diff --git a/tests/storage/conftest.py b/tests/storage/conftest.py index 02df9b8126..5279c49796 100644 --- a/tests/storage/conftest.py +++ b/tests/storage/conftest.py @@ -355,11 +355,6 @@ def hpp_daemonset_scope_module(hco_namespace, hpp_cr_suffix_scope_module): yield get_hpp_daemonset(hco_namespace=hco_namespace, hpp_cr_suffix=hpp_cr_suffix_scope_module) -@pytest.fixture() -def cirros_vm_name(request): - return request.param["vm_name"] - - @pytest.fixture() def rhel_vm_name(request): return request.param["vm_name"] diff --git a/tests/storage/golden_image/test_cached_snapshots.py b/tests/storage/golden_image/test_cached_snapshots.py index 5a569a44d9..c5de9ca93a 100644 --- a/tests/storage/golden_image/test_cached_snapshots.py +++ b/tests/storage/golden_image/test_cached_snapshots.py @@ -20,7 +20,7 @@ ) from utilities.ssp import wait_for_deleted_data_import_crons from utilities.storage import ( - data_volume_dict_modify_to_source_ref, + data_volume_template_with_source_ref_dict, verify_dv_and_pvc_does_not_exist, wait_for_succeeded_dv, wait_for_volume_snapshot_ready_to_use, @@ -201,20 +201,13 @@ def rhel9_golden_image_vm( unprivileged_client, namespace, ): - dv = DataVolume( - name=f"{RHEL9_STR}-test-vm", - namespace=namespace.name, - size=rhel9_cached_snapshot.instance.status.get("restoreSize"), - storage_class=snapshot_storage_class_name_scope_module, - api_name="storage", - ) with vm_instance_from_template( request=request, unprivileged_client=unprivileged_client, namespace=namespace, - data_volume_template=data_volume_dict_modify_to_source_ref( - dv=dv, + data_volume_template=data_volume_template_with_source_ref_dict( data_source=rhel9_data_source_scope_module, + storage_class=snapshot_storage_class_name_scope_module, ), ) as vm: yield vm diff --git a/tests/storage/online_resize/__init__.py b/tests/storage/online_resize/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/storage/online_resize/conftest.py b/tests/storage/online_resize/conftest.py new file mode 100644 index 0000000000..ea214cf254 --- /dev/null +++ b/tests/storage/online_resize/conftest.py @@ -0,0 +1,96 @@ +# -*- coding: utf-8 -*- + +""" +Fixtures for online resize tests +""" + +import pytest + +from tests.storage.online_resize.utils import ( + SMALLEST_POSSIBLE_EXPAND, + STORED_FILENAME, + cksum_file, + create_rhel_dv_from_data_source, + expand_pvc, + wait_for_resize, +) +from utilities.constants import OS_FLAVOR_RHEL, Images +from utilities.storage import create_dv, is_snapshot_supported_by_sc +from utilities.virt import VirtualMachineForTests, running_vm + + +@pytest.fixture(scope="module") +def xfail_if_storage_for_online_resize_does_not_support_snapshots( + admin_client, storage_class_matrix_online_resize_matrix__module__ +): + sc_name = [*storage_class_matrix_online_resize_matrix__module__][0] + if not is_snapshot_supported_by_sc( + sc_name=sc_name, + client=admin_client, + ): + pytest.xfail(f"Storage class for online resize '{sc_name}' doesn't support snapshots") + + +@pytest.fixture() +def orig_cksum(rhel_vm_for_online_resize, running_rhel_vm): + return cksum_file(vm=rhel_vm_for_online_resize, filename=STORED_FILENAME, create=True) + + +@pytest.fixture() +def rhel_dv_for_online_resize( + request, + namespace, + unprivileged_client, + storage_class_matrix_online_resize_matrix__module__, + rhel10_data_source_scope_module, +): + with create_rhel_dv_from_data_source( + unprivileged_client=unprivileged_client, + namespace=namespace.name, + name=request.param["dv_name"], + storage_class=[*storage_class_matrix_online_resize_matrix__module__][0], + rhel_data_source=rhel10_data_source_scope_module, + ) as dv: + yield dv + + +@pytest.fixture() +def second_rhel_dv_for_online_resize(rhel_dv_for_online_resize, unprivileged_client): + with create_dv( + source="pvc", + dv_name=f"{rhel_dv_for_online_resize.name}-target", + namespace=rhel_dv_for_online_resize.namespace, + client=unprivileged_client, + size=rhel_dv_for_online_resize.size, + storage_class=rhel_dv_for_online_resize.storage_class, + source_pvc=rhel_dv_for_online_resize.name, + ) as rhel_dv: + yield rhel_dv + + +@pytest.fixture() +def rhel_vm_for_online_resize( + request, unprivileged_client, namespace, rhel_dv_for_online_resize, modern_cpu_for_migration +): + with VirtualMachineForTests( + client=unprivileged_client, + name=request.param["vm_name"], + namespace=namespace.name, + data_volume=rhel_dv_for_online_resize, + memory_guest=Images.Rhel.DEFAULT_MEMORY_SIZE, + os_flavor=OS_FLAVOR_RHEL, + cpu_model=modern_cpu_for_migration, + ) as vm: + yield vm + + +@pytest.fixture() +def rhel_vm_after_expand(rhel_dv_for_online_resize, rhel_vm_for_online_resize, running_rhel_vm): + with wait_for_resize(vm=rhel_vm_for_online_resize): + expand_pvc(dv=rhel_dv_for_online_resize, size_change=SMALLEST_POSSIBLE_EXPAND) + return rhel_vm_for_online_resize + + +@pytest.fixture() +def running_rhel_vm(rhel_vm_for_online_resize): + return running_vm(vm=rhel_vm_for_online_resize) diff --git a/tests/storage/online_resize/test_online_resize.py b/tests/storage/online_resize/test_online_resize.py new file mode 100644 index 0000000000..2f34d21258 --- /dev/null +++ b/tests/storage/online_resize/test_online_resize.py @@ -0,0 +1,194 @@ +# -*- coding: utf-8 -*- + +""" +Online resize (PVC expanded while VM running) +""" + +import logging + +import pytest +from ocp_resources.datavolume import DataVolume +from timeout_sampler import TimeoutSampler + +from tests.storage.online_resize.utils import ( + RHEL_DV_SIZE, + SMALLEST_POSSIBLE_EXPAND, + check_file_unchanged, + expand_pvc, + vm_restore, + wait_for_resize, +) +from utilities.constants import TIMEOUT_1MIN, TIMEOUT_4MIN, TIMEOUT_5SEC +from utilities.storage import add_dv_to_vm, create_dv, vm_snapshot +from utilities.virt import migrate_vm_and_verify, running_vm + +LOGGER = logging.getLogger(__name__) + + +@pytest.mark.gating +@pytest.mark.polarion("CNV-6793") +@pytest.mark.parametrize( + "rhel_dv_for_online_resize, rhel_vm_for_online_resize", + [ + pytest.param( + {"dv_name": "sequential-expand-dv"}, + {"vm_name": "sequential-expand-vm"}, + ), + ], + indirect=True, +) +def test_sequential_disk_expand( + rhel_dv_for_online_resize, + rhel_vm_for_online_resize, + running_rhel_vm, +): + # Expand PVC and wait for resize 6 times + for _ in range(6): + with wait_for_resize(vm=rhel_vm_for_online_resize): + expand_pvc(dv=rhel_dv_for_online_resize, size_change=SMALLEST_POSSIBLE_EXPAND) + + +@pytest.mark.polarion("CNV-6794") +@pytest.mark.parametrize( + "rhel_dv_for_online_resize, rhel_vm_for_online_resize", + [ + pytest.param( + {"dv_name": "simultaneous-expand-dv"}, + {"vm_name": "simultaneous-expand-vm"}, + ), + ], + indirect=True, +) +def test_simultaneous_disk_expand( + rhel_dv_for_online_resize, + second_rhel_dv_for_online_resize, + rhel_vm_for_online_resize, +): + add_dv_to_vm(vm=rhel_vm_for_online_resize, dv_name=second_rhel_dv_for_online_resize.name) + running_vm(vm=rhel_vm_for_online_resize) + with wait_for_resize(vm=rhel_vm_for_online_resize, count=2): + expand_pvc(dv=rhel_dv_for_online_resize, size_change=SMALLEST_POSSIBLE_EXPAND) + expand_pvc(dv=second_rhel_dv_for_online_resize, size_change=SMALLEST_POSSIBLE_EXPAND) + + +@pytest.mark.polarion("CNV-8257") +@pytest.mark.parametrize( + "rhel_dv_for_online_resize, rhel_vm_for_online_resize", + [ + pytest.param( + {"dv_name": "expand-clone-fail-dv"}, + {"vm_name": "expand-clone-fail-vm"}, + ), + ], + indirect=True, +) +def test_disk_expand_then_clone_fail( + unprivileged_client, + rhel_dv_for_online_resize, + rhel_vm_after_expand, +): + LOGGER.info("Trying to clone DV with original size - should fail at webhook") + with create_dv( + source="pvc", + dv_name=f"{rhel_dv_for_online_resize.name}-target", + namespace=rhel_dv_for_online_resize.namespace, + client=unprivileged_client, + size=RHEL_DV_SIZE, + storage_class=rhel_dv_for_online_resize.storage_class, + source_pvc=rhel_dv_for_online_resize.name, + ) as dv: + for sample in TimeoutSampler( + wait_timeout=TIMEOUT_1MIN, + sleep=TIMEOUT_5SEC, + func=lambda: dv.instance.status.conditions, + ): + if any( + "The clone doesn't meet the validation requirements:" + " target resources requests storage size is smaller than the source" in condition["message"] + for condition in sample + ): + return + + +@pytest.mark.gating +@pytest.mark.polarion("CNV-6578") +@pytest.mark.parametrize( + "rhel_dv_for_online_resize, rhel_vm_for_online_resize", + [ + pytest.param( + {"dv_name": "expand-clone-success-dv"}, + {"vm_name": "expand-clone-success-vm"}, + ), + ], + indirect=True, +) +def test_disk_expand_then_clone_success( + unprivileged_client, + rhel_dv_for_online_resize, + rhel_vm_after_expand, +): + # Can't clone a running VM + rhel_vm_after_expand.stop() + + LOGGER.info("Trying to clone DV with new size - should succeed") + with create_dv( + source="pvc", + dv_name=f"{rhel_dv_for_online_resize.name}-target", + namespace=rhel_dv_for_online_resize.namespace, + client=unprivileged_client, + size=rhel_dv_for_online_resize.pvc.instance.spec.resources.requests.storage, + storage_class=rhel_dv_for_online_resize.storage_class, + source_pvc=rhel_dv_for_online_resize.name, + ) as cdv: + cdv.wait_for_condition( + condition=DataVolume.Condition.Type.READY, + status=DataVolume.Condition.Status.TRUE, + timeout=TIMEOUT_4MIN, + ) + + +@pytest.mark.polarion("CNV-6580") +@pytest.mark.parametrize( + "rhel_dv_for_online_resize, rhel_vm_for_online_resize", + [ + pytest.param( + {"dv_name": "expand-migrate-dv"}, + {"vm_name": "expand-migrate-vm"}, + ), + ], + indirect=True, +) +def test_disk_expand_then_migrate(rhel_vm_after_expand, orig_cksum): + migrate_vm_and_verify( + vm=rhel_vm_after_expand, + check_ssh_connectivity=True, + ) + check_file_unchanged(orig_cksum=orig_cksum, vm=rhel_vm_after_expand) + + +@pytest.mark.polarion("CNV-6797") +@pytest.mark.parametrize( + "rhel_dv_for_online_resize, rhel_vm_for_online_resize", + [ + pytest.param( + {"dv_name": "expand-snapshot-dv"}, + {"vm_name": "expand-snapshot-vm"}, + ), + ], + indirect=True, +) +def test_disk_expand_with_snapshots( + xfail_if_storage_for_online_resize_does_not_support_snapshots, + rhel_dv_for_online_resize, + rhel_vm_for_online_resize, + orig_cksum, +): + with vm_snapshot(vm=rhel_vm_for_online_resize, name="snapshot-before") as vm_snapshot_before: + with wait_for_resize(vm=rhel_vm_for_online_resize): + expand_pvc(dv=rhel_dv_for_online_resize, size_change=SMALLEST_POSSIBLE_EXPAND) + check_file_unchanged(orig_cksum=orig_cksum, vm=rhel_vm_for_online_resize) + with vm_snapshot(vm=rhel_vm_for_online_resize, name="snapshot-after") as vm_snapshot_after: + with vm_restore(vm=rhel_vm_for_online_resize, name=vm_snapshot_before.name) as vm_restored_before: + check_file_unchanged(orig_cksum=orig_cksum, vm=vm_restored_before) + with vm_restore(vm=rhel_vm_for_online_resize, name=vm_snapshot_after.name) as vm_restored_after: + check_file_unchanged(orig_cksum=orig_cksum, vm=vm_restored_after) diff --git a/tests/storage/online_resize/utils.py b/tests/storage/online_resize/utils.py new file mode 100644 index 0000000000..4eea7893c7 --- /dev/null +++ b/tests/storage/online_resize/utils.py @@ -0,0 +1,172 @@ +# -*- coding: utf-8 -*- + +""" +Utility functions and context managers for online resize tests +""" + +import logging +import shlex +from contextlib import contextmanager + +import bitmath +from ocp_resources.virtual_machine_restore import VirtualMachineRestore +from pyhelper_utils.shell import run_ssh_commands +from timeout_sampler import TimeoutExpiredError, TimeoutSampler + +from utilities.constants import TIMEOUT_2MIN, TIMEOUT_4MIN, TIMEOUT_5SEC +from utilities.storage import create_dv +from utilities.virt import running_vm + +LOGGER = logging.getLogger(__name__) +SMALLEST_POSSIBLE_EXPAND = "1Gi" +STORED_FILENAME = "random_data_file" + +# Increase DV size to 40Gi because source storage size should be larger than the target storage size +RHEL_DV_SIZE = "40Gi" + + +@contextmanager +def create_rhel_dv_from_data_source(unprivileged_client, namespace, name, storage_class, rhel_data_source): + with create_dv( + dv_name=f"dv-{name}", + namespace=namespace, + client=unprivileged_client, + size=RHEL_DV_SIZE, + storage_class=storage_class, + source_ref={ + "kind": rhel_data_source.kind, + "name": rhel_data_source.name, + "namespace": rhel_data_source.namespace, + }, + ) as dv: + dv.wait_for_dv_success() + yield dv + + +def cksum_file(vm, filename, create=False): + """ + Return the checksum of a previously generated file. + If requested, create the file using random data. + + Args: + vm (VirtualMachine): vm to run commands on + filename (str): The filename which we checksum + create (bool): Whether to create the file first + + Returns: + str: the SHA256 checksum of the file + """ + if create: + LOGGER.info("Creating file with random data") + run_ssh_commands( + host=vm.ssh_exec, + commands=shlex.split(f"dd if=/dev/urandom of={filename} count=100 && sync"), + wait_timeout=TIMEOUT_2MIN, + sleep=TIMEOUT_5SEC, + ) + + out = run_ssh_commands( + host=vm.ssh_exec, + commands=shlex.split(f"sha256sum {filename}"), + wait_timeout=TIMEOUT_2MIN, + sleep=TIMEOUT_5SEC, + )[0] + sha256sum = out.split()[0] + LOGGER.info(f"File sha256sum is {sha256sum}") + return sha256sum + + +def kubsize_add(a_size, b_size): + """ + + Sum two kubernetes size strings. + Output sum is provided in a format that is accepted by kubernetes + as a storage size. + + Args: + a_size (str): size string to be summed + b_size (str): second size string + + Returns: + str: a sum of the inputs tolerated by kubernetes + + """ + bm_a = bitmath.parse_string_unsafe(s=a_size) + bm_b = bitmath.parse_string_unsafe(s=b_size) + + bm_sum = bm_a + bm_b + return f"{bm_sum.bytes:0.0f}" + + +def expand_pvc(dv, size_change): + pvc = dv.pvc + new_size = kubsize_add(a_size=pvc.instance.spec.resources.requests.storage, b_size=size_change) + pvc.update({ + "metadata": {"name": dv.name}, + "spec": { + "resources": {"requests": {"storage": new_size}}, + }, + }) + + +def get_resize_count(vm): + commands = shlex.split("sudo dmesg | grep -c 'new size' || true") + return int( + run_ssh_commands( + host=vm.ssh_exec, + commands=commands, + wait_timeout=TIMEOUT_2MIN, + sleep=TIMEOUT_5SEC, + )[0] + ) + + +def check_file_unchanged(orig_cksum, vm): + new_cksum = cksum_file(vm=vm, filename=STORED_FILENAME) + assert orig_cksum == new_cksum, ( + f"File checksum changed, original checksum={orig_cksum}, current checksum={new_cksum}" + ) + + +@contextmanager +def wait_for_resize(vm, count=1): + starting_count = get_resize_count(vm=vm) + desired_count = starting_count + count + yield + samples = TimeoutSampler( + wait_timeout=TIMEOUT_4MIN, + sleep=5, + func=get_resize_count, + vm=vm, + ) + try: + for sample in samples: + current_resize_count = sample + LOGGER.info( + f"Current resize count is {current_resize_count}. Waiting until resize count is {desired_count}" + ) + if current_resize_count in (desired_count, desired_count + 1): + break + except TimeoutExpiredError: + dmesg = run_ssh_commands( + host=vm.ssh_exec, + commands=shlex.split("sudo dmesg"), + wait_timeout=TIMEOUT_2MIN, + sleep=TIMEOUT_5SEC, + )[0] + LOGGER.error(f"Failed to reach resize count {desired_count}.\ndmesg:\n{dmesg}") + raise + + +@contextmanager +def vm_restore(vm, name): + vm.stop(wait=True) + with VirtualMachineRestore( + name=f"restore-{name}", + namespace=vm.namespace, + vm_name=vm.name, + snapshot_name=name, + ) as restore: + restore.wait_restore_done() + running_vm(vm=vm) + yield vm diff --git a/tests/storage/test_online_resize.py b/tests/storage/test_online_resize.py deleted file mode 100644 index e835829615..0000000000 --- a/tests/storage/test_online_resize.py +++ /dev/null @@ -1,398 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -Online resize (PVC expanded while VM running) -""" - -import logging -import shlex -from contextlib import contextmanager - -import bitmath -import pytest -from ocp_resources.datavolume import DataVolume -from ocp_resources.virtual_machine_restore import VirtualMachineRestore -from pyhelper_utils.shell import run_ssh_commands -from timeout_sampler import TimeoutExpiredError, TimeoutSampler - -from tests.storage.utils import create_cirros_dv -from utilities.constants import OS_FLAVOR_CIRROS, TIMEOUT_1MIN, TIMEOUT_2MIN, TIMEOUT_4MIN, TIMEOUT_5SEC, Images -from utilities.storage import ( - add_dv_to_vm, - create_dv, - is_snapshot_supported_by_sc, - vm_snapshot, -) -from utilities.virt import VirtualMachineForTests, migrate_vm_and_verify, running_vm - -LOGGER = logging.getLogger(__name__) -SMALLEST_POSSIBLE_EXPAND = "1Gi" -STORED_FILENAME = "random_data_file" - - -@contextmanager -def clone_dv(dv, size): - with create_dv( - source="pvc", - dv_name=f"{dv.name}-target", - namespace=dv.namespace, - size=size, - storage_class=dv.storage_class, - volume_mode=dv.volume_mode, - source_pvc=dv.name, - ) as dv: - yield dv - - -def cksum_file(vm, filename, create=False): - """ - - Return the checksum of a previously generated file. - If requested, create the file using random data. - - Args: - vm (VirtualMachine): vm to run commands on - filename (str): The filename which we checksum - create (bool): Whether to create the file first - - Returns: - str: the SHA256 checksum of the file - - """ - if create: - LOGGER.info("Creating file with random data") - run_ssh_commands( - host=vm.ssh_exec, - commands=shlex.split(f"dd if=/dev/urandom of={filename} count=100 && sync"), - wait_timeout=TIMEOUT_2MIN, - sleep=TIMEOUT_5SEC, - ) - - out = run_ssh_commands( - host=vm.ssh_exec, - commands=shlex.split(f"sha256sum {filename}"), - wait_timeout=TIMEOUT_2MIN, - sleep=TIMEOUT_5SEC, - )[0] - sha256sum = out.split()[0] - LOGGER.info(f"File sha256sum is {sha256sum}") - return sha256sum - - -def kubsize_add(a_size, b_size): - """ - - Sum two kubernetes size strings. - Output sum is provided in a format that is accepted by kubernetes - as a storage size. - - Args: - a_size (str): size string to be summed - b_size (str): second size string - - Returns: - str: a sum of the inputs tolerated by kubernetes - - """ - bm_a = bitmath.parse_string_unsafe(s=a_size) - bm_b = bitmath.parse_string_unsafe(s=b_size) - - bm_sum = bm_a + bm_b - return f"{bm_sum.bytes:0.0f}" - - -def expand_pvc(dv, size_change): - pvc = dv.pvc - new_size = kubsize_add(a_size=pvc.instance.spec.resources.requests.storage, b_size=size_change) - pvc.update({ - "metadata": {"name": dv.name}, - "spec": { - "resources": {"requests": {"storage": new_size}}, - }, - }) - - -def get_resize_count(vm): - commands = shlex.split("dmesg | grep -c 'new size' || true") - return int( - run_ssh_commands( - host=vm.ssh_exec, - commands=commands, - wait_timeout=TIMEOUT_2MIN, - sleep=TIMEOUT_5SEC, - )[0] - ) - - -def check_file_unchanged(orig_cksum, vm): - new_cksum = cksum_file(vm=vm, filename=STORED_FILENAME) - assert orig_cksum == new_cksum, ( - f"File checksum changed, original checksum={orig_cksum}, current checksum={new_cksum}" - ) - - -@contextmanager -def wait_for_resize(vm, count=1): - starting_count = get_resize_count(vm=vm) - desired_count = starting_count + count - yield - samples = TimeoutSampler( - wait_timeout=TIMEOUT_4MIN, - sleep=5, - func=get_resize_count, - vm=vm, - ) - try: - for sample in samples: - current_resize_count = sample - LOGGER.info( - f"Current resize count is {current_resize_count}. Waiting until resize count is {desired_count}" - ) - if current_resize_count == desired_count: - break - except TimeoutExpiredError: - dmesg = run_ssh_commands( - host=vm.ssh_exec, - commands=shlex.split("dmesg"), - wait_timeout=TIMEOUT_2MIN, - sleep=TIMEOUT_5SEC, - )[0] - LOGGER.error(f"Failed to reach resize count {desired_count}.\ndmesg:\n{dmesg}") - raise - - -@contextmanager -def vm_restore(vm, name): - vm.stop(wait=True) - with VirtualMachineRestore( - name=f"restore-{name}", - namespace=vm.namespace, - vm_name=vm.name, - snapshot_name=name, - ) as restore: - restore.wait_restore_done() - running_vm(vm=vm, wait_for_interfaces=False) - yield vm - - -@pytest.fixture() -def cirros_dv_for_online_resize( - namespace, - cirros_vm_name, - storage_class_matrix_online_resize_matrix__module__, -): - yield from create_cirros_dv( - namespace=namespace.name, - name=cirros_vm_name, - storage_class=[*storage_class_matrix_online_resize_matrix__module__][0], - ) - - -@pytest.fixture() -def second_cirros_dv_for_online_resize(cirros_dv_for_online_resize): - with clone_dv( - dv=cirros_dv_for_online_resize, - size=cirros_dv_for_online_resize.size, - ) as second_dv: - yield second_dv - - -@pytest.fixture() -def cirros_vm_for_online_resize( - admin_client, - cirros_dv_for_online_resize, - namespace, - cirros_vm_name, -): - """ - Create a VM with a DV from the cirros_dv_for_online_resize fixture - """ - with VirtualMachineForTests( - name=cirros_vm_name, - namespace=namespace.name, - data_volume=cirros_dv_for_online_resize, - memory_guest=Images.Cirros.DEFAULT_MEMORY_SIZE, - os_flavor=OS_FLAVOR_CIRROS, - ) as vm: - yield vm - - -@pytest.fixture() -def cirros_vm_after_expand(cirros_dv_for_online_resize, cirros_vm_for_online_resize, running_cirros_vm): - with wait_for_resize(vm=cirros_vm_for_online_resize): - expand_pvc(dv=cirros_dv_for_online_resize, size_change=SMALLEST_POSSIBLE_EXPAND) - return cirros_vm_for_online_resize - - -@pytest.fixture() -def running_cirros_vm(cirros_vm_for_online_resize): - running_vm(vm=cirros_vm_for_online_resize, wait_for_interfaces=False) - - -@pytest.fixture() -def orig_cksum(cirros_vm_for_online_resize, running_cirros_vm): - return cksum_file(vm=cirros_vm_for_online_resize, filename=STORED_FILENAME, create=True) - - -@pytest.fixture(scope="module") -def skip_if_storage_for_online_resize_does_not_support_snapshots( - storage_class_matrix_online_resize_matrix__module__, admin_client -): - sc_name = [*storage_class_matrix_online_resize_matrix__module__][0] - if not is_snapshot_supported_by_sc( - sc_name=sc_name, - client=admin_client, - ): - pytest.skip(f"Storage class for online resize '{sc_name}' doesn't support snapshots") - - -@pytest.mark.gating -@pytest.mark.polarion("CNV-6793") -@pytest.mark.parametrize( - "cirros_vm_name", - [ - pytest.param( - {"vm_name": "cnv-6793"}, - ), - ], - indirect=True, -) -def test_sequential_disk_expand( - cirros_dv_for_online_resize, - cirros_vm_for_online_resize, - running_cirros_vm, -): - # Expand PVC and wait for resize 6 times - for _ in range(6): - with wait_for_resize(vm=cirros_vm_for_online_resize): - expand_pvc(dv=cirros_dv_for_online_resize, size_change=SMALLEST_POSSIBLE_EXPAND) - - -@pytest.mark.polarion("CNV-6794") -@pytest.mark.parametrize( - "cirros_vm_name", - [ - pytest.param( - {"vm_name": "cnv-6794"}, - ), - ], - indirect=True, -) -def test_simultaneous_disk_expand( - cirros_dv_for_online_resize, - second_cirros_dv_for_online_resize, - cirros_vm_for_online_resize, -): - add_dv_to_vm(vm=cirros_vm_for_online_resize, dv_name=second_cirros_dv_for_online_resize.name) - running_vm(vm=cirros_vm_for_online_resize, wait_for_interfaces=False) - with wait_for_resize(vm=cirros_vm_for_online_resize, count=2): - expand_pvc(dv=cirros_dv_for_online_resize, size_change=SMALLEST_POSSIBLE_EXPAND) - expand_pvc(dv=second_cirros_dv_for_online_resize, size_change=SMALLEST_POSSIBLE_EXPAND) - - -@pytest.mark.polarion("CNV-8257") -@pytest.mark.parametrize( - "cirros_vm_name", - [ - pytest.param( - {"vm_name": "cnv-8257"}, - ), - ], - indirect=True, -) -def test_disk_expand_then_clone_fail( - cirros_dv_for_online_resize, - cirros_vm_after_expand, -): - LOGGER.info("Trying to clone DV with original size - should fail at webhook") - with clone_dv( - dv=cirros_dv_for_online_resize, - size=Images.Cirros.DEFAULT_DV_SIZE, - ) as dv: - for sample in TimeoutSampler( - wait_timeout=TIMEOUT_1MIN, - sleep=TIMEOUT_5SEC, - func=lambda: dv.instance.status.conditions, - ): - if any( - "The clone doesn't meet the validation requirements:" - " target resources requests storage size is smaller than the source" in condition["message"] - for condition in sample - ): - return - - -@pytest.mark.gating -@pytest.mark.polarion("CNV-6578") -@pytest.mark.parametrize( - "cirros_vm_name", - [ - pytest.param( - {"vm_name": "cnv-6578"}, - ), - ], - indirect=True, -) -def test_disk_expand_then_clone_success( - cirros_dv_for_online_resize, - cirros_vm_after_expand, -): - # Can't clone a running VM - cirros_vm_after_expand.stop() - - LOGGER.info("Trying to clone DV with new size - should succeed") - with clone_dv( - dv=cirros_dv_for_online_resize, - size=cirros_dv_for_online_resize.pvc.instance.spec.resources.requests.storage, - ) as cdv: - cdv.wait_for_condition( - condition=DataVolume.Condition.Type.READY, - status=DataVolume.Condition.Status.TRUE, - timeout=TIMEOUT_4MIN, - ) - - -@pytest.mark.polarion("CNV-6580") -@pytest.mark.parametrize( - "cirros_vm_name", - [ - pytest.param( - {"vm_name": "cnv-6580"}, - ), - ], - indirect=True, -) -def test_disk_expand_then_migrate(cpu_for_migration, cirros_vm_after_expand, orig_cksum): - migrate_vm_and_verify( - vm=cirros_vm_after_expand, - wait_for_interfaces=False, - check_ssh_connectivity=True, - ) - check_file_unchanged(orig_cksum=orig_cksum, vm=cirros_vm_after_expand) - - -@pytest.mark.polarion("CNV-6797") -@pytest.mark.parametrize( - "cirros_vm_name", - [ - pytest.param( - {"vm_name": "cnv-6797"}, - ), - ], - indirect=True, -) -def test_disk_expand_with_snapshots( - skip_if_storage_for_online_resize_does_not_support_snapshots, - cirros_dv_for_online_resize, - cirros_vm_for_online_resize, - orig_cksum, -): - with vm_snapshot(vm=cirros_vm_for_online_resize, name="snapshot-before") as vm_snapshot_before: - with wait_for_resize(vm=cirros_vm_for_online_resize): - expand_pvc(dv=cirros_dv_for_online_resize, size_change=SMALLEST_POSSIBLE_EXPAND) - check_file_unchanged(orig_cksum=orig_cksum, vm=cirros_vm_for_online_resize) - with vm_snapshot(vm=cirros_vm_for_online_resize, name="snapshot-after") as vm_snapshot_after: - with vm_restore(vm=cirros_vm_for_online_resize, name=vm_snapshot_before.name) as vm_restored_before: - check_file_unchanged(orig_cksum=orig_cksum, vm=vm_restored_before) - with vm_restore(vm=cirros_vm_for_online_resize, name=vm_snapshot_after.name) as vm_restored_after: - check_file_unchanged(orig_cksum=orig_cksum, vm=vm_restored_after) diff --git a/utilities/storage.py b/utilities/storage.py index eda005f409..3bbeee0548 100644 --- a/utilities/storage.py +++ b/utilities/storage.py @@ -126,9 +126,13 @@ def create_dv( bind_immediate=None, preallocation=None, api_name="storage", + source_ref=None, ): artifactory_secret = None cert_created = None + + if source_ref: + source = None if source in ("http", "https"): if not utilities.infra.url_excluded_from_validation(url): # Make sure URL exists @@ -161,6 +165,7 @@ def create_dv( teardown=teardown, preallocation=preallocation, api_name=api_name, + source_ref=source_ref, ) as dv: if sc_volume_binding_mode_is_wffc(sc=storage_class) and consume_wffc: create_dummy_first_consumer_pod(dv=dv) @@ -572,19 +577,6 @@ def data_volume_template_dict( return dv.res -def data_volume_dict_modify_to_source_ref(dv, data_source): - dv.to_dict() - del dv.res["metadata"]["namespace"] - del dv.res["spec"]["source"] - del dv.res["spec"]["contentType"] - dv.res["spec"]["sourceRef"] = { - "kind": data_source.kind, - "name": data_source.name, - "namespace": data_source.namespace, - } - return dv.res - - def data_volume_template_with_source_ref_dict(data_source, storage_class=None): source_dict = data_source.source.instance.to_dict() dv = DataVolume( @@ -593,8 +585,16 @@ def data_volume_template_with_source_ref_dict(data_source, storage_class=None): size=get_dv_size_from_datasource(data_source=data_source), storage_class=storage_class or source_dict["spec"].get("storageClassName"), api_name="storage", + source_ref={ + "kind": data_source.kind, + "name": data_source.name, + "namespace": data_source.namespace, + }, ) - return data_volume_dict_modify_to_source_ref(dv=dv, data_source=data_source) + dv.to_dict() + # dataVolumeTemplate is not required to have the namespace explicitly set + dv.res["metadata"].pop("namespace", None) + return dv.res def get_test_artifact_server_url(schema="https"):