예제 #1
0
def check_workload_update(core_api, apps_api, count):  # NOQA
    da_list = apps_api.list_namespaced_daemon_set(LONGHORN_NAMESPACE).items
    for da in da_list:
        if da.status.updated_number_scheduled != count:
            return False

    dp_list = apps_api.list_namespaced_deployment(LONGHORN_NAMESPACE).items
    for dp in dp_list:
        if dp.status.updated_replicas != dp.spec.replicas:
            return False

    im_pod_list = core_api.list_namespaced_pod(
        LONGHORN_NAMESPACE,
        label_selector="longhorn.io/component=instance-manager").items
    if len(im_pod_list) != 2 * count:
        return False

    for p in im_pod_list:
        if p.status.phase != "Running":
            return False

    client = get_longhorn_api_client()  # NOQA
    images = client.list_engine_image()
    assert len(images) == 1
    ei_state = get_engine_image_status_value(client, images[0].name)
    if images[0].state != ei_state:
        return False

    return True
예제 #2
0
def test_engine_image_incompatible(client, volume_name):  # NOQA
    images = client.list_engine_image()
    assert len(images) == 1
    assert images[0]["default"]
    assert images[0]["state"] == "ready"

    cli_v = images[0]["cliAPIVersion"]
    # cli_minv = images[0]["cliAPIMinVersion"]
    ctl_v = images[0]["controllerAPIVersion"]
    ctl_minv = images[0]["controllerAPIMinVersion"]
    data_v = images[0]["dataFormatVersion"]
    data_minv = images[0]["dataFormatMinVersion"]

    fail_cli_v_image = common.get_compatibility_test_image(
        cli_v - 1, cli_v - 1, ctl_v, ctl_minv, data_v, data_minv)
    img = client.create_engine_image(image=fail_cli_v_image)
    img_name = img["name"]
    img = wait_for_engine_image_state(client, img_name, "incompatible")
    assert img["state"] == "incompatible"
    assert img["cliAPIVersion"] == cli_v - 1
    assert img["cliAPIMinVersion"] == cli_v - 1
    client.delete(img)

    fail_cli_minv_image = common.get_compatibility_test_image(
        cli_v + 1, cli_v + 1, ctl_v, ctl_minv, data_v, data_minv)
    img = client.create_engine_image(image=fail_cli_minv_image)
    img_name = img["name"]
    img = wait_for_engine_image_state(client, img_name, "incompatible")
    assert img["state"] == "incompatible"
    assert img["cliAPIVersion"] == cli_v + 1
    assert img["cliAPIMinVersion"] == cli_v + 1
    client.delete(img)
예제 #3
0
def wait_for_toleration_update(core_api, apps_api, count,
                               set_tolerations):  # NOQA
    updated = False

    for i in range(RETRY_COUNTS):
        time.sleep(RETRY_INTERVAL_LONG)
        updated = True

        da_list = apps_api.list_namespaced_daemon_set(LONGHORN_NAMESPACE).items
        for da in da_list:
            if da.status.updated_number_scheduled != count:
                updated = False
                break
        if not updated:
            continue

        dp_list = apps_api.list_namespaced_deployment(LONGHORN_NAMESPACE).items
        for dp in dp_list:
            if dp.status.updated_replicas != dp.spec.replicas:
                updated = False
                break
        if not updated:
            continue

        im_pod_list = core_api.list_namespaced_pod(
            LONGHORN_NAMESPACE,
            label_selector="longhorn.io/component=instance-manager").items
        if len(im_pod_list) != 2 * count:
            updated = False
            continue

        for p in im_pod_list:
            if p.status.phase != "Running":
                updated = False
                break
        if not updated:
            continue

        pod_list = core_api.list_namespaced_pod(LONGHORN_NAMESPACE).items
        for p in pod_list:
            if p.status.phase != "Running" or \
                    not check_tolerations_set(p.spec.tolerations,
                                              set_tolerations):
                updated = False
                break
        if not updated:
            continue

        client = get_longhorn_api_client()  # NOQA
        images = client.list_engine_image()
        assert len(images) == 1
        if images[0].state != "ready":
            updated = False
            continue

        if updated:
            break

    assert updated
def test_engine_image(client, volume_name):  # NOQA
    # can be leftover
    default_img = common.get_default_engine_image(client)
    default_img_name = default_img["name"]
    default_img = wait_for_engine_image_ref_count(client, default_img_name, 0)

    images = client.list_engine_image()
    assert len(images) == 1
    assert images[0]["default"]
    assert images[0]["state"] == "ready"
    assert images[0]["refCount"] == 0
    assert images[0]["gitCommit"] != ""
    assert images[0]["buildDate"] != ""

    cli_v = default_img["cliAPIVersion"]
    cli_minv = default_img["cliAPIMinVersion"]
    ctl_v = default_img["controllerAPIVersion"]
    ctl_minv = default_img["controllerAPIMinVersion"]
    data_v = default_img["dataFormatVersion"]
    data_minv = default_img["dataFormatMinVersion"]

    assert cli_v != 0
    assert cli_minv != 0
    assert ctl_v != 0
    assert ctl_minv != 0
    assert data_v != 0
    assert data_minv != 0

    # delete default image is not allowed
    with pytest.raises(Exception) as e:
        client.delete(images[0])
    assert "the default engine image" in str(e.value)

    # duplicate images
    with pytest.raises(Exception) as e:
        client.create_engine_image(image=default_img["image"])

    engine_upgrade_image = common.get_upgrade_test_image(cli_v, cli_minv,
                                                         ctl_v, ctl_minv,
                                                         data_v, data_minv)

    new_img = client.create_engine_image(image=engine_upgrade_image)
    new_img_name = new_img["name"]
    new_img = wait_for_engine_image_state(client, new_img_name, "ready")
    assert not new_img["default"]
    assert new_img["state"] == "ready"
    assert new_img["refCount"] == 0
    assert new_img["cliAPIVersion"] != 0
    assert new_img["cliAPIMinVersion"] != 0
    assert new_img["controllerAPIVersion"] != 0
    assert new_img["controllerAPIMinVersion"] != 0
    assert new_img["dataFormatVersion"] != 0
    assert new_img["dataFormatMinVersion"] != 0
    assert new_img["gitCommit"] != ""
    assert new_img["buildDate"] != ""

    client.delete(new_img)
def test_engine_image_incompatible(client, core_api, volume_name):  # NOQA
    """
    Test incompatible engine images

    1. Deploy incompatible engine images
    2. Make sure their state are `incompatible` once deployed.
    """
    images = client.list_engine_image()
    assert len(images) == 1
    assert images[0].default
    assert images[0].state == "ready"

    cli_v = images[0].cliAPIVersion
    # cli_minv = images[0].cliAPIMinVersion
    ctl_v = images[0].controllerAPIVersion
    ctl_minv = images[0].controllerAPIMinVersion
    data_v = images[0].dataFormatVersion
    data_minv = images[0].dataFormatMinVersion

    fail_cli_v_image = common.get_compatibility_test_image(
        cli_v - 1, cli_v - 1, ctl_v, ctl_minv, data_v, data_minv)
    img = client.create_engine_image(image=fail_cli_v_image)
    img_name = img.name
    img = wait_for_engine_image_state(client, img_name, "incompatible")
    assert img.state == "incompatible"
    assert img.cliAPIVersion == cli_v - 1
    assert img.cliAPIMinVersion == cli_v - 1
    client.delete(img)
    wait_for_engine_image_deletion(client, core_api, img.name)

    fail_cli_minv_image = common.get_compatibility_test_image(
        cli_v + 1, cli_v + 1, ctl_v, ctl_minv, data_v, data_minv)
    img = client.create_engine_image(image=fail_cli_minv_image)
    img_name = img.name
    img = wait_for_engine_image_state(client, img_name, "incompatible")
    assert img.state == "incompatible"
    assert img.cliAPIVersion == cli_v + 1
    assert img.cliAPIMinVersion == cli_v + 1
    client.delete(img)
    wait_for_engine_image_deletion(client, core_api, img.name)
def test_upgrade(
        upgrade_longhorn_manager_repo_url,
        upgrade_longhorn_manager_repo_branch,
        upgrade_longhorn_manager_image,
        upgrade_longhorn_engine_image,
        upgrade_longhorn_instance_manager_image,
        upgrade_longhorn_share_manager_image,
        upgrade_longhorn_backing_image_manager_image,
        client,
        core_api,
        volume_name,
        csi_pv,  # NOQA
        pvc,
        pod_make,
        statefulset,
        storage_class):  # NOQA
    """
    Test Longhorn upgrade

    TODO
    The test will cover both volume has revision counter enabled and
    disabled cases.

    Prerequisite:
      - Disable Auto Salvage Setting

    1. Find the upgrade image tag
    2. Create a volume, generate and write data into the volume.
        1. Create a volume with revision counter enabled case.
        2. Create a volume with revision counter disabled case.
    3. Create a Pod using a volume, generate and write data
    4. Create a StatefulSet with 2 replicas,
       generate and write data to their volumes
    5. Keep all volumes attached
    6. Upgrade Longhorn system.
    7. Check Pod and StatefulSet didn't restart after upgrade
    8. Check All volumes data
    9. Write data to StatefulSet pods, and Attached volume
    10. Check data written to StatefulSet pods, and attached volume.
    11. Detach the volume, and Delete Pod, and
        StatefulSet to detach theirvolumes
    12. Upgrade all volumes engine images.
    13. Attach the volume, and recreate Pod, and StatefulSet
    14. Check All volumes data
    """
    longhorn_manager_repo = upgrade_longhorn_manager_repo_url
    longhorn_manager_branch = upgrade_longhorn_manager_repo_branch
    longhorn_manager_image = upgrade_longhorn_manager_image
    longhorn_engine_image = upgrade_longhorn_engine_image
    longhorn_instance_manager_image = upgrade_longhorn_instance_manager_image
    longhorn_share_manager_image = upgrade_longhorn_share_manager_image
    longhorn_backing_image_manager_image = \
        upgrade_longhorn_backing_image_manager_image

    host_id = get_self_host_id()
    pod_data_path = "/data/test"

    pod_volume_name = generate_volume_name()

    auto_salvage_setting = client.by_id_setting(SETTING_AUTO_SALVAGE)
    setting = client.update(auto_salvage_setting, value="false")

    assert setting.name == SETTING_AUTO_SALVAGE
    assert setting.value == "false"

    # Create Volume attached to a node.
    volume1 = create_and_check_volume(client, volume_name, size=SIZE)
    volume1.attach(hostId=host_id)
    volume1 = wait_for_volume_healthy(client, volume_name)
    volume1_data = write_volume_random_data(volume1)

    # Create Volume used by Pod
    pod_name, pv_name, pvc_name, pod_md5sum = \
        prepare_pod_with_data_in_mb(client, core_api, csi_pv, pvc,
                                    pod_make, pod_volume_name,
                                    data_path=pod_data_path,
                                    add_liveness_probe=False)

    # Create multiple volumes used by StatefulSet
    statefulset_name = 'statefulset-upgrade-test'
    update_statefulset_manifests(statefulset, storage_class, statefulset_name)
    create_storage_class(storage_class)
    create_and_wait_statefulset(statefulset)
    statefulset_pod_info = get_statefulset_pod_info(core_api, statefulset)

    for sspod_info in statefulset_pod_info:
        sspod_info['data'] = generate_random_data(VOLUME_RWTEST_SIZE)
        write_pod_volume_data(core_api, sspod_info['pod_name'],
                              sspod_info['data'])

    # upgrade Longhorn
    assert longhorn_upgrade(longhorn_manager_repo, longhorn_manager_branch,
                            longhorn_manager_image, longhorn_engine_image,
                            longhorn_instance_manager_image,
                            longhorn_share_manager_image,
                            longhorn_backing_image_manager_image)

    client = get_longhorn_api_client()

    # wait for 1 minute before checking pod restarts
    time.sleep(60)

    pod = core_api.read_namespaced_pod(name=pod_name, namespace='default')
    assert pod.status.container_statuses[0].restart_count == 0

    for sspod_info in statefulset_pod_info:
        sspod = core_api.read_namespaced_pod(name=sspod_info['pod_name'],
                                             namespace='default')
        assert \
            sspod.status.container_statuses[0].restart_count == 0

    for sspod_info in statefulset_pod_info:
        resp = read_volume_data(core_api, sspod_info['pod_name'])
        assert resp == sspod_info['data']

    res_pod_md5sum = get_pod_data_md5sum(core_api, pod_name, pod_data_path)
    assert res_pod_md5sum == pod_md5sum

    check_volume_data(volume1, volume1_data)

    for sspod_info in statefulset_pod_info:
        sspod_info['data'] = generate_random_data(VOLUME_RWTEST_SIZE)
        write_pod_volume_data(core_api, sspod_info['pod_name'],
                              sspod_info['data'])

    for sspod_info in statefulset_pod_info:
        resp = read_volume_data(core_api, sspod_info['pod_name'])
        assert resp == sspod_info['data']

    volume1 = client.by_id_volume(volume_name)
    volume1_data = write_volume_random_data(volume1)
    check_volume_data(volume1, volume1_data)

    statefulset['spec']['replicas'] = replicas = 0
    apps_api = get_apps_api_client()

    apps_api.patch_namespaced_stateful_set(
        name=statefulset_name,
        namespace='default',
        body={'spec': {
            'replicas': replicas
        }})

    delete_and_wait_pod(core_api, pod_name)

    volume = client.by_id_volume(volume_name)
    volume.detach(hostId="")

    volumes = client.list_volume()
    for v in volumes:
        wait_for_volume_detached(client, v.name)

    engineimages = client.list_engine_image()
    for ei in engineimages:
        if ei.image == longhorn_engine_image:
            new_ei = ei

    volumes = client.list_volume()
    for v in volumes:
        volume = client.by_id_volume(v.name)
        volume.engineUpgrade(image=new_ei.image)

    statefulset['spec']['replicas'] = replicas = 2
    apps_api = get_apps_api_client()

    apps_api.patch_namespaced_stateful_set(
        name=statefulset_name,
        namespace='default',
        body={'spec': {
            'replicas': replicas
        }})

    wait_statefulset(statefulset)

    pod = pod_make(name=pod_name)
    pod['spec']['volumes'] = [create_pvc_spec(pvc_name)]
    create_and_wait_pod(core_api, pod)

    volume1 = client.by_id_volume(volume_name)
    volume1.attach(hostId=host_id)
    volume1 = wait_for_volume_healthy(client, volume_name)

    for sspod_info in statefulset_pod_info:
        resp = read_volume_data(core_api, sspod_info['pod_name'])
        assert resp == sspod_info['data']

    res_pod_md5sum = get_pod_data_md5sum(core_api, pod_name, pod_data_path)
    assert res_pod_md5sum == pod_md5sum

    check_volume_data(volume1, volume1_data)
예제 #7
0
def test_engine_image(client, core_api, volume_name):  # NOQA
    """
    Test Engine Image deployment

    1. List Engine Images and validate basic properities.
    2. Try deleting default engine image and it should fail.
    3. Try creating a duplicate engine image as default and it should fail
    4. Get upgrade test image for the same versions
    5. Test if the upgrade test image can be deployed and deleted correctly
    """
    # can be leftover
    default_img = common.get_default_engine_image(client)
    default_img_name = default_img.name
    default_img = wait_for_engine_image_ref_count(client, default_img_name, 0)
    ei_state = get_engine_image_status_value(client, default_img_name)

    images = client.list_engine_image()
    assert len(images) == 1
    assert images[0].default
    assert images[0].state == ei_state
    assert images[0].refCount == 0
    assert images[0].gitCommit != ""
    assert images[0].buildDate != ""

    cli_v = default_img.cliAPIVersion
    cli_minv = default_img.cliAPIMinVersion
    ctl_v = default_img.controllerAPIVersion
    ctl_minv = default_img.controllerAPIMinVersion
    data_v = default_img.dataFormatVersion
    data_minv = default_img.dataFormatMinVersion

    assert cli_v != 0
    assert cli_minv != 0
    assert ctl_v != 0
    assert ctl_minv != 0
    assert data_v != 0
    assert data_minv != 0

    # delete default image is not allowed
    with pytest.raises(Exception) as e:
        client.delete(images[0])
    assert "the default engine image" in str(e.value)

    # duplicate images
    with pytest.raises(Exception) as e:
        client.create_engine_image(image=default_img.image)

    engine_upgrade_image = common.get_upgrade_test_image(
        cli_v, cli_minv, ctl_v, ctl_minv, data_v, data_minv)

    # test if engine image can be created and cleaned up successfully
    for _ in range(ENGINE_IMAGE_TEST_REPEAT_COUNT):
        new_img = client.create_engine_image(image=engine_upgrade_image)
        new_img_name = new_img.name
        new_img = wait_for_engine_image_state(client, new_img_name, ei_state)
        assert not new_img.default
        assert new_img.state == ei_state
        assert new_img.refCount == 0
        assert new_img.cliAPIVersion != 0
        assert new_img.cliAPIMinVersion != 0
        assert new_img.controllerAPIVersion != 0
        assert new_img.controllerAPIMinVersion != 0
        assert new_img.dataFormatVersion != 0
        assert new_img.dataFormatMinVersion != 0
        assert new_img.gitCommit != ""
        assert new_img.buildDate != ""

        client.delete(new_img)
        wait_for_engine_image_deletion(client, core_api, new_img.name)