Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
]

Expand Down
Empty file.
159 changes: 159 additions & 0 deletions tests/fixtures/images/validation_os_images.py
Comment thread
acinko-rh marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -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
Comment thread
acinko-rh marked this conversation as resolved.
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
Comment thread
acinko-rh marked this conversation as resolved.

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}"
)
Comment thread
acinko-rh marked this conversation as resolved.
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
27 changes: 26 additions & 1 deletion tests/storage/cdi_clone/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
from tests.storage.constants import QUAY_FEDORA_CONTAINER_IMAGE
Comment thread
acinko-rh marked this conversation as resolved.
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()
Expand Down Expand Up @@ -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
143 changes: 62 additions & 81 deletions tests/storage/cdi_clone/test_clone.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -29,8 +31,6 @@
running_vm,
)

WINDOWS_CLONE_TIMEOUT = TIMEOUT_40MIN


def create_vm_from_clone_dv_template(
vm_name,
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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",
Expand Down
6 changes: 5 additions & 1 deletion tests/storage/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__)
Expand Down
Loading