From c127604737bef14bb92f84286793e871ebd2c56f Mon Sep 17 00:00:00 2001 From: Adam Cinko Date: Mon, 29 Jun 2026 11:12:43 +0200 Subject: [PATCH 01/16] Use DataSource sourceRef for Windows VM cloning with vTPM Replace direct PVC cloning with DataSource sourceRef pattern for Windows 2022 VM tests. Create session-scoped Windows image fixtures in a dedicated validation-os-images namespace with proper RBAC for cross-namespace cloning. - Add tests/fixtures/images/validation_os_images.py with session-scoped fixtures for namespace, RBAC, DataVolume, and DataSource - Update cdi_clone and hotplug tests to use the new DataSource fixtures - Replace create_windows2022_dv_from_registry with create_windows2022_vm_using_existing_dv and create_windows2022_vm_with_data_volume_template in tests/utils.py - Add VALIDATION_OS_IMAGES to NamespacesNames constants Signed-off-by: Adam Cinko --- conftest.py | 1 + tests/fixtures/images/__init__.py | 0 tests/fixtures/images/validation_os_images.py | 127 ++++++++++++++++++ tests/storage/cdi_clone/conftest.py | 27 +++- tests/storage/cdi_clone/constants.py | 7 + tests/storage/cdi_clone/test_clone.py | 79 ++++++++++- tests/storage/conftest.py | 6 +- tests/storage/test_hotplug.py | 53 +++----- tests/utils.py | 62 ++++++++- utilities/constants/namespaces.py | 1 + 10 files changed, 317 insertions(+), 46 deletions(-) create mode 100644 tests/fixtures/images/__init__.py create mode 100644 tests/fixtures/images/validation_os_images.py create mode 100644 tests/storage/cdi_clone/constants.py diff --git a/conftest.py b/conftest.py index c65e0aeb03..a20a842c5a 100644 --- a/conftest.py +++ b/conftest.py @@ -77,6 +77,7 @@ pytest_plugins = [ "tests.fixtures.network.l2_bridge", "tests.fixtures.network.cluster", + "tests.fixtures.images.validation_os_images", ] LOGGER = logging.getLogger(__name__) diff --git a/tests/fixtures/images/__init__.py b/tests/fixtures/images/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/fixtures/images/validation_os_images.py b/tests/fixtures/images/validation_os_images.py new file mode 100644 index 0000000000..3daef88c69 --- /dev/null +++ b/tests/fixtures/images/validation_os_images.py @@ -0,0 +1,127 @@ +import pytest +from ocp_resources.cluster_role import ClusterRole +from ocp_resources.data_source import DataSource +from ocp_resources.datavolume import DataVolume +from ocp_resources.namespace import Namespace +from ocp_resources.role_binding import RoleBinding +from pytest_testconfig import config as py_config + +from utilities.artifactory import ( + cleanup_artifactory_secret_and_config_map, + get_artifactory_config_map, + get_artifactory_secret, + get_test_artifact_server_url, +) +from utilities.constants import BIND_IMMEDIATE_ANNOTATION, REGISTRY_STR, TIMEOUT_40MIN, TIMEOUT_50MIN, WIN_2K22, Images +from utilities.constants.namespaces import NamespacesNames +from utilities.os_utils import get_windows_container_disk_path +from utilities.storage import ( + generate_data_source_dict, +) + + +@pytest.fixture(scope="session") +def validation_os_images_namespace(admin_client): + validation_os_images_namespace = Namespace( + name=NamespacesNames.VALIDATION_OS_IMAGES, + client=admin_client, + ) + if validation_os_images_namespace.exists: + yield validation_os_images_namespace + else: + with validation_os_images_namespace as ns: + yield ns + + +@pytest.fixture(scope="session") +def validation_os_images_role_binding(admin_client, validation_os_images_namespace): + """Grants view permissions in the namespace so unprivileged clients can clone from it.""" + role_binding = RoleBinding( + client=admin_client, + name="validation-os-images-view", + namespace=validation_os_images_namespace.name, + subjects_kind="Group", + subjects_name="system:authenticated", + role_ref_kind=ClusterRole.kind, + role_ref_name="view", + ) + + if role_binding.exists: + yield role_binding + else: + with role_binding as rb: + yield rb + + +@pytest.fixture(scope="session") +def windows_validation_os_images_data_volume_scope_session( + admin_client, + validation_os_images_role_binding, + validation_os_images_namespace_artifactory_secret_and_configmap, +): + """Fixture that imports a Windows image into the validation os images namespace. Yields existing DataVolume if it was already created""" + + win_dv = DataVolume( + name=WIN_2K22, + namespace=validation_os_images_role_binding.namespace, + storage_class=py_config["default_storage_class"], + source=REGISTRY_STR, + url=f"{get_test_artifact_server_url(schema='registry')}/{get_windows_container_disk_path(os_value=WIN_2K22)}", + size=Images.Windows.CONTAINER_DISK_DV_SIZE, + client=admin_client, + api_name="storage", + secret=validation_os_images_namespace_artifactory_secret_and_configmap["secret"], + cert_configmap=validation_os_images_namespace_artifactory_secret_and_configmap["config_map"].name, + annotations=BIND_IMMEDIATE_ANNOTATION, + ) + + if win_dv.exists: + yield win_dv + else: + with win_dv as wdv: + wdv.wait_for_dv_success(timeout=TIMEOUT_50MIN) + yield wdv + + +@pytest.fixture(scope="session") +def windows_validation_os_images_data_source_scope_session( + admin_client, + windows_validation_os_images_data_volume_scope_session, +): + win_data_source = DataSource( + name=windows_validation_os_images_data_volume_scope_session.name, + namespace=windows_validation_os_images_data_volume_scope_session.namespace, + client=admin_client, + source=generate_data_source_dict(dv=windows_validation_os_images_data_volume_scope_session), + ) + if win_data_source.exists and any( + condition.get("type") == win_data_source.Condition.READY + and condition.get("status") == win_data_source.Condition.Status.TRUE + for condition in win_data_source.instance.get("status", {}).get("conditions", []) + ): + yield win_data_source + else: + with win_data_source as win_ds: + win_data_source.wait_for_condition( + condition=win_data_source.Condition.READY, + status=win_data_source.Condition.Status.TRUE, + timeout=TIMEOUT_40MIN, + ) + yield win_ds + + +@pytest.fixture(scope="session") +def validation_os_images_namespace_artifactory_secret_and_configmap(validation_os_images_role_binding): + artifactory_secret = get_artifactory_secret( + namespace=validation_os_images_role_binding.namespace, client=validation_os_images_role_binding.client + ) + artifactory_config_map = get_artifactory_config_map( + namespace=validation_os_images_role_binding.namespace, client=validation_os_images_role_binding.client + ) + try: + yield {"secret": artifactory_secret, "config_map": artifactory_config_map} + finally: + cleanup_artifactory_secret_and_config_map( + artifactory_secret=artifactory_secret, + artifactory_config_map=artifactory_config_map, + ) diff --git a/tests/storage/cdi_clone/conftest.py b/tests/storage/cdi_clone/conftest.py index 56e3c02790..4e0b1033e8 100644 --- a/tests/storage/cdi_clone/conftest.py +++ b/tests/storage/cdi_clone/conftest.py @@ -1,8 +1,9 @@ import pytest from ocp_resources.datavolume import DataVolume +from tests.storage.cdi_clone.constants import WINDOWS_CLONE_TIMEOUT from tests.storage.constants import QUAY_FEDORA_CONTAINER_IMAGE -from utilities.constants import Images +from utilities.constants import WIN_2K22, Images from utilities.constants.storage import REGISTRY_STR from utilities.storage import create_dv, data_volume @@ -60,3 +61,27 @@ def fedora_dv_with_block_volume_mode( ) as dv: dv.wait_for_dv_success() yield dv + + +@pytest.fixture(scope="class") +def cloned_windows_dv_multi_storage_scope_class( + unprivileged_client, + namespace, + storage_class_name_scope_class, + windows_validation_os_images_data_source_scope_session, +): + """Fixture that creates a cloned DataVolume from a Windows DataSource.""" + with create_dv( + client=unprivileged_client, + dv_name=f"dv-target-{WIN_2K22}-clone", + namespace=namespace.name, + size=Images.Windows.CONTAINER_DISK_DV_SIZE, + storage_class=storage_class_name_scope_class, + source_ref={ + "kind": windows_validation_os_images_data_source_scope_session.kind, + "name": windows_validation_os_images_data_source_scope_session.name, + "namespace": windows_validation_os_images_data_source_scope_session.namespace, + }, + ) as cdv: + cdv.wait_for_dv_success(timeout=WINDOWS_CLONE_TIMEOUT) + yield cdv diff --git a/tests/storage/cdi_clone/constants.py b/tests/storage/cdi_clone/constants.py new file mode 100644 index 0000000000..d58196af1e --- /dev/null +++ b/tests/storage/cdi_clone/constants.py @@ -0,0 +1,7 @@ +""" +Constants for CDI clone tests. +""" + +from utilities.constants import TIMEOUT_40MIN + +WINDOWS_CLONE_TIMEOUT = TIMEOUT_40MIN diff --git a/tests/storage/cdi_clone/test_clone.py b/tests/storage/cdi_clone/test_clone.py index 678f1b1f35..4e794a1c2a 100644 --- a/tests/storage/cdi_clone/test_clone.py +++ b/tests/storage/cdi_clone/test_clone.py @@ -5,15 +5,16 @@ import pytest from ocp_resources.datavolume import DataVolume -from tests.os_params import FEDORA_LATEST, WINDOWS_11, WINDOWS_11_TEMPLATE_LABELS +from tests.os_params import FEDORA_LATEST from tests.storage.utils import ( assert_pvc_snapshot_clone_annotation, assert_use_populator, - create_windows_vm_validate_guest_agent_info, ) -from utilities.constants import Images +from tests.utils import create_windows2022_vm_using_existing_dv +from utilities.constants import WIN_2K22, Images from utilities.constants.images import OS_FLAVOR_FEDORA, OS_FLAVOR_WINDOWS -from utilities.constants.timeouts import TIMEOUT_1MIN, TIMEOUT_40MIN +from utilities.constants.timeouts import TIMEOUT_1MIN +from utilities.ssp import validate_os_info_vmi_vs_windows_os from utilities.storage import ( check_disk_count_in_vm, create_dv, @@ -29,8 +30,6 @@ running_vm, ) -WINDOWS_CLONE_TIMEOUT = TIMEOUT_40MIN - def create_vm_from_clone_dv_template( vm_name, @@ -60,6 +59,7 @@ def create_vm_from_clone_dv_template( running_vm(vm=vm) +<<<<<<< HEAD @pytest.mark.tier3 @pytest.mark.parametrize( "data_volume_multi_storage_scope_function", @@ -93,6 +93,8 @@ def test_successful_clone_of_large_image( cdv.wait_for_dv_success(timeout=WINDOWS_CLONE_TIMEOUT) +======= +>>>>>>> ecf9cc62 (Use DataSource sourceRef for Windows VM cloning with vTPM) @pytest.mark.sno @pytest.mark.polarion("CNV-2148") @pytest.mark.gating() @@ -141,6 +143,7 @@ def test_successful_vm_restart_with_cloned_dv( @pytest.mark.tier3 +<<<<<<< HEAD @pytest.mark.parametrize( ("data_volume_multi_storage_scope_function", "vm_params"), [ @@ -184,8 +187,67 @@ def test_successful_vm_from_cloned_dv_windows( namespace=namespace, unprivileged_client=unprivileged_client, vm_params=vm_params, +======= +@pytest.mark.incremental +class TestWindowsClonedDv: + """ + Tests for Windows 2022 DV cloning, and VM creation with vTPM. + + Preconditions: + - Windows Server 2022 DataVolume + - Cloned DataVolume created from the source DataVolume (PVC clone) + """ + + @pytest.mark.polarion("CNV-1892") + def test_clone_dv_windows(self, cloned_windows_dv_multi_storage_scope_class): + """ + Test that a large image can be cloned. + + Preconditions: + - Cloned DataVolume created from the source DataVolume (PVC clone) + + Steps: + 1. Verify the cloned DataVolume status + + Expected: + - Cloned DataVolume status is "Succeeded" + """ + assert cloned_windows_dv_multi_storage_scope_class.status == DataVolume.Status.SUCCEEDED, ( + f"Cloned DV status is {cloned_windows_dv_multi_storage_scope_class.status}, expected {DataVolume.Status.SUCCEEDED}" +>>>>>>> ecf9cc62 (Use DataSource sourceRef for Windows VM cloning with vTPM) ) + @pytest.mark.polarion("CNV-3638") + def test_vm_from_cloned_dv_windows( + self, + unprivileged_client, + namespace, + modern_cpu_for_migration, + cloned_windows_dv_multi_storage_scope_class, + ): + """ + Test that a Windows 2022 VM with vTPM boots from a cloned DataVolume. + + Preconditions: + - Cloned DataVolume created from the source DataVolume (PVC clone) + + Steps: + 1. Create a Windows 2022 VM with vTPM from the cloned DataVolume using instance type and preference + 2. Wait for the VM to reach Running state + 3. Wait for Windows OS to be ready inside the VM + + Expected: + - VM OS info reported by VMI matches the expected Windows OS parameters + """ + with create_windows2022_vm_using_existing_dv( + namespace=namespace.name, + client=unprivileged_client, + vm_name=f"vm-{WIN_2K22}", + cpu_model=modern_cpu_for_migration, + existing_data_volume=cloned_windows_dv_multi_storage_scope_class, + ) as vm: + validate_os_info_vmi_vs_windows_os(vm=vm) + @pytest.mark.parametrize( "data_volume_snapshot_capable_storage_scope_function", @@ -200,8 +262,13 @@ def test_successful_vm_from_cloned_dv_windows( ), pytest.param( { +<<<<<<< HEAD "dv_name": f"dv-source-{OS_FLAVOR_WINDOWS}", "image": f"{Images.Windows.DIR}/{Images.Windows.WIN11_IMG}", +======= + "dv_name": "dv-source-win", + "image": f"{Images.Windows.DIR}/{Images.Windows.WIN2022_IMG}", +>>>>>>> ecf9cc62 (Use DataSource sourceRef for Windows VM cloning with vTPM) "dv_size": Images.Windows.DEFAULT_DV_SIZE, }, marks=(pytest.mark.polarion("CNV-3552"), pytest.mark.tier3()), diff --git a/tests/storage/conftest.py b/tests/storage/conftest.py index 42c5747a70..ec0a6c0380 100644 --- a/tests/storage/conftest.py +++ b/tests/storage/conftest.py @@ -58,7 +58,11 @@ INTERNAL_HTTP_SERVER_ADDRESS, ExecCommandOnPod, ) -from utilities.storage import data_volume_template_with_source_ref_dict, get_downloaded_artifact, write_file_via_ssh +from utilities.storage import ( + data_volume_template_with_source_ref_dict, + get_downloaded_artifact, + write_file_via_ssh, +) from utilities.virt import VirtualMachineForTests, running_vm LOGGER = logging.getLogger(__name__) diff --git a/tests/storage/test_hotplug.py b/tests/storage/test_hotplug.py index 6ff7200d5c..9b52bf65e7 100644 --- a/tests/storage/test_hotplug.py +++ b/tests/storage/test_hotplug.py @@ -14,8 +14,8 @@ from ocp_resources.storage_profile import StorageProfile from tests.storage.utils import assert_disk_bus -from tests.utils import create_windows2022_dv_from_registry, create_windows2022_vm_with_vtpm_from_registry -from utilities.constants import Images +from tests.utils import create_windows2022_vm_with_data_volume_template +from utilities.constants import WIN_2K22, Images from utilities.constants.storage import HOTPLUG_DISK_SCSI_BUS, HOTPLUG_DISK_SERIAL, HOTPLUG_DISK_VIRTIO_BUS from utilities.hco import ResourceEditorValidateHCOReconcile from utilities.jira import is_jira_open @@ -23,6 +23,7 @@ assert_disk_serial, assert_hotplugvolume_nonexist, create_dv, + data_volume_template_with_source_ref_dict, virtctl_volume, wait_for_vm_volume_ready, ) @@ -64,12 +65,12 @@ def enabled_feature_gate_for_declarative_hotplug_volumes( @pytest.fixture(scope="class") def hotplug_volume_windows_scope_class( - request, namespace, vm_instance_from_template_multi_storage_scope_class, blank_disk_dv_multi_storage_scope_class + request, namespace, vm_instance_multi_storage_scope_class, blank_disk_dv_multi_storage_scope_class ): with virtctl_volume( action="add", namespace=namespace.name, - vm_name=vm_instance_from_template_multi_storage_scope_class.name, + vm_name=vm_instance_multi_storage_scope_class.name, volume_name=blank_disk_dv_multi_storage_scope_class.name, **request.param, ) as res: @@ -79,34 +80,22 @@ def hotplug_volume_windows_scope_class( @pytest.fixture(scope="class") -def windows_dv_from_registry_scope_class( - unprivileged_client, - namespace, - storage_class_matrix__class__, -): - """Creates a Windows 2022 DataVolume from registry container disk.""" - with create_windows2022_dv_from_registry( - dv_name="dv-windows-2022-hotplug", - namespace=namespace.name, - client=unprivileged_client, - storage_class=next(iter(storage_class_matrix__class__)), - ) as dv_dict: - yield dv_dict - - -@pytest.fixture(scope="class") -def vm_instance_from_template_multi_storage_scope_class( +def vm_instance_multi_storage_scope_class( unprivileged_client, namespace, modern_cpu_for_migration, - windows_dv_from_registry_scope_class, + windows_validation_os_images_data_source_scope_session, + storage_class_name_scope_class, ): - """Creates a Windows 2022 VM with vTPM from registry container disk.""" - with create_windows2022_vm_with_vtpm_from_registry( - dv_dict=windows_dv_from_registry_scope_class, + """Creates a Windows 2022 VM with vTPM from the session-scoped Windows DataSource.""" + with create_windows2022_vm_with_data_volume_template( + dv_template=data_volume_template_with_source_ref_dict( + data_source=windows_validation_os_images_data_source_scope_session, + storage_class=storage_class_name_scope_class, + ), namespace=namespace.name, client=unprivileged_client, - vm_name="vm-win-2022-hotplug", + vm_name=f"vm-{WIN_2K22}-hotplug", cpu_model=modern_cpu_for_migration, ) as vm: yield vm @@ -281,17 +270,17 @@ class TestHotPlugWindows: def test_windows_hotplug( self, blank_disk_dv_multi_storage_scope_class, - vm_instance_from_template_multi_storage_scope_class, + vm_instance_multi_storage_scope_class, ): wait_for_vm_volume_ready( - vm=vm_instance_from_template_multi_storage_scope_class, + vm=vm_instance_multi_storage_scope_class, volume_name=blank_disk_dv_multi_storage_scope_class.name, ) assert_disk_serial( command=shlex.split("wmic diskdrive get SerialNumber"), - vm=vm_instance_from_template_multi_storage_scope_class, + vm=vm_instance_multi_storage_scope_class, ) - assert_hotplugvolume_nonexist(vm=vm_instance_from_template_multi_storage_scope_class) + assert_hotplugvolume_nonexist(vm=vm_instance_multi_storage_scope_class) @pytest.mark.polarion("CNV-11391") @pytest.mark.dependency(depends=["test_windows_hotplug"]) @@ -299,11 +288,11 @@ def test_windows_hotplug_migrate( self, admin_client: DynamicClient, blank_disk_dv_multi_storage_scope_class: DataVolume, - vm_instance_from_template_multi_storage_scope_class: VirtualMachineForTests, + vm_instance_multi_storage_scope_class: VirtualMachineForTests, ): if is_dv_migratable(dv=blank_disk_dv_multi_storage_scope_class): migrate_vm_and_verify( - vm=vm_instance_from_template_multi_storage_scope_class, + vm=vm_instance_multi_storage_scope_class, client=admin_client, check_ssh_connectivity=True, ) diff --git a/tests/utils.py b/tests/utils.py index b9bc63c0e3..54a4a890b5 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -27,12 +27,10 @@ from timeout_sampler import TimeoutExpiredError, TimeoutSampler, retry from utilities.artifactory import ( - cleanup_artifactory_secret_and_config_map, get_artifactory_config_map, get_artifactory_header, get_artifactory_secret, get_http_image_url, - get_test_artifact_server_url, ) from utilities.constants import Images from utilities.constants.cluster import RHSM_SECRET_NAME @@ -55,11 +53,17 @@ TIMEOUT_10SEC, TIMEOUT_15SEC, TIMEOUT_30MIN, +<<<<<<< HEAD ) from utilities.constants.virt import ( DISK_SERIAL, NODE_HUGE_PAGES_1GI_KEY, WIN_2K22, +======= + U1_LARGE, + WINDOWS_2K22_PREFERENCE, + Images, +>>>>>>> ecf9cc62 (Use DataSource sourceRef for Windows VM cloning with vTPM) ) from utilities.data_collector import get_data_collector_dir, write_to_file from utilities.exceptions import ResourceValueError @@ -67,8 +71,11 @@ from utilities.infra import ( ExecCommandOnPod, ) +<<<<<<< HEAD from utilities.os_utils import get_windows_container_disk_path from utilities.storage import construct_datavolume_source_dict +======= +>>>>>>> ecf9cc62 (Use DataSource sourceRef for Windows VM cloning with vTPM) from utilities.virt import ( VirtualMachineForTests, fedora_vm_body, @@ -714,6 +721,7 @@ def verify_rwx_default_storage(client: DynamicClient) -> None: @contextmanager +<<<<<<< HEAD def create_windows2022_dv_from_registry( dv_name: str, namespace: str, @@ -762,16 +770,57 @@ def create_windows2022_dv_from_registry( @contextmanager def create_windows2022_vm_with_vtpm_from_registry( dv_dict: dict, +======= +def create_windows2022_vm_using_existing_dv( +>>>>>>> ecf9cc62 (Use DataSource sourceRef for Windows VM cloning with vTPM) + namespace: str, + client: DynamicClient, + vm_name: str, + cpu_model: str | None = None, + existing_data_volume: DataVolume | None = None, +) -> Generator[VirtualMachineForTests]: + """ + Creates a Windows Server 2022 VM with vTPM using existing DataVolume. + + Args: + existing_data_volume: DataVolume to use for the VM's data volume + namespace: Kubernetes namespace + client: Kubernetes client + vm_name: Name for the VirtualMachine + cpu_model: CPU model specification (can be None) + + Yields: + VirtualMachineForTests: Running Windows 2022 VM with vTPM + """ + + with VirtualMachineForTests( + name=vm_name, + namespace=namespace, + client=client, + os_flavor=OS_FLAVOR_WIN_CONTAINER_DISK, + vm_instance_type=VirtualMachineClusterInstancetype(name=U1_LARGE, client=client), + vm_preference=VirtualMachineClusterPreference(name=WINDOWS_2K22_PREFERENCE, client=client), + data_volume=existing_data_volume, + cpu_model=cpu_model, + ) as vm: + running_vm(vm=vm) + wait_for_windows_vm(vm=vm, version="2022") + yield vm + + +@contextmanager +def create_windows2022_vm_with_data_volume_template( namespace: str, client: DynamicClient, vm_name: str, - cpu_model: str | None, + cpu_model: str | None = None, + dv_template: dict | None = None, ) -> Generator[VirtualMachineForTests]: """ - Creates a Windows Server 2022 VM with vTPM from registry container disk. + Creates a Windows Server 2022 VM with vTPM with dv template. Args: - dv_dict: DataVolume template dictionary with metadata and spec + dv_template: DataVolume template dictionary with metadata and spec namespace: Kubernetes namespace client: Kubernetes client vm_name: Name for the VirtualMachine @@ -780,6 +829,7 @@ def create_windows2022_vm_with_vtpm_from_registry( Yields: VirtualMachineForTests: Running Windows 2022 VM with vTPM """ + with VirtualMachineForTests( name=vm_name, namespace=namespace, @@ -787,7 +837,7 @@ def create_windows2022_vm_with_vtpm_from_registry( os_flavor=OS_FLAVOR_WIN_CONTAINER_DISK, vm_instance_type=VirtualMachineClusterInstancetype(name=U1_LARGE, client=client), vm_preference=VirtualMachineClusterPreference(name=WINDOWS_2K22_PREFERENCE, client=client), - data_volume_template=dv_dict, + data_volume_template=dv_template, cpu_model=cpu_model, ) as vm: running_vm(vm=vm) diff --git a/utilities/constants/namespaces.py b/utilities/constants/namespaces.py index d4a0dfc584..9b9c213c3f 100644 --- a/utilities/constants/namespaces.py +++ b/utilities/constants/namespaces.py @@ -26,3 +26,4 @@ class NamespacesNames: OPENSHIFT_MTV = "openshift-mtv" CNV_TESTS_UTILITIES = "cnv-tests-utilities" ADP_NAMESPACE = "openshift-adp" + VALIDATION_OS_IMAGES = "validation-os-images" From 7c50e63447972cddf2b2576164116957564e11d8 Mon Sep 17 00:00:00 2001 From: Adam Cinko Date: Tue, 30 Jun 2026 07:54:15 +0200 Subject: [PATCH 02/16] remove artifactory credential fetching from fixture and only fetch when needed Signed-off-by: Adam Cinko --- tests/fixtures/images/validation_os_images.py | 58 +++++++++---------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/tests/fixtures/images/validation_os_images.py b/tests/fixtures/images/validation_os_images.py index 3daef88c69..dc6f2222b5 100644 --- a/tests/fixtures/images/validation_os_images.py +++ b/tests/fixtures/images/validation_os_images.py @@ -57,30 +57,45 @@ def validation_os_images_role_binding(admin_client, validation_os_images_namespa def windows_validation_os_images_data_volume_scope_session( admin_client, validation_os_images_role_binding, - validation_os_images_namespace_artifactory_secret_and_configmap, ): """Fixture that imports a Windows image into the validation os images namespace. Yields existing DataVolume if it was already created""" win_dv = DataVolume( name=WIN_2K22, namespace=validation_os_images_role_binding.namespace, - storage_class=py_config["default_storage_class"], - source=REGISTRY_STR, - url=f"{get_test_artifact_server_url(schema='registry')}/{get_windows_container_disk_path(os_value=WIN_2K22)}", - size=Images.Windows.CONTAINER_DISK_DV_SIZE, - client=admin_client, - api_name="storage", - secret=validation_os_images_namespace_artifactory_secret_and_configmap["secret"], - cert_configmap=validation_os_images_namespace_artifactory_secret_and_configmap["config_map"].name, - annotations=BIND_IMMEDIATE_ANNOTATION, + client=validation_os_images_role_binding.client, ) if win_dv.exists: yield win_dv else: - with win_dv as wdv: - wdv.wait_for_dv_success(timeout=TIMEOUT_50MIN) - yield wdv + artifactory_secret = get_artifactory_secret( + namespace=validation_os_images_role_binding.namespace, client=validation_os_images_role_binding.client + ) + artifactory_config_map = get_artifactory_config_map( + namespace=validation_os_images_role_binding.namespace, client=validation_os_images_role_binding.client + ) + try: + with DataVolume( + name=WIN_2K22, + namespace=validation_os_images_role_binding.namespace, + storage_class=py_config["default_storage_class"], + source=REGISTRY_STR, + url=f"{get_test_artifact_server_url(schema='registry')}/{get_windows_container_disk_path(os_value=WIN_2K22)}", + size=Images.Windows.CONTAINER_DISK_DV_SIZE, + client=admin_client, + api_name="storage", + secret=artifactory_secret, + cert_configmap=artifactory_config_map.name, + annotations=BIND_IMMEDIATE_ANNOTATION, + ) as wdv: + wdv.wait_for_dv_success(timeout=TIMEOUT_50MIN) + yield wdv + finally: + cleanup_artifactory_secret_and_config_map( + artifactory_secret=artifactory_secret, + artifactory_config_map=artifactory_config_map, + ) @pytest.fixture(scope="session") @@ -108,20 +123,3 @@ def windows_validation_os_images_data_source_scope_session( timeout=TIMEOUT_40MIN, ) yield win_ds - - -@pytest.fixture(scope="session") -def validation_os_images_namespace_artifactory_secret_and_configmap(validation_os_images_role_binding): - artifactory_secret = get_artifactory_secret( - namespace=validation_os_images_role_binding.namespace, client=validation_os_images_role_binding.client - ) - artifactory_config_map = get_artifactory_config_map( - namespace=validation_os_images_role_binding.namespace, client=validation_os_images_role_binding.client - ) - try: - yield {"secret": artifactory_secret, "config_map": artifactory_config_map} - finally: - cleanup_artifactory_secret_and_config_map( - artifactory_secret=artifactory_secret, - artifactory_config_map=artifactory_config_map, - ) From 102beedb7b4a103551268b2e06d27af7f6fda849 Mon Sep 17 00:00:00 2001 From: Adam Cinko Date: Tue, 30 Jun 2026 14:03:06 +0200 Subject: [PATCH 03/16] apply reviewer's suggestions Signed-off-by: Adam Cinko --- tests/fixtures/images/validation_os_images.py | 38 ++++++++++++++----- tests/storage/cdi_clone/conftest.py | 4 +- tests/storage/cdi_clone/constants.py | 4 +- tests/storage/cdi_clone/test_clone.py | 3 +- tests/storage/test_hotplug.py | 3 +- utilities/constants/namespaces.py | 1 - 6 files changed, 36 insertions(+), 17 deletions(-) diff --git a/tests/fixtures/images/validation_os_images.py b/tests/fixtures/images/validation_os_images.py index dc6f2222b5..0d87ec0647 100644 --- a/tests/fixtures/images/validation_os_images.py +++ b/tests/fixtures/images/validation_os_images.py @@ -3,6 +3,7 @@ from ocp_resources.data_source import DataSource from ocp_resources.datavolume import DataVolume from ocp_resources.namespace import Namespace +from ocp_resources.persistent_volume_claim import PersistentVolumeClaim from ocp_resources.role_binding import RoleBinding from pytest_testconfig import config as py_config @@ -12,8 +13,10 @@ get_artifactory_secret, get_test_artifact_server_url, ) -from utilities.constants import BIND_IMMEDIATE_ANNOTATION, REGISTRY_STR, TIMEOUT_40MIN, TIMEOUT_50MIN, WIN_2K22, Images -from utilities.constants.namespaces import NamespacesNames +from utilities.constants import Images +from utilities.constants.storage import BIND_IMMEDIATE_ANNOTATION, REGISTRY_STR +from utilities.constants.timeouts import TIMEOUT_10MIN, TIMEOUT_50MIN +from utilities.constants.virt import WIN_2K22 from utilities.os_utils import get_windows_container_disk_path from utilities.storage import ( generate_data_source_dict, @@ -23,7 +26,7 @@ @pytest.fixture(scope="session") def validation_os_images_namespace(admin_client): validation_os_images_namespace = Namespace( - name=NamespacesNames.VALIDATION_OS_IMAGES, + name="validation-os-images", client=admin_client, ) if validation_os_images_namespace.exists: @@ -58,17 +61,34 @@ def windows_validation_os_images_data_volume_scope_session( admin_client, validation_os_images_role_binding, ): - """Fixture that imports a Windows image into the validation os images namespace. Yields existing DataVolume if it was already created""" + """ + Fixture that imports a Windows image into the validation os images namespace. Yields existing DataVolume if it was already created - win_dv = DataVolume( + The DV is also used in self-validation and if we move the version, UI needs to follow. + """ + + win_pvc = PersistentVolumeClaim( name=WIN_2K22, namespace=validation_os_images_role_binding.namespace, client=validation_os_images_role_binding.client, ) - - if win_dv.exists: - yield win_dv + if win_pvc.exists: + if win_pvc.status != PersistentVolumeClaim.Status.BOUND: + raise RuntimeError( + f"PVC {win_pvc.name} in namespace {validation_os_images_role_binding.namespace} is in {win_pvc.status} state, expected {PersistentVolumeClaim.Status.BOUND}." + ) + yield DataVolume( + name=WIN_2K22, + namespace=validation_os_images_role_binding.namespace, + client=validation_os_images_role_binding.client, + ) else: + if py_config.get("conformance_tests"): + raise RuntimeError( + f"PVC {WIN_2K22} does not exist in namespace {validation_os_images_role_binding.namespace}. " + "Self-validation requires the Windows image to be pre-created." + ) + artifactory_secret = get_artifactory_secret( namespace=validation_os_images_role_binding.namespace, client=validation_os_images_role_binding.client ) @@ -120,6 +140,6 @@ def windows_validation_os_images_data_source_scope_session( win_data_source.wait_for_condition( condition=win_data_source.Condition.READY, status=win_data_source.Condition.Status.TRUE, - timeout=TIMEOUT_40MIN, + timeout=TIMEOUT_10MIN, ) yield win_ds diff --git a/tests/storage/cdi_clone/conftest.py b/tests/storage/cdi_clone/conftest.py index 4e0b1033e8..603d278086 100644 --- a/tests/storage/cdi_clone/conftest.py +++ b/tests/storage/cdi_clone/conftest.py @@ -3,8 +3,9 @@ from tests.storage.cdi_clone.constants import WINDOWS_CLONE_TIMEOUT from tests.storage.constants import QUAY_FEDORA_CONTAINER_IMAGE -from utilities.constants import WIN_2K22, Images +from utilities.constants import Images from utilities.constants.storage import REGISTRY_STR +from utilities.constants.virt import WIN_2K22 from utilities.storage import create_dv, data_volume @@ -70,7 +71,6 @@ def cloned_windows_dv_multi_storage_scope_class( storage_class_name_scope_class, windows_validation_os_images_data_source_scope_session, ): - """Fixture that creates a cloned DataVolume from a Windows DataSource.""" with create_dv( client=unprivileged_client, dv_name=f"dv-target-{WIN_2K22}-clone", diff --git a/tests/storage/cdi_clone/constants.py b/tests/storage/cdi_clone/constants.py index d58196af1e..f472cf86dc 100644 --- a/tests/storage/cdi_clone/constants.py +++ b/tests/storage/cdi_clone/constants.py @@ -2,6 +2,4 @@ Constants for CDI clone tests. """ -from utilities.constants import TIMEOUT_40MIN - -WINDOWS_CLONE_TIMEOUT = TIMEOUT_40MIN +WINDOWS_CLONE_TIMEOUT = 60 * 40 diff --git a/tests/storage/cdi_clone/test_clone.py b/tests/storage/cdi_clone/test_clone.py index 4e794a1c2a..ede98e9a53 100644 --- a/tests/storage/cdi_clone/test_clone.py +++ b/tests/storage/cdi_clone/test_clone.py @@ -11,9 +11,10 @@ assert_use_populator, ) from tests.utils import create_windows2022_vm_using_existing_dv -from utilities.constants import WIN_2K22, Images +from utilities.constants import Images from utilities.constants.images import OS_FLAVOR_FEDORA, OS_FLAVOR_WINDOWS from utilities.constants.timeouts import TIMEOUT_1MIN +from utilities.constants.virt import WIN_2K22 from utilities.ssp import validate_os_info_vmi_vs_windows_os from utilities.storage import ( check_disk_count_in_vm, diff --git a/tests/storage/test_hotplug.py b/tests/storage/test_hotplug.py index 9b52bf65e7..45da278ef0 100644 --- a/tests/storage/test_hotplug.py +++ b/tests/storage/test_hotplug.py @@ -15,8 +15,9 @@ from tests.storage.utils import assert_disk_bus from tests.utils import create_windows2022_vm_with_data_volume_template -from utilities.constants import WIN_2K22, Images +from utilities.constants import Images from utilities.constants.storage import HOTPLUG_DISK_SCSI_BUS, HOTPLUG_DISK_SERIAL, HOTPLUG_DISK_VIRTIO_BUS +from utilities.constants.virt import WIN_2K22 from utilities.hco import ResourceEditorValidateHCOReconcile from utilities.jira import is_jira_open from utilities.storage import ( diff --git a/utilities/constants/namespaces.py b/utilities/constants/namespaces.py index 9b9c213c3f..d4a0dfc584 100644 --- a/utilities/constants/namespaces.py +++ b/utilities/constants/namespaces.py @@ -26,4 +26,3 @@ class NamespacesNames: OPENSHIFT_MTV = "openshift-mtv" CNV_TESTS_UTILITIES = "cnv-tests-utilities" ADP_NAMESPACE = "openshift-adp" - VALIDATION_OS_IMAGES = "validation-os-images" From 176ef095251f3cf45be4f2e11e844abe4136401e Mon Sep 17 00:00:00 2001 From: Adam Cinko Date: Wed, 1 Jul 2026 11:29:06 +0200 Subject: [PATCH 04/16] code cleanup Signed-off-by: Adam Cinko --- tests/fixtures/images/validation_os_images.py | 50 +++++++------------ 1 file changed, 18 insertions(+), 32 deletions(-) diff --git a/tests/fixtures/images/validation_os_images.py b/tests/fixtures/images/validation_os_images.py index 0d87ec0647..ff2b7fb05b 100644 --- a/tests/fixtures/images/validation_os_images.py +++ b/tests/fixtures/images/validation_os_images.py @@ -3,8 +3,8 @@ from ocp_resources.data_source import DataSource from ocp_resources.datavolume import DataVolume from ocp_resources.namespace import Namespace -from ocp_resources.persistent_volume_claim import PersistentVolumeClaim from ocp_resources.role_binding import RoleBinding +from ocp_resources.utils.constants import TIMEOUT_1MINUTE from pytest_testconfig import config as py_config from utilities.artifactory import ( @@ -67,27 +67,18 @@ def windows_validation_os_images_data_volume_scope_session( The DV is also used in self-validation and if we move the version, UI needs to follow. """ - win_pvc = PersistentVolumeClaim( + win_dv = DataVolume( name=WIN_2K22, namespace=validation_os_images_role_binding.namespace, client=validation_os_images_role_binding.client, ) - if win_pvc.exists: - if win_pvc.status != PersistentVolumeClaim.Status.BOUND: - raise RuntimeError( - f"PVC {win_pvc.name} in namespace {validation_os_images_role_binding.namespace} is in {win_pvc.status} state, expected {PersistentVolumeClaim.Status.BOUND}." - ) - yield DataVolume( - name=WIN_2K22, - namespace=validation_os_images_role_binding.namespace, - client=validation_os_images_role_binding.client, - ) + if win_dv.exists: + win_dv.wait_for_dv_success(timeout=TIMEOUT_1MINUTE) + yield win_dv else: - if py_config.get("conformance_tests"): - raise RuntimeError( - f"PVC {WIN_2K22} does not exist in namespace {validation_os_images_role_binding.namespace}. " - "Self-validation requires the Windows image to be pre-created." - ) + assert not py_config.get("conformance_tests"), ( + f"Windows image {WIN_2K22} does not exist in namespace {validation_os_images_role_binding.namespace}. Self-validation requires the Windows image to be pre-created." + ) artifactory_secret = get_artifactory_secret( namespace=validation_os_images_role_binding.namespace, client=validation_os_images_role_binding.client @@ -101,7 +92,7 @@ def windows_validation_os_images_data_volume_scope_session( namespace=validation_os_images_role_binding.namespace, storage_class=py_config["default_storage_class"], source=REGISTRY_STR, - url=f"{get_test_artifact_server_url(schema='registry')}/{get_windows_container_disk_path(os_value=WIN_2K22)}", + url=f"{get_test_artifact_server_url(schema=REGISTRY_STR)}/{get_windows_container_disk_path(os_value=WIN_2K22)}", size=Images.Windows.CONTAINER_DISK_DV_SIZE, client=admin_client, api_name="storage", @@ -129,17 +120,12 @@ def windows_validation_os_images_data_source_scope_session( client=admin_client, source=generate_data_source_dict(dv=windows_validation_os_images_data_volume_scope_session), ) - if win_data_source.exists and any( - condition.get("type") == win_data_source.Condition.READY - and condition.get("status") == win_data_source.Condition.Status.TRUE - for condition in win_data_source.instance.get("status", {}).get("conditions", []) - ): - yield win_data_source - else: - with win_data_source as win_ds: - win_data_source.wait_for_condition( - condition=win_data_source.Condition.READY, - status=win_data_source.Condition.Status.TRUE, - timeout=TIMEOUT_10MIN, - ) - yield win_ds + if not win_data_source.exists: + win_data_source.deploy() + + win_data_source.wait_for_condition( + condition=win_data_source.Condition.READY, + status=win_data_source.Condition.Status.TRUE, + timeout=TIMEOUT_10MIN, + ) + yield win_data_source From a776bc8f5e9663318207904995a351d08d8394c2 Mon Sep 17 00:00:00 2001 From: Adam Cinko Date: Thu, 2 Jul 2026 08:31:43 +0200 Subject: [PATCH 05/16] cleanup only if the config map and secret existed plus code cleanup Signed-off-by: Adam Cinko --- tests/fixtures/images/validation_os_images.py | 47 +++++++++---------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/tests/fixtures/images/validation_os_images.py b/tests/fixtures/images/validation_os_images.py index ff2b7fb05b..053cfb1184 100644 --- a/tests/fixtures/images/validation_os_images.py +++ b/tests/fixtures/images/validation_os_images.py @@ -67,10 +67,25 @@ def windows_validation_os_images_data_volume_scope_session( The DV is also used in self-validation and if we move the version, UI needs to follow. """ + artifactory_secret = get_artifactory_secret( + namespace=validation_os_images_role_binding.namespace, client=validation_os_images_role_binding.client + ) + artifactory_config_map = get_artifactory_config_map( + namespace=validation_os_images_role_binding.namespace, client=validation_os_images_role_binding.client + ) + win_dv = DataVolume( name=WIN_2K22, namespace=validation_os_images_role_binding.namespace, + storage_class=py_config["default_storage_class"], + source=REGISTRY_STR, + url=f"{get_test_artifact_server_url(schema=REGISTRY_STR)}/{get_windows_container_disk_path(os_value=WIN_2K22)}", + size=Images.Windows.CONTAINER_DISK_DV_SIZE, client=validation_os_images_role_binding.client, + api_name="storage", + secret=artifactory_secret, + cert_configmap=artifactory_config_map.name, + annotations=BIND_IMMEDIATE_ANNOTATION, ) if win_dv.exists: win_dv.wait_for_dv_success(timeout=TIMEOUT_1MINUTE) @@ -80,33 +95,13 @@ def windows_validation_os_images_data_volume_scope_session( f"Windows image {WIN_2K22} does not exist in namespace {validation_os_images_role_binding.namespace}. Self-validation requires the Windows image to be pre-created." ) - artifactory_secret = get_artifactory_secret( - namespace=validation_os_images_role_binding.namespace, client=validation_os_images_role_binding.client - ) - artifactory_config_map = get_artifactory_config_map( - namespace=validation_os_images_role_binding.namespace, client=validation_os_images_role_binding.client + with win_dv as wdv: + wdv.wait_for_dv_success(timeout=TIMEOUT_50MIN) + yield wdv + cleanup_artifactory_secret_and_config_map( + artifactory_secret=artifactory_secret, + artifactory_config_map=artifactory_config_map, ) - try: - with DataVolume( - name=WIN_2K22, - namespace=validation_os_images_role_binding.namespace, - storage_class=py_config["default_storage_class"], - source=REGISTRY_STR, - url=f"{get_test_artifact_server_url(schema=REGISTRY_STR)}/{get_windows_container_disk_path(os_value=WIN_2K22)}", - size=Images.Windows.CONTAINER_DISK_DV_SIZE, - client=admin_client, - api_name="storage", - secret=artifactory_secret, - cert_configmap=artifactory_config_map.name, - annotations=BIND_IMMEDIATE_ANNOTATION, - ) as wdv: - wdv.wait_for_dv_success(timeout=TIMEOUT_50MIN) - yield wdv - finally: - cleanup_artifactory_secret_and_config_map( - artifactory_secret=artifactory_secret, - artifactory_config_map=artifactory_config_map, - ) @pytest.fixture(scope="session") From f38345155a661578ddb23b95f65105a859810b49 Mon Sep 17 00:00:00 2001 From: Adam Cinko Date: Thu, 2 Jul 2026 13:45:57 +0200 Subject: [PATCH 06/16] verify the PVC from DataStore exists before proceeding also removed constants from CDI clone and cleaned up the code further Signed-off-by: Adam Cinko --- tests/fixtures/images/validation_os_images.py | 57 +++++++++++-------- tests/storage/cdi_clone/conftest.py | 8 +-- tests/storage/cdi_clone/constants.py | 5 -- 3 files changed, 38 insertions(+), 32 deletions(-) delete mode 100644 tests/storage/cdi_clone/constants.py diff --git a/tests/fixtures/images/validation_os_images.py b/tests/fixtures/images/validation_os_images.py index 053cfb1184..f161320238 100644 --- a/tests/fixtures/images/validation_os_images.py +++ b/tests/fixtures/images/validation_os_images.py @@ -57,45 +57,46 @@ def validation_os_images_role_binding(admin_client, validation_os_images_namespa @pytest.fixture(scope="session") -def windows_validation_os_images_data_volume_scope_session( - admin_client, - validation_os_images_role_binding, -): +def windows_validation_os_images_data_volume_scope_session(validation_os_images_role_binding, conformance_tests): """ Fixture that imports a Windows image into the validation os images namespace. Yields existing DataVolume if it was already created The DV is also used in self-validation and if we move the version, UI needs to follow. """ - artifactory_secret = get_artifactory_secret( - namespace=validation_os_images_role_binding.namespace, client=validation_os_images_role_binding.client - ) - artifactory_config_map = get_artifactory_config_map( - namespace=validation_os_images_role_binding.namespace, client=validation_os_images_role_binding.client - ) - win_dv = DataVolume( name=WIN_2K22, namespace=validation_os_images_role_binding.namespace, - storage_class=py_config["default_storage_class"], - source=REGISTRY_STR, - url=f"{get_test_artifact_server_url(schema=REGISTRY_STR)}/{get_windows_container_disk_path(os_value=WIN_2K22)}", - size=Images.Windows.CONTAINER_DISK_DV_SIZE, client=validation_os_images_role_binding.client, - api_name="storage", - secret=artifactory_secret, - cert_configmap=artifactory_config_map.name, - annotations=BIND_IMMEDIATE_ANNOTATION, ) if win_dv.exists: win_dv.wait_for_dv_success(timeout=TIMEOUT_1MINUTE) yield win_dv else: - assert not py_config.get("conformance_tests"), ( - f"Windows image {WIN_2K22} does not exist in namespace {validation_os_images_role_binding.namespace}. Self-validation requires the Windows image to be pre-created." + assert not conformance_tests, ( + f"Windows image {win_dv.name} does not exist in namespace {validation_os_images_role_binding.namespace}. Self-validation requires the Windows image to be pre-created." ) - with win_dv as wdv: + artifactory_secret = get_artifactory_secret( + namespace=validation_os_images_role_binding.namespace, client=validation_os_images_role_binding.client + ) + artifactory_config_map = get_artifactory_config_map( + namespace=validation_os_images_role_binding.namespace, client=validation_os_images_role_binding.client + ) + + with DataVolume( + name=win_dv.name, + namespace=win_dv.namespace, + client=win_dv.client, + storage_class=py_config["default_storage_class"], + source=REGISTRY_STR, + url=f"{get_test_artifact_server_url(schema=REGISTRY_STR)}/{get_windows_container_disk_path(os_value=WIN_2K22)}", + size=Images.Windows.CONTAINER_DISK_DV_SIZE, + api_name="storage", + secret=artifactory_secret, + cert_configmap=artifactory_config_map.name, + annotations=BIND_IMMEDIATE_ANNOTATION, + ) as wdv: wdv.wait_for_dv_success(timeout=TIMEOUT_50MIN) yield wdv cleanup_artifactory_secret_and_config_map( @@ -115,7 +116,17 @@ def windows_validation_os_images_data_source_scope_session( client=admin_client, source=generate_data_source_dict(dv=windows_validation_os_images_data_volume_scope_session), ) - if not win_data_source.exists: + if win_data_source.exists: + source_pvc = win_data_source.instance.spec.source.pvc + assert source_pvc.name == windows_validation_os_images_data_volume_scope_session.pvc.name, ( + f"DataSource {win_data_source.name} source PVC name is {source_pvc.name}, " + f"expected {windows_validation_os_images_data_volume_scope_session.pvc.name}" + ) + assert source_pvc.namespace == windows_validation_os_images_data_volume_scope_session.pvc.namespace, ( + f"DataSource {win_data_source.name} source PVC namespace is {source_pvc.namespace}, " + f"expected {windows_validation_os_images_data_volume_scope_session.pvc.namespace}" + ) + else: win_data_source.deploy() win_data_source.wait_for_condition( diff --git a/tests/storage/cdi_clone/conftest.py b/tests/storage/cdi_clone/conftest.py index 603d278086..1a8db95d28 100644 --- a/tests/storage/cdi_clone/conftest.py +++ b/tests/storage/cdi_clone/conftest.py @@ -1,12 +1,12 @@ import pytest from ocp_resources.datavolume import DataVolume -from tests.storage.cdi_clone.constants import WINDOWS_CLONE_TIMEOUT from tests.storage.constants import QUAY_FEDORA_CONTAINER_IMAGE from utilities.constants import Images from utilities.constants.storage import REGISTRY_STR +from utilities.constants.timeouts import TIMEOUT_40MIN from utilities.constants.virt import WIN_2K22 -from utilities.storage import create_dv, data_volume +from utilities.storage import create_dv, data_volume, get_dv_size_from_datasource @pytest.fixture() @@ -75,7 +75,7 @@ def cloned_windows_dv_multi_storage_scope_class( client=unprivileged_client, dv_name=f"dv-target-{WIN_2K22}-clone", namespace=namespace.name, - size=Images.Windows.CONTAINER_DISK_DV_SIZE, + size=get_dv_size_from_datasource(windows_validation_os_images_data_source_scope_session), storage_class=storage_class_name_scope_class, source_ref={ "kind": windows_validation_os_images_data_source_scope_session.kind, @@ -83,5 +83,5 @@ def cloned_windows_dv_multi_storage_scope_class( "namespace": windows_validation_os_images_data_source_scope_session.namespace, }, ) as cdv: - cdv.wait_for_dv_success(timeout=WINDOWS_CLONE_TIMEOUT) + cdv.wait_for_dv_success(timeout=TIMEOUT_40MIN) yield cdv diff --git a/tests/storage/cdi_clone/constants.py b/tests/storage/cdi_clone/constants.py deleted file mode 100644 index f472cf86dc..0000000000 --- a/tests/storage/cdi_clone/constants.py +++ /dev/null @@ -1,5 +0,0 @@ -""" -Constants for CDI clone tests. -""" - -WINDOWS_CLONE_TIMEOUT = 60 * 40 From 4d91562574c3e2f779976d64e7b121bf344ee6db Mon Sep 17 00:00:00 2001 From: Adam Cinko Date: Thu, 2 Jul 2026 14:59:54 +0200 Subject: [PATCH 07/16] add edge case where user provides own PVC Signed-off-by: Adam Cinko --- tests/fixtures/images/validation_os_images.py | 36 ++++++++--- tests/utils.py | 64 ------------------- 2 files changed, 26 insertions(+), 74 deletions(-) diff --git a/tests/fixtures/images/validation_os_images.py b/tests/fixtures/images/validation_os_images.py index f161320238..71d86e578e 100644 --- a/tests/fixtures/images/validation_os_images.py +++ b/tests/fixtures/images/validation_os_images.py @@ -3,6 +3,7 @@ from ocp_resources.data_source import DataSource from ocp_resources.datavolume import DataVolume from ocp_resources.namespace import Namespace +from ocp_resources.persistent_volume_claim import PersistentVolumeClaim from ocp_resources.role_binding import RoleBinding from ocp_resources.utils.constants import TIMEOUT_1MINUTE from pytest_testconfig import config as py_config @@ -57,7 +58,21 @@ def validation_os_images_role_binding(admin_client, validation_os_images_namespa @pytest.fixture(scope="session") -def windows_validation_os_images_data_volume_scope_session(validation_os_images_role_binding, conformance_tests): +def windows_validation_os_images_pvc_scope_session( + validation_os_images_role_binding, +): + win_pvc = PersistentVolumeClaim( + name=WIN_2K22, + namespace=validation_os_images_role_binding.namespace, + client=validation_os_images_role_binding.client, + ) + yield win_pvc + + +@pytest.fixture(scope="session") +def windows_validation_os_images_data_volume_scope_session( + validation_os_images_role_binding, conformance_tests, windows_validation_os_images_pvc_scope_session +): """ Fixture that imports a Windows image into the validation os images namespace. Yields existing DataVolume if it was already created @@ -72,6 +87,8 @@ def windows_validation_os_images_data_volume_scope_session(validation_os_images_ if win_dv.exists: win_dv.wait_for_dv_success(timeout=TIMEOUT_1MINUTE) yield win_dv + elif windows_validation_os_images_pvc_scope_session.exists: + yield else: assert not conformance_tests, ( f"Windows image {win_dv.name} does not exist in namespace {validation_os_images_role_binding.namespace}. Self-validation requires the Windows image to be pre-created." @@ -107,24 +124,23 @@ def windows_validation_os_images_data_volume_scope_session(validation_os_images_ @pytest.fixture(scope="session") def windows_validation_os_images_data_source_scope_session( - admin_client, - windows_validation_os_images_data_volume_scope_session, + admin_client, windows_validation_os_images_pvc_scope_session, windows_validation_os_images_data_volume_scope_session ): win_data_source = DataSource( - name=windows_validation_os_images_data_volume_scope_session.name, - namespace=windows_validation_os_images_data_volume_scope_session.namespace, + name=windows_validation_os_images_pvc_scope_session.name, + namespace=windows_validation_os_images_pvc_scope_session.namespace, client=admin_client, - source=generate_data_source_dict(dv=windows_validation_os_images_data_volume_scope_session), + source=generate_data_source_dict(dv=windows_validation_os_images_pvc_scope_session), ) if win_data_source.exists: source_pvc = win_data_source.instance.spec.source.pvc - assert source_pvc.name == windows_validation_os_images_data_volume_scope_session.pvc.name, ( + assert source_pvc.name == windows_validation_os_images_pvc_scope_session.name, ( f"DataSource {win_data_source.name} source PVC name is {source_pvc.name}, " - f"expected {windows_validation_os_images_data_volume_scope_session.pvc.name}" + f"expected {windows_validation_os_images_pvc_scope_session.name}" ) - assert source_pvc.namespace == windows_validation_os_images_data_volume_scope_session.pvc.namespace, ( + assert source_pvc.namespace == windows_validation_os_images_pvc_scope_session.namespace, ( f"DataSource {win_data_source.name} source PVC namespace is {source_pvc.namespace}, " - f"expected {windows_validation_os_images_data_volume_scope_session.pvc.namespace}" + f"expected {windows_validation_os_images_pvc_scope_session.namespace}" ) else: win_data_source.deploy() diff --git a/tests/utils.py b/tests/utils.py index 54a4a890b5..06eb55d0a4 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -53,17 +53,9 @@ TIMEOUT_10SEC, TIMEOUT_15SEC, TIMEOUT_30MIN, -<<<<<<< HEAD -) -from utilities.constants.virt import ( - DISK_SERIAL, - NODE_HUGE_PAGES_1GI_KEY, - WIN_2K22, -======= U1_LARGE, WINDOWS_2K22_PREFERENCE, Images, ->>>>>>> ecf9cc62 (Use DataSource sourceRef for Windows VM cloning with vTPM) ) from utilities.data_collector import get_data_collector_dir, write_to_file from utilities.exceptions import ResourceValueError @@ -71,11 +63,6 @@ from utilities.infra import ( ExecCommandOnPod, ) -<<<<<<< HEAD -from utilities.os_utils import get_windows_container_disk_path -from utilities.storage import construct_datavolume_source_dict -======= ->>>>>>> ecf9cc62 (Use DataSource sourceRef for Windows VM cloning with vTPM) from utilities.virt import ( VirtualMachineForTests, fedora_vm_body, @@ -721,58 +708,7 @@ def verify_rwx_default_storage(client: DynamicClient) -> None: @contextmanager -<<<<<<< HEAD -def create_windows2022_dv_from_registry( - dv_name: str, - namespace: str, - client: DynamicClient, - storage_class: str, -) -> Generator[dict]: - """ - Creates a Windows Server 2022 DataVolume from registry container disk. - - Args: - dv_name: Name for the DataVolume - namespace: Kubernetes namespace - client: Kubernetes client - storage_class: Storage class name - - Yields: - dict: DataVolume template dictionary with metadata and spec - """ - artifactory_secret = get_artifactory_secret(namespace=namespace) - artifactory_config_map = get_artifactory_config_map(namespace=namespace) - - dv = DataVolume( - name=dv_name, - namespace=namespace, - storage_class=storage_class, - source_dict=construct_datavolume_source_dict( - source="registry", - url=f"{get_test_artifact_server_url(schema='registry')}/{get_windows_container_disk_path(os_value=WIN_2K22)}", - secret_name=artifactory_secret.name, - cert_configmap_name=artifactory_config_map.name, - ), - size=Images.Windows.CONTAINER_DISK_DV_SIZE, - client=client, - api_name="storage", - ) - dv.to_dict() - - try: - yield {"metadata": dv.res["metadata"], "spec": dv.res["spec"]} - finally: - cleanup_artifactory_secret_and_config_map( - artifactory_secret=artifactory_secret, artifactory_config_map=artifactory_config_map - ) - - -@contextmanager -def create_windows2022_vm_with_vtpm_from_registry( - dv_dict: dict, -======= def create_windows2022_vm_using_existing_dv( ->>>>>>> ecf9cc62 (Use DataSource sourceRef for Windows VM cloning with vTPM) namespace: str, client: DynamicClient, vm_name: str, From 76f3de255c913671e59e4c4f83ac1da8616effe7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 7 Jul 2026 05:58:48 +0000 Subject: [PATCH 08/16] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/utils.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/utils.py b/tests/utils.py index 06eb55d0a4..721d68b887 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -63,6 +63,10 @@ from utilities.infra import ( ExecCommandOnPod, ) +<<<<<<< HEAD +======= +from utilities.storage import construct_datavolume_source_dict +>>>>>>> 336fc5e7 ([pre-commit.ci] auto fixes from pre-commit.com hooks) from utilities.virt import ( VirtualMachineForTests, fedora_vm_body, From fd9a86d78d60a948fc91b2659184c866363e7c49 Mon Sep 17 00:00:00 2001 From: Adam Cinko Date: Tue, 7 Jul 2026 10:55:03 +0200 Subject: [PATCH 09/16] use PVC instead of DV also did a cleanup, used sources only if needed and made the role binding verified it contains the correct credentials all requrests from reviewers Signed-off-by: Adam Cinko --- tests/fixtures/images/validation_os_images.py | 169 ++++++++++-------- 1 file changed, 98 insertions(+), 71 deletions(-) diff --git a/tests/fixtures/images/validation_os_images.py b/tests/fixtures/images/validation_os_images.py index 71d86e578e..7c813c6297 100644 --- a/tests/fixtures/images/validation_os_images.py +++ b/tests/fixtures/images/validation_os_images.py @@ -4,6 +4,7 @@ from ocp_resources.datavolume import DataVolume from ocp_resources.namespace import Namespace from ocp_resources.persistent_volume_claim import PersistentVolumeClaim +from ocp_resources.resource import ResourceEditor from ocp_resources.role_binding import RoleBinding from ocp_resources.utils.constants import TIMEOUT_1MINUTE from pytest_testconfig import config as py_config @@ -19,9 +20,7 @@ from utilities.constants.timeouts import TIMEOUT_10MIN, TIMEOUT_50MIN from utilities.constants.virt import WIN_2K22 from utilities.os_utils import get_windows_container_disk_path -from utilities.storage import ( - generate_data_source_dict, -) +from utilities.storage import construct_datavolume_source_dict, generate_data_source_dict @pytest.fixture(scope="session") @@ -51,32 +50,40 @@ def validation_os_images_role_binding(admin_client, validation_os_images_namespa ) if role_binding.exists: + subjects = next(iter(role_binding.instance.subjects)) + assert subjects.kind == "Group", ( + f"RoleBinding {role_binding.name} subjects kind is {subjects.kind}, expected Group" + ) + assert subjects.name == "system:authenticated", ( + f"RoleBinding {role_binding.name} subjects name is {subjects.name}, expected system:authenticated" + ) + role_ref = role_binding.instance.roleRef + assert role_ref.kind == ClusterRole.kind, ( + f"RoleBinding {role_binding.name} roleRef kind is {role_ref.kind}, expected {ClusterRole.kind}" + ) + assert role_ref.name == "view", ( + f"RoleBinding {role_binding.name} roleRef name is {role_ref.name}, expected view" + ) yield role_binding - else: - with role_binding as rb: - yield rb - + return -@pytest.fixture(scope="session") -def windows_validation_os_images_pvc_scope_session( - validation_os_images_role_binding, -): - win_pvc = PersistentVolumeClaim( - name=WIN_2K22, - namespace=validation_os_images_role_binding.namespace, - client=validation_os_images_role_binding.client, - ) - yield win_pvc + with role_binding as rb: + yield rb @pytest.fixture(scope="session") -def windows_validation_os_images_data_volume_scope_session( - validation_os_images_role_binding, conformance_tests, windows_validation_os_images_pvc_scope_session +def windows_validation_os_images_persistent_volume_claim_scope_session( + validation_os_images_role_binding, conformance_tests ): - """ - Fixture that imports a Windows image into the validation os images namespace. Yields existing DataVolume if it was already created + """Provides the PVC backing the Windows Server 2022 image in the validation-os-images namespace. - The DV is also used in self-validation and if we move the version, UI needs to follow. + Resolution order: + 1. DataVolume exists — waits for success, yields its PVC. + 2. PVC exists without a DataVolume — user-provided image, yields the PVC directly. + 3. Neither exists — imports via Artifactory (fails on conformance runs), yields the new PVC. + + Yields: + PersistentVolumeClaim: The PVC containing the Windows 2022 image. """ win_dv = DataVolume( @@ -84,70 +91,90 @@ def windows_validation_os_images_data_volume_scope_session( namespace=validation_os_images_role_binding.namespace, client=validation_os_images_role_binding.client, ) + + win_pvc = PersistentVolumeClaim( + name=WIN_2K22, + namespace=validation_os_images_role_binding.namespace, + client=validation_os_images_role_binding.client, + ) + if win_dv.exists: win_dv.wait_for_dv_success(timeout=TIMEOUT_1MINUTE) - yield win_dv - elif windows_validation_os_images_pvc_scope_session.exists: - yield - else: - assert not conformance_tests, ( - f"Windows image {win_dv.name} does not exist in namespace {validation_os_images_role_binding.namespace}. Self-validation requires the Windows image to be pre-created." - ) + yield win_dv.pvc + return - artifactory_secret = get_artifactory_secret( - namespace=validation_os_images_role_binding.namespace, client=validation_os_images_role_binding.client - ) - artifactory_config_map = get_artifactory_config_map( - namespace=validation_os_images_role_binding.namespace, client=validation_os_images_role_binding.client - ) + if win_pvc.exists: + yield win_pvc + return - with DataVolume( - name=win_dv.name, - namespace=win_dv.namespace, - client=win_dv.client, - storage_class=py_config["default_storage_class"], - source=REGISTRY_STR, - url=f"{get_test_artifact_server_url(schema=REGISTRY_STR)}/{get_windows_container_disk_path(os_value=WIN_2K22)}", - size=Images.Windows.CONTAINER_DISK_DV_SIZE, - api_name="storage", - secret=artifactory_secret, - cert_configmap=artifactory_config_map.name, - annotations=BIND_IMMEDIATE_ANNOTATION, - ) as wdv: - wdv.wait_for_dv_success(timeout=TIMEOUT_50MIN) - yield wdv - cleanup_artifactory_secret_and_config_map( - artifactory_secret=artifactory_secret, - artifactory_config_map=artifactory_config_map, - ) + assert not conformance_tests, ( + f"Windows image {win_dv.name} does not exist in namespace {validation_os_images_role_binding.namespace}. Self-validation requires the Windows image to be pre-created." + ) + + artifactory_secret = get_artifactory_secret( + namespace=validation_os_images_role_binding.namespace, client=validation_os_images_role_binding.client + ) + artifactory_config_map = get_artifactory_config_map( + namespace=validation_os_images_role_binding.namespace, client=validation_os_images_role_binding.client + ) + + win_dv.storage_class = py_config["default_storage_class"] + win_dv.source_dict = construct_datavolume_source_dict( + source=REGISTRY_STR, + url=f"{get_test_artifact_server_url(schema=REGISTRY_STR)}/{get_windows_container_disk_path(os_value=WIN_2K22)}", + secret_name=artifactory_secret.name, + cert_configmap_name=artifactory_config_map.name, + ) + win_dv.size = Images.Windows.CONTAINER_DISK_DV_SIZE + win_dv.api_name = "storage" + win_dv.annotations = BIND_IMMEDIATE_ANNOTATION + + with win_dv as wdv: + wdv.wait_for_dv_success(timeout=TIMEOUT_50MIN) + yield wdv.pvc + cleanup_artifactory_secret_and_config_map( + artifactory_secret=artifactory_secret, + artifactory_config_map=artifactory_config_map, + ) @pytest.fixture(scope="session") def windows_validation_os_images_data_source_scope_session( - admin_client, windows_validation_os_images_pvc_scope_session, windows_validation_os_images_data_volume_scope_session + admin_client, windows_validation_os_images_persistent_volume_claim_scope_session ): win_data_source = DataSource( - name=windows_validation_os_images_pvc_scope_session.name, - namespace=windows_validation_os_images_pvc_scope_session.namespace, + name=windows_validation_os_images_persistent_volume_claim_scope_session.name, + namespace=windows_validation_os_images_persistent_volume_claim_scope_session.namespace, client=admin_client, - source=generate_data_source_dict(dv=windows_validation_os_images_pvc_scope_session), ) if win_data_source.exists: source_pvc = win_data_source.instance.spec.source.pvc - assert source_pvc.name == windows_validation_os_images_pvc_scope_session.name, ( + assert source_pvc.name == windows_validation_os_images_persistent_volume_claim_scope_session.name, ( f"DataSource {win_data_source.name} source PVC name is {source_pvc.name}, " - f"expected {windows_validation_os_images_pvc_scope_session.name}" + f"expected {windows_validation_os_images_persistent_volume_claim_scope_session.name}" ) - assert source_pvc.namespace == windows_validation_os_images_pvc_scope_session.namespace, ( + assert source_pvc.namespace == windows_validation_os_images_persistent_volume_claim_scope_session.namespace, ( f"DataSource {win_data_source.name} source PVC namespace is {source_pvc.namespace}, " - f"expected {windows_validation_os_images_pvc_scope_session.namespace}" + f"expected {windows_validation_os_images_persistent_volume_claim_scope_session.namespace}" ) - else: - win_data_source.deploy() - - win_data_source.wait_for_condition( - condition=win_data_source.Condition.READY, - status=win_data_source.Condition.Status.TRUE, - timeout=TIMEOUT_10MIN, - ) - yield win_data_source + yield win_data_source + return + + with win_data_source as wds: + ResourceEditor( + patches={ + wds: { + "spec": { + "source": generate_data_source_dict( + dv=windows_validation_os_images_persistent_volume_claim_scope_session + ) + } + } + } + ).update() + wds.wait_for_condition( + condition=wds.Condition.READY, + status=wds.Condition.Status.TRUE, + timeout=TIMEOUT_10MIN, + ) + yield wds From 860367b5a9e2617db9d0d834fd1140a3cf6ae805 Mon Sep 17 00:00:00 2001 From: Adam Cinko Date: Tue, 7 Jul 2026 16:20:27 +0200 Subject: [PATCH 10/16] use new DataSource object instead Signed-off-by: Adam Cinko --- tests/fixtures/images/validation_os_images.py | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/tests/fixtures/images/validation_os_images.py b/tests/fixtures/images/validation_os_images.py index 7c813c6297..30ee504259 100644 --- a/tests/fixtures/images/validation_os_images.py +++ b/tests/fixtures/images/validation_os_images.py @@ -160,18 +160,12 @@ def windows_validation_os_images_data_source_scope_session( yield win_data_source return - with win_data_source as wds: - ResourceEditor( - patches={ - wds: { - "spec": { - "source": generate_data_source_dict( - dv=windows_validation_os_images_persistent_volume_claim_scope_session - ) - } - } - } - ).update() + with DataSource( + name=windows_validation_os_images_persistent_volume_claim_scope_session.name, + namespace=windows_validation_os_images_persistent_volume_claim_scope_session.namespace, + client=admin_client, + source=generate_data_source_dict(dv=windows_validation_os_images_persistent_volume_claim_scope_session), + ) as wds: wds.wait_for_condition( condition=wds.Condition.READY, status=wds.Condition.Status.TRUE, From 8bd596453361c7e71bf06b04968a7d36e6851552 Mon Sep 17 00:00:00 2001 From: Adam Cinko Date: Wed, 8 Jul 2026 09:51:30 +0200 Subject: [PATCH 11/16] update the `DataSource` object's source directly Signed-off-by: Adam Cinko --- tests/fixtures/images/validation_os_images.py | 11 +-- tests/storage/cdi_clone/test_clone.py | 87 ------------------- tests/utils.py | 7 +- 3 files changed, 5 insertions(+), 100 deletions(-) diff --git a/tests/fixtures/images/validation_os_images.py b/tests/fixtures/images/validation_os_images.py index 30ee504259..eb14fbc6b3 100644 --- a/tests/fixtures/images/validation_os_images.py +++ b/tests/fixtures/images/validation_os_images.py @@ -4,7 +4,6 @@ from ocp_resources.datavolume import DataVolume from ocp_resources.namespace import Namespace from ocp_resources.persistent_volume_claim import PersistentVolumeClaim -from ocp_resources.resource import ResourceEditor from ocp_resources.role_binding import RoleBinding from ocp_resources.utils.constants import TIMEOUT_1MINUTE from pytest_testconfig import config as py_config @@ -160,12 +159,10 @@ def windows_validation_os_images_data_source_scope_session( yield win_data_source return - with DataSource( - name=windows_validation_os_images_persistent_volume_claim_scope_session.name, - namespace=windows_validation_os_images_persistent_volume_claim_scope_session.namespace, - client=admin_client, - source=generate_data_source_dict(dv=windows_validation_os_images_persistent_volume_claim_scope_session), - ) as wds: + win_data_source.source = generate_data_source_dict( + dv=windows_validation_os_images_persistent_volume_claim_scope_session + ) + with win_data_source as wds: wds.wait_for_condition( condition=wds.Condition.READY, status=wds.Condition.Status.TRUE, diff --git a/tests/storage/cdi_clone/test_clone.py b/tests/storage/cdi_clone/test_clone.py index ede98e9a53..e56ddfb948 100644 --- a/tests/storage/cdi_clone/test_clone.py +++ b/tests/storage/cdi_clone/test_clone.py @@ -60,42 +60,6 @@ def create_vm_from_clone_dv_template( running_vm(vm=vm) -<<<<<<< HEAD -@pytest.mark.tier3 -@pytest.mark.parametrize( - "data_volume_multi_storage_scope_function", - [ - pytest.param( - { - "dv_name": "dv-source", - "image": f"{Images.Windows.DIR}/{Images.Windows.WIN11_IMG}", - "dv_size": Images.Windows.DEFAULT_DV_SIZE, - }, - marks=(pytest.mark.polarion("CNV-1892")), - ), - ], - indirect=True, -) -@pytest.mark.s390x -def test_successful_clone_of_large_image( - namespace, - data_volume_multi_storage_scope_function, -): - with create_dv( - source="pvc", - dv_name="dv-target", - namespace=namespace.name, - size=data_volume_multi_storage_scope_function.size, - source_pvc_name=data_volume_multi_storage_scope_function.name, - source_pvc_namespace=data_volume_multi_storage_scope_function.namespace, - storage_class=data_volume_multi_storage_scope_function.storage_class, - client=namespace.client, - ) as cdv: - cdv.wait_for_dv_success(timeout=WINDOWS_CLONE_TIMEOUT) - - -======= ->>>>>>> ecf9cc62 (Use DataSource sourceRef for Windows VM cloning with vTPM) @pytest.mark.sno @pytest.mark.polarion("CNV-2148") @pytest.mark.gating() @@ -144,51 +108,6 @@ def test_successful_vm_restart_with_cloned_dv( @pytest.mark.tier3 -<<<<<<< HEAD -@pytest.mark.parametrize( - ("data_volume_multi_storage_scope_function", "vm_params"), - [ - pytest.param( - { - "dv_name": "dv-source", - "source": "http", - "image": f"{Images.Windows.DIR}/{Images.Windows.WIN11_IMG}", - "dv_size": Images.Windows.DEFAULT_DV_SIZE, - }, - { - "vm_name": f"vm-win-{WINDOWS_11.get('os_version')}", - "template_labels": WINDOWS_11_TEMPLATE_LABELS, - "os_version": WINDOWS_11.get("os_version"), - "ssh": True, - }, - marks=pytest.mark.polarion("CNV-3638"), - ), - ], - indirect=["data_volume_multi_storage_scope_function"], -) -def test_successful_vm_from_cloned_dv_windows( - unprivileged_client, - data_volume_multi_storage_scope_function, - vm_params, - namespace, -): - with create_dv( - client=unprivileged_client, - source="pvc", - dv_name="dv-target", - namespace=data_volume_multi_storage_scope_function.namespace, - size=data_volume_multi_storage_scope_function.size, - source_pvc_name=data_volume_multi_storage_scope_function.name, - source_pvc_namespace=data_volume_multi_storage_scope_function.namespace, - storage_class=data_volume_multi_storage_scope_function.storage_class, - ) as cdv: - cdv.wait_for_dv_success(timeout=WINDOWS_CLONE_TIMEOUT) - create_windows_vm_validate_guest_agent_info( - dv=cdv, - namespace=namespace, - unprivileged_client=unprivileged_client, - vm_params=vm_params, -======= @pytest.mark.incremental class TestWindowsClonedDv: """ @@ -215,7 +134,6 @@ def test_clone_dv_windows(self, cloned_windows_dv_multi_storage_scope_class): """ assert cloned_windows_dv_multi_storage_scope_class.status == DataVolume.Status.SUCCEEDED, ( f"Cloned DV status is {cloned_windows_dv_multi_storage_scope_class.status}, expected {DataVolume.Status.SUCCEEDED}" ->>>>>>> ecf9cc62 (Use DataSource sourceRef for Windows VM cloning with vTPM) ) @pytest.mark.polarion("CNV-3638") @@ -263,13 +181,8 @@ def test_vm_from_cloned_dv_windows( ), pytest.param( { -<<<<<<< HEAD - "dv_name": f"dv-source-{OS_FLAVOR_WINDOWS}", - "image": f"{Images.Windows.DIR}/{Images.Windows.WIN11_IMG}", -======= "dv_name": "dv-source-win", "image": f"{Images.Windows.DIR}/{Images.Windows.WIN2022_IMG}", ->>>>>>> ecf9cc62 (Use DataSource sourceRef for Windows VM cloning with vTPM) "dv_size": Images.Windows.DEFAULT_DV_SIZE, }, marks=(pytest.mark.polarion("CNV-3552"), pytest.mark.tier3()), diff --git a/tests/utils.py b/tests/utils.py index 721d68b887..b5f2d24947 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -53,20 +53,15 @@ TIMEOUT_10SEC, TIMEOUT_15SEC, TIMEOUT_30MIN, - U1_LARGE, - WINDOWS_2K22_PREFERENCE, - Images, ) +from utilities.constants.virt import DISK_SERIAL, NODE_HUGE_PAGES_1GI_KEY from utilities.data_collector import get_data_collector_dir, write_to_file from utilities.exceptions import ResourceValueError from utilities.hco import ResourceEditorValidateHCOReconcile from utilities.infra import ( ExecCommandOnPod, ) -<<<<<<< HEAD -======= from utilities.storage import construct_datavolume_source_dict ->>>>>>> 336fc5e7 ([pre-commit.ci] auto fixes from pre-commit.com hooks) from utilities.virt import ( VirtualMachineForTests, fedora_vm_body, From e607c0182e26b9e3318fb52ab06981085ca2c3ad Mon Sep 17 00:00:00 2001 From: Adam Cinko Date: Wed, 8 Jul 2026 10:17:27 +0200 Subject: [PATCH 12/16] access the private value directly Signed-off-by: Adam Cinko --- tests/fixtures/images/validation_os_images.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/fixtures/images/validation_os_images.py b/tests/fixtures/images/validation_os_images.py index eb14fbc6b3..728cb6dfa6 100644 --- a/tests/fixtures/images/validation_os_images.py +++ b/tests/fixtures/images/validation_os_images.py @@ -159,7 +159,7 @@ def windows_validation_os_images_data_source_scope_session( yield win_data_source return - win_data_source.source = generate_data_source_dict( + win_data_source._source = generate_data_source_dict( dv=windows_validation_os_images_persistent_volume_claim_scope_session ) with win_data_source as wds: From a6da977f304492d993b7895ead06c15c75d52ace Mon Sep 17 00:00:00 2001 From: Adam Cinko Date: Fri, 10 Jul 2026 09:22:06 +0200 Subject: [PATCH 13/16] remove PVC logic, keep the DV fixture only since the DV will always exist Signed-off-by: Adam Cinko --- tests/fixtures/images/validation_os_images.py | 50 ++++++++----------- 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/tests/fixtures/images/validation_os_images.py b/tests/fixtures/images/validation_os_images.py index 728cb6dfa6..a7648d72d7 100644 --- a/tests/fixtures/images/validation_os_images.py +++ b/tests/fixtures/images/validation_os_images.py @@ -3,7 +3,6 @@ from ocp_resources.data_source import DataSource from ocp_resources.datavolume import DataVolume from ocp_resources.namespace import Namespace -from ocp_resources.persistent_volume_claim import PersistentVolumeClaim from ocp_resources.role_binding import RoleBinding from ocp_resources.utils.constants import TIMEOUT_1MINUTE from pytest_testconfig import config as py_config @@ -69,20 +68,19 @@ def validation_os_images_role_binding(admin_client, validation_os_images_namespa with role_binding as rb: yield rb - @pytest.fixture(scope="session") -def windows_validation_os_images_persistent_volume_claim_scope_session( - validation_os_images_role_binding, conformance_tests +def windows_validation_os_images_data_volume_scope_session( + validation_os_images_role_binding, + conformance_tests, ): - """Provides the PVC backing the Windows Server 2022 image in the validation-os-images namespace. + """Provides the DV backing the Windows Server 2022 image in the validation-os-images namespace. Resolution order: - 1. DataVolume exists — waits for success, yields its PVC. - 2. PVC exists without a DataVolume — user-provided image, yields the PVC directly. - 3. Neither exists — imports via Artifactory (fails on conformance runs), yields the new PVC. + 1. DataVolume exists — waits for success, yields it. + 2. DataVolume does not exist — imports via Artifactory (fails on conformance runs), yields the new DataVolume. Yields: - PersistentVolumeClaim: The PVC containing the Windows 2022 image. + DataVolume: The DV containing the Windows 2022 image. """ win_dv = DataVolume( @@ -91,23 +89,14 @@ def windows_validation_os_images_persistent_volume_claim_scope_session( client=validation_os_images_role_binding.client, ) - win_pvc = PersistentVolumeClaim( - name=WIN_2K22, - namespace=validation_os_images_role_binding.namespace, - client=validation_os_images_role_binding.client, - ) - if win_dv.exists: win_dv.wait_for_dv_success(timeout=TIMEOUT_1MINUTE) - yield win_dv.pvc - return - - if win_pvc.exists: - yield win_pvc + yield win_dv return assert not conformance_tests, ( - f"Windows image {win_dv.name} does not exist in namespace {validation_os_images_role_binding.namespace}. Self-validation requires the Windows image to be pre-created." + f"Windows image {win_dv.name} does not exist in namespace {validation_os_images_role_binding.namespace}." + " Self-validation requires the Windows image to be pre-created." ) artifactory_secret = get_artifactory_secret( @@ -130,7 +119,7 @@ def windows_validation_os_images_persistent_volume_claim_scope_session( with win_dv as wdv: wdv.wait_for_dv_success(timeout=TIMEOUT_50MIN) - yield wdv.pvc + yield wdv cleanup_artifactory_secret_and_config_map( artifactory_secret=artifactory_secret, artifactory_config_map=artifactory_config_map, @@ -139,28 +128,29 @@ def windows_validation_os_images_persistent_volume_claim_scope_session( @pytest.fixture(scope="session") def windows_validation_os_images_data_source_scope_session( - admin_client, windows_validation_os_images_persistent_volume_claim_scope_session + admin_client, windows_validation_os_images_data_volume_scope_session ): win_data_source = DataSource( - name=windows_validation_os_images_persistent_volume_claim_scope_session.name, - namespace=windows_validation_os_images_persistent_volume_claim_scope_session.namespace, + name=windows_validation_os_images_data_volume_scope_session.name, + namespace=windows_validation_os_images_data_volume_scope_session.namespace, client=admin_client, ) if win_data_source.exists: source_pvc = win_data_source.instance.spec.source.pvc - assert source_pvc.name == windows_validation_os_images_persistent_volume_claim_scope_session.name, ( + assert source_pvc.name == windows_validation_os_images_data_volume_scope_session.name, ( f"DataSource {win_data_source.name} source PVC name is {source_pvc.name}, " - f"expected {windows_validation_os_images_persistent_volume_claim_scope_session.name}" + f"expected {windows_validation_os_images_data_volume_scope_session.name}" ) - assert source_pvc.namespace == windows_validation_os_images_persistent_volume_claim_scope_session.namespace, ( + assert source_pvc.namespace == windows_validation_os_images_data_volume_scope_session.pvc.namespace, ( f"DataSource {win_data_source.name} source PVC namespace is {source_pvc.namespace}, " - f"expected {windows_validation_os_images_persistent_volume_claim_scope_session.namespace}" + f"expected {windows_validation_os_images_data_volume_scope_session.namespace}" ) yield win_data_source return + win_data_source._source = generate_data_source_dict( - dv=windows_validation_os_images_persistent_volume_claim_scope_session + dv=windows_validation_os_images_data_volume_scope_session ) with win_data_source as wds: wds.wait_for_condition( From edd932522fa45c835304388effb87577e6cd5882 Mon Sep 17 00:00:00 2001 From: Adam Cinko Date: Mon, 13 Jul 2026 07:43:41 +0200 Subject: [PATCH 14/16] reverting change for `test_successful_snapshot_clone` in `test_clone.py` Signed-off-by: Adam Cinko --- tests/storage/cdi_clone/test_clone.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/storage/cdi_clone/test_clone.py b/tests/storage/cdi_clone/test_clone.py index e56ddfb948..64c01d734a 100644 --- a/tests/storage/cdi_clone/test_clone.py +++ b/tests/storage/cdi_clone/test_clone.py @@ -181,8 +181,8 @@ def test_vm_from_cloned_dv_windows( ), pytest.param( { - "dv_name": "dv-source-win", - "image": f"{Images.Windows.DIR}/{Images.Windows.WIN2022_IMG}", + "dv_name": f"dv-source-{OS_FLAVOR_WINDOWS}", + "image": f"{Images.Windows.DIR}/{Images.Windows.WIN11_IMG}", "dv_size": Images.Windows.DEFAULT_DV_SIZE, }, marks=(pytest.mark.polarion("CNV-3552"), pytest.mark.tier3()), From 2a2f44f68abc30c1b7400b3923ac8564a520c3ae Mon Sep 17 00:00:00 2001 From: Adam Cinko Date: Mon, 13 Jul 2026 09:40:23 +0200 Subject: [PATCH 15/16] reformat Signed-off-by: Adam Cinko --- tests/fixtures/images/validation_os_images.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/fixtures/images/validation_os_images.py b/tests/fixtures/images/validation_os_images.py index a7648d72d7..f2f93d719f 100644 --- a/tests/fixtures/images/validation_os_images.py +++ b/tests/fixtures/images/validation_os_images.py @@ -68,6 +68,7 @@ def validation_os_images_role_binding(admin_client, validation_os_images_namespa with role_binding as rb: yield rb + @pytest.fixture(scope="session") def windows_validation_os_images_data_volume_scope_session( validation_os_images_role_binding, @@ -148,10 +149,7 @@ def windows_validation_os_images_data_source_scope_session( yield win_data_source return - - win_data_source._source = generate_data_source_dict( - dv=windows_validation_os_images_data_volume_scope_session - ) + win_data_source._source = generate_data_source_dict(dv=windows_validation_os_images_data_volume_scope_session) with win_data_source as wds: wds.wait_for_condition( condition=wds.Condition.READY, From 44641c12438f09712458487af7969e36fe5d18e1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 13 Jul 2026 14:46:09 +0000 Subject: [PATCH 16/16] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/storage/test_hotplug.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/storage/test_hotplug.py b/tests/storage/test_hotplug.py index 871076b9f6..42465e1870 100644 --- a/tests/storage/test_hotplug.py +++ b/tests/storage/test_hotplug.py @@ -15,7 +15,6 @@ from tests.storage.utils import assert_disk_bus from tests.utils import create_windows2022_vm_with_data_volume_template -from utilities.constants import Images from utilities.constants.storage import HOTPLUG_DISK_SCSI_BUS, HOTPLUG_DISK_SERIAL, HOTPLUG_DISK_VIRTIO_BUS from utilities.constants.virt import WIN_2K22 from utilities.hco import ResourceEditorValidateHCOReconcile