From a63b87b5a9345cadc55dcb7cff24c6ded056a7c9 Mon Sep 17 00:00:00 2001 From: Ohad Date: Thu, 11 Dec 2025 14:57:48 +0200 Subject: [PATCH 1/2] Modify windows vm deployment to include virtio modify the fixture for creating windows vm to include virtio and wsl --- tests/observability/metrics/utils.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/observability/metrics/utils.py b/tests/observability/metrics/utils.py index c3c1adc605..43e498bda7 100644 --- a/tests/observability/metrics/utils.py +++ b/tests/observability/metrics/utils.py @@ -17,6 +17,7 @@ from ocp_resources.virtual_machine_cluster_preference import VirtualMachineClusterPreference from ocp_utilities.monitoring import Prometheus from pyhelper_utils.shell import run_ssh_commands +from pytest_testconfig import py_config from timeout_sampler import TimeoutExpiredError, TimeoutSampler from tests.observability.constants import KUBEVIRT_VIRT_OPERATOR_READY @@ -33,7 +34,7 @@ cleanup_artifactory_secret_and_config_map, get_artifactory_config_map, get_artifactory_secret, - get_http_image_url, + get_http_image_url, get_test_artifact_server_url, ) from utilities.constants import ( CAPACITY, @@ -692,14 +693,14 @@ def create_windows11_wsl2_vm( artifactory_secret = get_artifactory_secret(namespace=namespace) artifactory_config_map = get_artifactory_config_map(namespace=namespace) dv = DataVolume( + client=client, name=dv_name, namespace=namespace, - storage_class=storage_class, - source="http", - url=get_http_image_url(image_directory=Images.Windows.DIR, image_name=Images.Windows.WIN11_WSL2_IMG), - size=Images.Windows.DEFAULT_DV_SIZE, - client=client, api_name="storage", + source="registry", + size=Images.Windows.CONTAINER_DISK_DV_SIZE, + storage_class=storage_class, + url=f"{get_test_artifact_server_url(schema='registry')}/docker/windows-qe/win_11:virtio", secret=artifactory_secret, cert_configmap=artifactory_config_map.name, ) From d970ce6fc85e488822be21f9c8971be21f9e170d Mon Sep 17 00:00:00 2001 From: Ohad Date: Sun, 14 Dec 2025 10:26:48 +0200 Subject: [PATCH 2/2] Modify windows vm deployment to include virtio Windows vm needs to include virtio drivers in order some metrics will be able to get the info they need. Also updated network metrics to work with the new change and simplified it. --- tests/observability/metrics/conftest.py | 19 ++++++- .../metrics/test_network_metrics.py | 20 ++++--- tests/observability/metrics/utils.py | 52 +++++++++++-------- 3 files changed, 62 insertions(+), 29 deletions(-) diff --git a/tests/observability/metrics/conftest.py b/tests/observability/metrics/conftest.py index 0d5408444d..eeffc2aad5 100644 --- a/tests/observability/metrics/conftest.py +++ b/tests/observability/metrics/conftest.py @@ -31,9 +31,11 @@ disk_file_system_info, enable_swap_fedora_vm, get_metric_sum_value, + get_pod_interface_name_from_vm, get_vm_comparison_info_dict, get_vmi_guest_os_kernel_release_info_metric_from_vm, metric_result_output_dict_by_mountpoint, + network_packets_received, vnic_info_from_vm_or_vmi, ) from tests.observability.utils import validate_metrics_value @@ -229,17 +231,30 @@ def generated_network_traffic_windows_vm(windows_vm_for_test): src_vm=windows_vm_for_test, dst_ip=get_ip_from_vm_or_virt_handler_pod(family=IPV4_STR, vm=windows_vm_for_test), windows=True, + quiet_output=False, ) @pytest.fixture(scope="class") def linux_vm_for_test_interface_name(vm_for_test): - return vm_for_test.vmi.interfaces[0].interfaceName + return get_pod_interface_name_from_vm(vm=vm_for_test) @pytest.fixture(scope="class") def windows_vm_for_test_interface_name(windows_vm_for_test): - return windows_vm_for_test.vmi.interfaces[0].interfaceName + return get_pod_interface_name_from_vm(vm=windows_vm_for_test) + + +@pytest.fixture() +def network_packet_received_windows_vm(windows_vm_for_test, windows_vm_for_test_interface_name): + return network_packets_received( + vm=windows_vm_for_test, interface_name=windows_vm_for_test_interface_name, windows_wsl=True + ) + + +@pytest.fixture() +def network_packet_received_linux_vm(vm_for_test, linux_vm_for_test_interface_name): + return network_packets_received(vm=vm_for_test, interface_name=linux_vm_for_test_interface_name) @pytest.fixture(scope="class") diff --git a/tests/observability/metrics/test_network_metrics.py b/tests/observability/metrics/test_network_metrics.py index 599bcd2abc..0bbd6637a7 100644 --- a/tests/observability/metrics/test_network_metrics.py +++ b/tests/observability/metrics/test_network_metrics.py @@ -17,12 +17,17 @@ class TestVmiNetworkMetricsLinux: @pytest.mark.polarion("CNV-11177") @pytest.mark.s390x def test_kubevirt_vmi_network_traffic_bytes_total( - self, prometheus, vm_for_test, linux_vm_for_test_interface_name, generated_network_traffic + self, + prometheus, + vm_for_test, + linux_vm_for_test_interface_name, + generated_network_traffic, + network_packet_received_linux_vm, ): validate_network_traffic_metrics_value( prometheus=prometheus, vm=vm_for_test, - interface_name=linux_vm_for_test_interface_name, + network_packet_received=network_packet_received_linux_vm, ) @@ -30,10 +35,13 @@ def test_kubevirt_vmi_network_traffic_bytes_total( class TestVmiNetworkMetricsWindows: @pytest.mark.polarion("CNV-11846") def test_kubevirt_vmi_network_traffic_bytes_total_windows_vm( - self, prometheus, windows_vm_for_test, windows_vm_for_test_interface_name, generated_network_traffic_windows_vm + self, + prometheus, + windows_vm_for_test, + windows_vm_for_test_interface_name, + generated_network_traffic_windows_vm, + network_packet_received_windows_vm, ): validate_network_traffic_metrics_value( - prometheus=prometheus, - vm=windows_vm_for_test, - interface_name=windows_vm_for_test_interface_name, + prometheus=prometheus, vm=windows_vm_for_test, network_packet_received=network_packet_received_windows_vm ) diff --git a/tests/observability/metrics/utils.py b/tests/observability/metrics/utils.py index 43e498bda7..3607a0ca4c 100644 --- a/tests/observability/metrics/utils.py +++ b/tests/observability/metrics/utils.py @@ -2,7 +2,6 @@ import math import re import shlex -import time import urllib from contextlib import contextmanager from datetime import datetime, timezone @@ -17,7 +16,6 @@ from ocp_resources.virtual_machine_cluster_preference import VirtualMachineClusterPreference from ocp_utilities.monitoring import Prometheus from pyhelper_utils.shell import run_ssh_commands -from pytest_testconfig import py_config from timeout_sampler import TimeoutExpiredError, TimeoutSampler from tests.observability.constants import KUBEVIRT_VIRT_OPERATOR_READY @@ -34,7 +32,7 @@ cleanup_artifactory_secret_and_config_map, get_artifactory_config_map, get_artifactory_secret, - get_http_image_url, get_test_artifact_server_url, + get_test_artifact_server_url, ) from utilities.constants import ( CAPACITY, @@ -49,6 +47,7 @@ TIMEOUT_15SEC, TIMEOUT_20SEC, TIMEOUT_30SEC, + TIMEOUT_40MIN, USED, VIRT_HANDLER, Images, @@ -327,18 +326,26 @@ def validate_metric_value_within_range( raise -def network_packets_received(vm: VirtualMachineForTests, interface_name: str) -> dict[str, str]: - ip_link_show_content = run_ssh_commands(host=vm.ssh_exec, commands=shlex.split("ip -s link show"))[0] +def network_packets_received( + vm: VirtualMachineForTests, interface_name: str, windows_wsl: bool = False +) -> dict[str, str]: + ip_link_show_content = run_ssh_commands( + host=vm.ssh_exec, commands=shlex.split(f"{'wsl' if windows_wsl else ''} ip -s link show") + )[0] + LOGGER.info(f"Looking for interface: '{interface_name}'") + LOGGER.info(f"ip link show output:\n{ip_link_show_content}") + pattern = re.compile( rf".*?{re.escape(interface_name)}:.*?" # Match the line with the interface name - r"(?:RX:\s+bytes\s+packets\s+errors\s+dropped\s+.*?(\d+)\s+(\d+)\s+(\d+)\s+(\d+)).*?" # Capture RX stats - r"(?:TX:\s+bytes\s+packets\s+errors\s+dropped\s+.*?(\d+)\s+(\d+)\s+(\d+)\s+(\d+))", # Capture TX stats + r"RX:.*?\n\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+\d+\s+\d+.*?" # Capture RX stats (bytes, packets, errors, dropped) + r"TX:.*?\n\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)", # Capture TX stats (bytes, packets, errors, dropped) re.DOTALL | re.IGNORECASE, ) match = pattern.search(string=ip_link_show_content) + if match: rx_bytes, rx_packets, rx_errs, rx_drop, tx_bytes, tx_packets, tx_errs, tx_drop = match.groups() - return { + result = { "rx_bytes": rx_bytes, "rx_packets": rx_packets, "rx_errs": rx_errs, @@ -348,16 +355,17 @@ def network_packets_received(vm: VirtualMachineForTests, interface_name: str) -> "tx_errs": tx_errs, "tx_drop": tx_drop, } - return {} + LOGGER.info(f"Successfully parsed network stats: {result}") + return result + else: + LOGGER.warning(f"No match found for interface '{interface_name}' in ip link show output") + return {} def compare_network_traffic_bytes_and_metrics( - prometheus: Prometheus, vm: VirtualMachineForTests, vm_interface_name: str + prometheus: Prometheus, vm: VirtualMachineForTests, network_packet_received: dict[str, str] ) -> bool: - packet_received = network_packets_received(vm=vm, interface_name=vm_interface_name) rx_tx_indicator = False - LOGGER.info("Waiting for metric kubevirt_vmi_network_traffic_bytes_total to update") - time.sleep(TIMEOUT_15SEC) metric_result = ( prometheus .query(query=f"kubevirt_vmi_network_traffic_bytes_total{{name='{vm.name}'}}") @@ -366,9 +374,7 @@ def compare_network_traffic_bytes_and_metrics( ) for entry in metric_result: entry_value = entry.get("value")[1] - if math.isclose( - int(entry_value), int(packet_received[f"{entry.get('metric').get('type')}_bytes"]), rel_tol=0.05 - ): + if int(entry_value) >= int(network_packet_received[f"{entry.get('metric').get('type')}_bytes"]): rx_tx_indicator = True else: break @@ -378,7 +384,7 @@ def compare_network_traffic_bytes_and_metrics( def validate_network_traffic_metrics_value( - prometheus: Prometheus, vm: VirtualMachineForTests, interface_name: str + prometheus: Prometheus, vm: VirtualMachineForTests, network_packet_received: dict[str, str] ) -> None: samples = TimeoutSampler( wait_timeout=TIMEOUT_4MIN, @@ -386,7 +392,7 @@ def validate_network_traffic_metrics_value( func=compare_network_traffic_bytes_and_metrics, prometheus=prometheus, vm=vm, - vm_interface_name=interface_name, + network_packet_received=network_packet_received, ) try: for sample in samples: @@ -710,11 +716,11 @@ def create_windows11_wsl2_vm( name=vm_name, namespace=namespace, client=client, - vm_instance_type=VirtualMachineClusterInstancetype(client=client, name="u1.xlarge"), + vm_instance_type=VirtualMachineClusterInstancetype(client=client, name="u1.large"), vm_preference=VirtualMachineClusterPreference(client=client, name="windows.11"), data_volume_template={"metadata": dv.res["metadata"], "spec": dv.res["spec"]}, ) as vm: - running_vm(vm=vm) + running_vm(vm=vm, dv_wait_timeout=TIMEOUT_40MIN) yield vm cleanup_artifactory_secret_and_config_map( artifactory_secret=artifactory_secret, artifactory_config_map=artifactory_config_map @@ -764,7 +770,7 @@ def get_pvc_size_bytes(vm: VirtualMachineForTests) -> str: def validate_metric_value_greater_than_initial_value( - prometheus: Prometheus, metric_name: str, initial_value: float, timeout: int = TIMEOUT_4MIN + prometheus: Prometheus, metric_name: str, initial_value: float, timeout: int = TIMEOUT_4MIN, equals: bool = False ) -> None: samples = TimeoutSampler( wait_timeout=timeout, @@ -834,3 +840,7 @@ def _get_metric_values(): return metric_sample raise TimeoutError("Timed out waiting for Prometheus metrics to match expected values.") + + +def get_pod_interface_name_from_vm(vm: VirtualMachineForTests) -> str: + return vm.vmi.interfaces[0].podInterfaceName