diff --git a/conftest.py b/conftest.py index c80c6ce111..62b8a08a25 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", "tests.fixtures.network.multiarch", ] 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..f2f93d719f --- /dev/null +++ b/tests/fixtures/images/validation_os_images.py @@ -0,0 +1,159 @@ +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 ocp_resources.utils.constants import TIMEOUT_1MINUTE +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 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 construct_datavolume_source_dict, generate_data_source_dict + + +@pytest.fixture(scope="session") +def validation_os_images_namespace(admin_client): + validation_os_images_namespace = Namespace( + name="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: + 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 + return + + 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, +): + """Provides the DV backing the Windows Server 2022 image in the validation-os-images namespace. + + Resolution order: + 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: + DataVolume: The DV containing the Windows 2022 image. + """ + + win_dv = 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 + 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." + ) + + 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 + 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_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, + ) + 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.name, ( + f"DataSource {win_data_source.name} source PVC name is {source_pvc.name}, " + f"expected {windows_validation_os_images_data_volume_scope_session.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.namespace}" + ) + yield win_data_source + return + + 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, + status=wds.Condition.Status.TRUE, + timeout=TIMEOUT_10MIN, + ) + yield wds diff --git a/tests/storage/cdi_clone/conftest.py b/tests/storage/cdi_clone/conftest.py index 56e3c02790..1a8db95d28 100644 --- a/tests/storage/cdi_clone/conftest.py +++ b/tests/storage/cdi_clone/conftest.py @@ -4,7 +4,9 @@ from tests.storage.constants import QUAY_FEDORA_CONTAINER_IMAGE from utilities.constants import Images from utilities.constants.storage import REGISTRY_STR -from utilities.storage import create_dv, data_volume +from utilities.constants.timeouts import TIMEOUT_40MIN +from utilities.constants.virt import WIN_2K22 +from utilities.storage import create_dv, data_volume, get_dv_size_from_datasource @pytest.fixture() @@ -60,3 +62,26 @@ 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, +): + with create_dv( + client=unprivileged_client, + dv_name=f"dv-target-{WIN_2K22}-clone", + namespace=namespace.name, + 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, + "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=TIMEOUT_40MIN) + yield cdv diff --git a/tests/storage/cdi_clone/test_clone.py b/tests/storage/cdi_clone/test_clone.py index 3904e2b136..b2e9aa9f54 100644 --- a/tests/storage/cdi_clone/test_clone.py +++ b/tests/storage/cdi_clone/test_clone.py @@ -5,15 +5,17 @@ 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 tests.utils import create_windows2022_vm_using_existing_dv from utilities.constants import 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.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, create_dv, @@ -29,8 +31,6 @@ running_vm, ) -WINDOWS_CLONE_TIMEOUT = TIMEOUT_40MIN - def create_vm_from_clone_dv_template( vm_name, @@ -60,39 +60,6 @@ def create_vm_from_clone_dv_template( running_vm(vm=vm) -@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) - - @pytest.mark.sno @pytest.mark.polarion("CNV-2148") @pytest.mark.gating() @@ -141,51 +108,65 @@ def test_successful_vm_restart_with_cloned_dv( @pytest.mark.tier3 -@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: + """ + 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}" ) + @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", 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 0ebc4279e2..42465e1870 100644 --- a/tests/storage/test_hotplug.py +++ b/tests/storage/test_hotplug.py @@ -14,13 +14,15 @@ 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 tests.utils import create_windows2022_vm_with_data_volume_template 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.storage import ( assert_disk_serial, assert_hotplugvolume_nonexist, create_dv, + data_volume_template_with_source_ref_dict, virtctl_volume, wait_for_vm_volume_ready, ) @@ -62,12 +64,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: @@ -77,34 +79,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 @@ -269,17 +259,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"]) @@ -287,11 +277,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..b5f2d24947 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 @@ -56,18 +54,13 @@ TIMEOUT_15SEC, TIMEOUT_30MIN, ) -from utilities.constants.virt import ( - DISK_SERIAL, - NODE_HUGE_PAGES_1GI_KEY, - WIN_2K22, -) +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, ) -from utilities.os_utils import get_windows_container_disk_path from utilities.storage import construct_datavolume_source_dict from utilities.virt import ( VirtualMachineForTests, @@ -714,64 +707,55 @@ def verify_rwx_default_storage(client: DynamicClient) -> None: @contextmanager -def create_windows2022_dv_from_registry( - dv_name: str, +def create_windows2022_vm_using_existing_dv( namespace: str, client: DynamicClient, - storage_class: str, -) -> Generator[dict]: + vm_name: str, + cpu_model: str | None = None, + existing_data_volume: DataVolume | None = None, +) -> Generator[VirtualMachineForTests]: """ - Creates a Windows Server 2022 DataVolume from registry container disk. + Creates a Windows Server 2022 VM with vTPM using existing DataVolume. Args: - dv_name: Name for the DataVolume + existing_data_volume: DataVolume to use for the VM's data volume namespace: Kubernetes namespace client: Kubernetes client - storage_class: Storage class name + vm_name: Name for the VirtualMachine + cpu_model: CPU model specification (can be None) Yields: - dict: DataVolume template dictionary with metadata and spec + VirtualMachineForTests: Running Windows 2022 VM with vTPM """ - artifactory_secret = get_artifactory_secret(namespace=namespace) - artifactory_config_map = get_artifactory_config_map(namespace=namespace) - dv = DataVolume( - name=dv_name, + with VirtualMachineForTests( + name=vm_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 - ) + 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_vtpm_from_registry( - dv_dict: dict, +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 +764,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 +772,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)