From a48840c8a759fc5d7d8dbe50617d1d57433e0502 Mon Sep 17 00:00:00 2001 From: Geetika Kapoor Date: Mon, 13 Jul 2026 18:31:54 +0100 Subject: [PATCH] Add multiarch support for golden image boot source tests - Populate per-arch data_import_cron_matrix and auto_update_data_source_matrix in multiarch config. - Make boot source fixtures, template label selectors and DIC filtering arch-aware. - Add arm64 marker to applicable tests. Update unit tests for matrix propagation. Signed-off-by: Geetika Kapoor --- tests/global_config_arm64.py | 2 - tests/global_config_multiarch.py | 29 +++++++++++++ .../test_boot_sources_vm.py | 1 + .../test_ssp_common_templates_boot_sources.py | 41 ++++++++++++++----- .../test_ssp_data_import_crons.py | 19 +++++++-- .../golden_images/update_boot_source/utils.py | 3 +- utilities/pytest_utils.py | 2 + utilities/unittests/test_pytest_utils.py | 20 ++++++++- utilities/virt.py | 5 ++- 9 files changed, 101 insertions(+), 21 deletions(-) diff --git a/tests/global_config_arm64.py b/tests/global_config_arm64.py index 26c790fa0b..d43a7621bf 100644 --- a/tests/global_config_arm64.py +++ b/tests/global_config_arm64.py @@ -2,7 +2,6 @@ from ocp_resources.datavolume import DataVolume -from utilities.constants import Images from utilities.constants.architecture import ARM_64 from utilities.constants.images import OS_FLAVOR_FEDORA from utilities.constants.instance_types import ( @@ -19,7 +18,6 @@ global config -Images.Cirros.RAW_IMG_XZ = "cirros-0.4.0-aarch64-disk.raw.xz" EXPECTED_CLUSTER_INSTANCE_TYPE_LABELS[PREFERENCE_STR] = f"rhel.9.{ARM_64}" diff --git a/tests/global_config_multiarch.py b/tests/global_config_multiarch.py index 287ba9965f..a8e25ad699 100644 --- a/tests/global_config_multiarch.py +++ b/tests/global_config_multiarch.py @@ -13,6 +13,7 @@ RHEL8_PREFERENCE, RHEL9_PREFERENCE, RHEL10_PREFERENCE, + U1_MEDIUM_STR, ) from utilities.constants.storage import StorageClassNames @@ -53,6 +54,20 @@ "instance_type_rhel_os_list": [RHEL8_PREFERENCE, RHEL9_PREFERENCE, RHEL10_PREFERENCE], "instance_type_fedora_os_list": [OS_FLAVOR_FEDORA], "instance_type_centos_os_list": [CENTOS_STREAM9_PREFERENCE, CENTOS_STREAM10_PREFERENCE], + "data_import_cron_matrix": [ + {"centos-stream9-amd64": {"instance_type": U1_MEDIUM_STR, "preference": CENTOS_STREAM9_PREFERENCE}}, + {"centos-stream10-amd64": {"instance_type": U1_MEDIUM_STR, "preference": CENTOS_STREAM10_PREFERENCE}}, + {"fedora-amd64": {"instance_type": U1_MEDIUM_STR, "preference": OS_FLAVOR_FEDORA}}, + {"rhel8-amd64": {"instance_type": U1_MEDIUM_STR, "preference": RHEL8_PREFERENCE}}, + {"rhel9-amd64": {"instance_type": U1_MEDIUM_STR, "preference": RHEL9_PREFERENCE}}, + {"rhel10-amd64": {"instance_type": U1_MEDIUM_STR, "preference": RHEL10_PREFERENCE}}, + ], + "auto_update_data_source_matrix": [ + {"centos-stream9-amd64": {"template_os": "centos-stream9"}}, + {"fedora-amd64": {"template_os": "fedora"}}, + {"rhel8-amd64": {"template_os": "rhel8.4"}}, + {"rhel9-amd64": {"template_os": "rhel9.0"}}, + ], }, ARM_64: { "rhel_os_list": ["rhel-9-6"], @@ -61,6 +76,20 @@ "instance_type_rhel_os_list": [RHEL10_PREFERENCE], "instance_type_fedora_os_list": [OS_FLAVOR_FEDORA], "instance_type_centos_os_list": [CENTOS_STREAM10_PREFERENCE], + # centos and rhel8 have no arm64-specific preferences, while fedora, rhel9 and rhel10 do. + "data_import_cron_matrix": [ + {"centos-stream9-arm64": {"instance_type": U1_MEDIUM_STR, "preference": CENTOS_STREAM9_PREFERENCE}}, + {"centos-stream10-arm64": {"instance_type": U1_MEDIUM_STR, "preference": CENTOS_STREAM10_PREFERENCE}}, + {"fedora-arm64": {"instance_type": U1_MEDIUM_STR, "preference": f"{OS_FLAVOR_FEDORA}.{ARM_64}"}}, + {"rhel8-arm64": {"instance_type": U1_MEDIUM_STR, "preference": RHEL8_PREFERENCE}}, + {"rhel9-arm64": {"instance_type": U1_MEDIUM_STR, "preference": f"{RHEL9_PREFERENCE}.{ARM_64}"}}, + {"rhel10-arm64": {"instance_type": U1_MEDIUM_STR, "preference": f"{RHEL10_PREFERENCE}.{ARM_64}"}}, + ], + "auto_update_data_source_matrix": [ + {"centos-stream9-arm64": {"template_os": "centos-stream9"}}, + {"fedora-arm64": {"template_os": "fedora"}}, + {"rhel9-arm64": {"template_os": "rhel9.0"}}, + ], }, } diff --git a/tests/infrastructure/golden_images/update_boot_source/test_boot_sources_vm.py b/tests/infrastructure/golden_images/update_boot_source/test_boot_sources_vm.py index d95840b9d9..ea62bce577 100644 --- a/tests/infrastructure/golden_images/update_boot_source/test_boot_sources_vm.py +++ b/tests/infrastructure/golden_images/update_boot_source/test_boot_sources_vm.py @@ -60,6 +60,7 @@ def auto_update_boot_source_instance_type_vm( yield vm +@pytest.mark.arm64 @pytest.mark.polarion("CNV-11774") def test_instance_type_vm_from_auto_update_boot_source( auto_update_boot_source_instance_type_vm, diff --git a/tests/infrastructure/golden_images/update_boot_source/test_ssp_common_templates_boot_sources.py b/tests/infrastructure/golden_images/update_boot_source/test_ssp_common_templates_boot_sources.py index 1b23f867a4..a3c59db818 100644 --- a/tests/infrastructure/golden_images/update_boot_source/test_ssp_common_templates_boot_sources.py +++ b/tests/infrastructure/golden_images/update_boot_source/test_ssp_common_templates_boot_sources.py @@ -12,9 +12,10 @@ assert_os_version_mismatch_in_vm, ) from utilities.constants import Images +from utilities.constants.architecture import MULTIARCH from utilities.constants.images import ( - DEFAULT_FEDORA_REGISTRY_URL, OS_FLAVOR_FEDORA, + ArchImages, ) from utilities.constants.storage import BIND_IMMEDIATE_ANNOTATION from utilities.constants.timeouts import ( @@ -84,13 +85,28 @@ def auto_update_boot_source_vm( @pytest.fixture() -def vm_without_boot_source(unprivileged_client, namespace, fedora_data_source): +def fedora_boot_source_data_source(unprivileged_client, golden_images_namespace): + data_source_name = ( + f"{OS_FLAVOR_FEDORA}-{py_config['cpu_arch']}" + if py_config.get("cluster_type") == MULTIARCH + else OS_FLAVOR_FEDORA + ) + return DataSource( + client=unprivileged_client, + name=data_source_name, + namespace=golden_images_namespace.name, + ensure_exists=True, + ) + + +@pytest.fixture() +def vm_without_boot_source(unprivileged_client, namespace, fedora_boot_source_data_source): with VirtualMachineForTestsFromTemplate( - name=f"{fedora_data_source.name}-vm", + name=f"{fedora_boot_source_data_source.name}-vm", namespace=namespace.name, client=unprivileged_client, labels=template_labels(os=OS_FLAVOR_FEDORA), - data_source=fedora_data_source, + data_source=fedora_boot_source_data_source, non_existing_pvc=True, ) as vm: vm.start() @@ -99,29 +115,30 @@ def vm_without_boot_source(unprivileged_client, namespace, fedora_data_source): @pytest.fixture() -def opted_out_fedora_data_source(fedora_data_source): - LOGGER.info(f"Wait for DataSource {fedora_data_source.name} to opt out") +def opted_out_fedora_data_source(fedora_boot_source_data_source): + LOGGER.info(f"Wait for DataSource {fedora_boot_source_data_source.name} to opt out") try: for sample in TimeoutSampler( wait_timeout=TIMEOUT_5MIN, sleep=TIMEOUT_5SEC, - func=lambda: fedora_data_source.source.name == OS_FLAVOR_FEDORA, + func=lambda: fedora_boot_source_data_source.source.name == fedora_boot_source_data_source.name, ): if sample: return except TimeoutExpiredError: - LOGGER.error(f"{fedora_data_source.name} DataSource source was not updated.") + LOGGER.error(f"{fedora_boot_source_data_source.name} DataSource source was not updated.") raise @pytest.fixture() -def imported_fedora_dv(admin_client, golden_images_namespace, fedora_data_source): +def imported_fedora_dv(admin_client, golden_images_namespace, fedora_boot_source_data_source): + fedora_registry_url = f"docker://{getattr(ArchImages, py_config['cpu_arch'].upper()).Fedora.FEDORA_CONTAINER_IMAGE}" with DataVolume( client=admin_client, - name=fedora_data_source.name, + name=fedora_boot_source_data_source.name, namespace=golden_images_namespace.name, api_name="storage", - source_dict=construct_datavolume_source_dict(source="registry", url=DEFAULT_FEDORA_REGISTRY_URL), + source_dict=construct_datavolume_source_dict(source="registry", url=fedora_registry_url), size=Images.Fedora.DEFAULT_DV_SIZE, storage_class=py_config["default_storage_class"], annotations=BIND_IMMEDIATE_ANNOTATION, @@ -130,6 +147,7 @@ def imported_fedora_dv(admin_client, golden_images_namespace, fedora_data_source yield dv +@pytest.mark.arm64 @pytest.mark.polarion("CNV-7586") def test_vm_from_auto_update_boot_source( auto_update_boot_source_vm, @@ -159,6 +177,7 @@ def test_common_templates_boot_source_reference(base_templates): assert not failed_templates, f"Some templates do not use {source_ref_str}, templates: {failed_templates}" +@pytest.mark.arm64 @pytest.mark.polarion("CNV-7535") def test_vm_with_uploaded_golden_image_opt_out( admin_client, diff --git a/tests/infrastructure/golden_images/update_boot_source/test_ssp_data_import_crons.py b/tests/infrastructure/golden_images/update_boot_source/test_ssp_data_import_crons.py index 911990505a..c1b7f95e98 100644 --- a/tests/infrastructure/golden_images/update_boot_source/test_ssp_data_import_crons.py +++ b/tests/infrastructure/golden_images/update_boot_source/test_ssp_data_import_crons.py @@ -4,6 +4,7 @@ from kubernetes.dynamic.exceptions import UnprocessibleEntityError from ocp_resources.data_import_cron import DataImportCron from ocp_resources.data_source import DataSource +from pytest_testconfig import config as py_config from timeout_sampler import TimeoutExpiredError, TimeoutSampler from tests.infrastructure.golden_images.constants import ( @@ -15,7 +16,8 @@ wait_for_created_volume_from_data_import_cron, wait_for_existing_auto_update_data_import_crons, ) -from utilities.constants.images import DEFAULT_FEDORA_REGISTRY_URL +from utilities.constants.architecture import MULTIARCH +from utilities.constants.images import DEFAULT_FEDORA_REGISTRY_URL, OS_FLAVOR_RHEL from utilities.constants.timeouts import ( TIMEOUT_2MIN, TIMEOUT_5MIN, @@ -31,12 +33,20 @@ LOGGER = logging.getLogger(__name__) -pytestmark = pytest.mark.post_upgrade +pytestmark = [pytest.mark.post_upgrade, pytest.mark.arm64] @pytest.mark.polarion("CNV-12414") def test_updated_rhel_image(golden_images_data_import_crons_scope_class, latest_rhel_release_versions_dict, subtests): - for rhel_dic in [dic for dic in golden_images_data_import_crons_scope_class if "rhel" in dic.name.lower()]: + cpu_arch = py_config["cpu_arch"] + arch_suffix = f"-{cpu_arch}" + rhel_dics = [ + dic + for dic in golden_images_data_import_crons_scope_class + if OS_FLAVOR_RHEL in dic.name.lower() + and (py_config.get("cluster_type") != MULTIARCH or dic.instance.spec.managedDataSource.endswith(arch_suffix)) + ] + for rhel_dic in rhel_dics: rhel_instance_dict = rhel_dic.instance image_reference_version = get_image_version( image=rhel_instance_dict.metadata.annotations.get("cdi.kubevirt.io/storage.import.imageStreamDockerRef") @@ -44,7 +54,8 @@ def test_updated_rhel_image(golden_images_data_import_crons_scope_class, latest_ with subtests.test(rhel_dic_name=rhel_dic.name, managed_data_source=rhel_instance_dict.spec.managedDataSource): managed_data_source = rhel_instance_dict.spec.managedDataSource assert managed_data_source, "spec.managedDataSource doesn't exists" - assert latest_rhel_release_versions_dict[managed_data_source] == image_reference_version + base_data_source = managed_data_source.removesuffix(arch_suffix) + assert latest_rhel_release_versions_dict[base_data_source] == image_reference_version class TestDataImportCronValidation: diff --git a/tests/infrastructure/golden_images/update_boot_source/utils.py b/tests/infrastructure/golden_images/update_boot_source/utils.py index 66d70159bf..526fe5bd20 100644 --- a/tests/infrastructure/golden_images/update_boot_source/utils.py +++ b/tests/infrastructure/golden_images/update_boot_source/utils.py @@ -63,11 +63,12 @@ def generate_data_import_cron_dict( } -def template_labels(os): +def template_labels(os, architecture=None): return Template.generate_template_labels( os=os, workload=Template.Workload.SERVER, flavor=Template.Flavor.SMALL, + architecture=architecture, ) diff --git a/utilities/pytest_utils.py b/utilities/pytest_utils.py index c005905463..075b53b4da 100644 --- a/utilities/pytest_utils.py +++ b/utilities/pytest_utils.py @@ -698,6 +698,8 @@ def update_cpu_arch_related_config(cpu_arch_option: str) -> None: if py_config["cluster_type"] == MULTIARCH: generate_common_template_matrix_dicts(os_dict=py_config["os_matrix"][arch], cpu_arch=arch) generate_instance_type_matrix_dicts(os_dict=py_config["os_matrix"][arch], cpu_arch=arch) + py_config["data_import_cron_matrix"] = py_config["os_matrix"][arch]["data_import_cron_matrix"] + py_config["auto_update_data_source_matrix"] = py_config["os_matrix"][arch]["auto_update_data_source_matrix"] else: generate_common_template_matrix_dicts(os_dict=py_config) if py_config["cluster_type"] != AMD_64: diff --git a/utilities/unittests/test_pytest_utils.py b/utilities/unittests/test_pytest_utils.py index 5113232602..6777d72b59 100644 --- a/utilities/unittests/test_pytest_utils.py +++ b/utilities/unittests/test_pytest_utils.py @@ -2301,7 +2301,13 @@ def test_multiarch_cluster_uses_os_matrix_arch( mock_generate_instance, ): """Test that MULTIARCH cluster type uses os_matrix[arch] for OS matrix generation""" - os_matrix_amd64 = {"rhel_os_list": ["rhel-9-6"]} + dic_matrix = [{"rhel10-amd64": {"instance_type": "u1.medium", "preference": "rhel.10"}}] + auto_update_matrix = [{"centos-stream9-amd64": {"template_os": "centos-stream9"}}] + os_matrix_amd64 = { + "rhel_os_list": ["rhel-9-6"], + "data_import_cron_matrix": dic_matrix, + "auto_update_data_source_matrix": auto_update_matrix, + } mock_py_config = { "cluster_type": "multiarch", "os_matrix": {"amd64": os_matrix_amd64, "arm64": {"rhel_os_list": ["rhel-9-5"]}}, @@ -2318,6 +2324,8 @@ def test_multiarch_cluster_uses_os_matrix_arch( assert utilities.constants.Images is mock_arch_images.AMD64 mock_generate_common.assert_called_once_with(os_dict=os_matrix_amd64, cpu_arch="amd64") mock_generate_instance.assert_called_once_with(os_dict=os_matrix_amd64, cpu_arch="amd64") + assert mock_py_config["data_import_cron_matrix"] == dic_matrix + assert mock_py_config["auto_update_data_source_matrix"] == auto_update_matrix @patch("utilities.pytest_utils.generate_instance_type_matrix_dicts") @patch("utilities.pytest_utils.generate_common_template_matrix_dicts") @@ -2469,7 +2477,13 @@ def test_multiarch_cluster_arm64_uses_correct_os_matrix( mock_generate_instance, ): """Test that MULTIARCH cluster with arm64 option uses os_matrix[arm64]""" - os_matrix_arm64 = {"rhel_os_list": ["rhel-9-5"]} + dic_matrix = [{"rhel10-arm64": {"instance_type": "u1.medium", "preference": "rhel.10.arm64"}}] + auto_update_matrix = [{"fedora-arm64": {"template_os": "fedora"}}] + os_matrix_arm64 = { + "rhel_os_list": ["rhel-9-5"], + "data_import_cron_matrix": dic_matrix, + "auto_update_data_source_matrix": auto_update_matrix, + } mock_py_config = { "cluster_type": "multiarch", "os_matrix": {"amd64": {"rhel_os_list": ["rhel-9-6"]}, "arm64": os_matrix_arm64}, @@ -2486,6 +2500,8 @@ def test_multiarch_cluster_arm64_uses_correct_os_matrix( assert utilities.constants.Images is mock_arch_images.ARM64 mock_generate_common.assert_called_once_with(os_dict=os_matrix_arm64, cpu_arch="arm64") mock_generate_instance.assert_called_once_with(os_dict=os_matrix_arm64, cpu_arch="arm64") + assert mock_py_config["data_import_cron_matrix"] == dic_matrix + assert mock_py_config["auto_update_data_source_matrix"] == auto_update_matrix @patch("utilities.pytest_utils.generate_instance_type_matrix_dicts") @patch("utilities.pytest_utils.generate_common_template_matrix_dicts") diff --git a/utilities/virt.py b/utilities/virt.py index ab03d1abbc..5e57b4d745 100644 --- a/utilities/virt.py +++ b/utilities/virt.py @@ -2338,12 +2338,15 @@ def get_base_templates_list(client: DynamicClient) -> list[Template]: def get_template_by_labels(admin_client, template_labels): + selector_labels = [label for label in template_labels if OS_FLAVOR_FEDORA not in label] + if cpu_arch := py_config.get("cpu_arch"): + selector_labels.append(f"{Template.Labels.ARCHITECTURE}={cpu_arch}") template = list( Template.get( client=admin_client, singular_name=Template.singular_name, namespace="openshift", - label_selector=",".join([label for label in template_labels if OS_FLAVOR_FEDORA not in label]), + label_selector=",".join(selector_labels), ), ) if any(