From b2d476f04c4c426ffa0de89398cc8d1f036af5b3 Mon Sep 17 00:00:00 2001 From: Denys Shchedrivyi Date: Mon, 30 Mar 2026 10:36:54 -0700 Subject: [PATCH 1/4] [VIRT] Add Windows crash detection test with hyperv panic device Test Windows BSOD detection using hyperv panic device and hv-crash. Verifies KubeVirt emits GuestPanicked events when Windows crashes. Co-Authored-By: Claude Sonnet 4.5 Signed-off-by: Denys Shchedrivyi --- .../test_windows_crash_detection.py | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 tests/virt/node/hyperv_support/test_windows_crash_detection.py diff --git a/tests/virt/node/hyperv_support/test_windows_crash_detection.py b/tests/virt/node/hyperv_support/test_windows_crash_detection.py new file mode 100644 index 0000000000..b2ac6a2024 --- /dev/null +++ b/tests/virt/node/hyperv_support/test_windows_crash_detection.py @@ -0,0 +1,102 @@ +import logging + +import pytest +from pyhelper_utils.shell import run_ssh_commands +from timeout_sampler import TimeoutExpiredError, TimeoutSampler + +from tests.os_params import WINDOWS_LATEST, WINDOWS_LATEST_LABELS +from utilities.constants import TIMEOUT_3MIN, TIMEOUT_5SEC, TIMEOUT_10SEC +from utilities.data_collector import collect_vnc_screenshot_for_vms +from utilities.virt import running_vm, vm_instance_from_template + +LOGGER = logging.getLogger(__name__) + +BSOD_COMMAND = ( + "$e=$false; $r=0; " + "Add-Type -TypeDefinition 'using System; using System.Runtime.InteropServices; " + 'public class C { [DllImport("ntdll.dll")] public static extern uint NtRaiseHardError' + "(uint a,uint b,uint c,IntPtr d,uint e,out uint f); " + '[DllImport("ntdll.dll")] public static extern uint RtlAdjustPrivilege' + "(int a,bool b,bool c,out bool d);}'; " + "[C]::RtlAdjustPrivilege(19,$true,$false,[ref]$e) | Out-Null; " + "[C]::NtRaiseHardError([uint32]3221226528,0,0,[IntPtr]::Zero,6,[ref]$r)" +) + + +@pytest.fixture() +def windows_crashed(windows_vm_with_panic_device): + LOGGER.info(f"Triggering BSOD on VM {windows_vm_with_panic_device.name} via NtRaiseHardError") + try: + run_ssh_commands( + host=windows_vm_with_panic_device.ssh_exec, + commands=["powershell", "-c", BSOD_COMMAND], + timeout=TIMEOUT_10SEC, + ) + except TimeoutError: + LOGGER.info("SSH timeout as expected - VM has crashed") + + +def wait_for_guest_panicked_event(vm): + LOGGER.info(f"Waiting for GuestPanicked event for VM {vm.name}") + try: + for sample in TimeoutSampler( + wait_timeout=TIMEOUT_3MIN, + sleep=TIMEOUT_5SEC, + func=lambda: list(vm.vmi.events(timeout=TIMEOUT_5SEC, field_selector="reason==GuestPanicked")), + ): + if sample: + LOGGER.info("GuestPanicked event found") + return + except TimeoutExpiredError: + LOGGER.error(f"GuestPanicked event not found for VM {vm.name}") + collect_vnc_screenshot_for_vms(vm=vm) + raise + + +@pytest.fixture() +def windows_vm_with_panic_device( + request, + unprivileged_client, + namespace, + golden_image_data_volume_template_for_test_scope_function, +): + vm_dict = {"spec": {"template": {"spec": {"domain": {"devices": {"panicDevices": [{"model": "hyperv"}]}}}}}} + request.param["vm_dict"] = vm_dict + + with vm_instance_from_template( + request=request, + unprivileged_client=unprivileged_client, + namespace=namespace, + data_volume_template=golden_image_data_volume_template_for_test_scope_function, + ) as vm: + running_vm(vm=vm) + yield vm + + +@pytest.mark.parametrize( + ( + "enabled_featuregate_scope_function, " + "golden_image_data_source_for_test_scope_function, " + "windows_vm_with_panic_device" + ), + [ + pytest.param( + "PanicDevices", + {"os_dict": WINDOWS_LATEST}, + { + "vm_name": "windows-crash-detection-vm", + "template_labels": WINDOWS_LATEST_LABELS, + }, + marks=pytest.mark.polarion("CNV-15265"), + ), + ], + indirect=True, +) +@pytest.mark.special_infra +@pytest.mark.high_resource_vm +def test_windows_crash_detection_with_hyperv_panic( + enabled_featuregate_scope_function, + windows_vm_with_panic_device, + windows_crashed, +): + wait_for_guest_panicked_event(vm=windows_vm_with_panic_device) From a2a16485683c4f4255ee12e2666daf6b310c9afd Mon Sep 17 00:00:00 2001 From: Denys Shchedrivyi Date: Mon, 13 Apr 2026 18:56:03 -0700 Subject: [PATCH 2/4] Add STD docstrings to Windows crash detection test Added module-level and test function docstrings following STD format with Preconditions, Steps, and Expected sections as requested by CodeRabbit review. Co-Authored-By: Claude Sonnet 4.5 Signed-off-by: Denys Shchedrivyi --- .../test_windows_crash_detection.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/virt/node/hyperv_support/test_windows_crash_detection.py b/tests/virt/node/hyperv_support/test_windows_crash_detection.py index b2ac6a2024..34fd3fefad 100644 --- a/tests/virt/node/hyperv_support/test_windows_crash_detection.py +++ b/tests/virt/node/hyperv_support/test_windows_crash_detection.py @@ -1,3 +1,7 @@ +""" +Windows crash detection with hyperv panic device +""" + import logging import pytest @@ -99,4 +103,17 @@ def test_windows_crash_detection_with_hyperv_panic( windows_vm_with_panic_device, windows_crashed, ): + """Test that KubeVirt detects Windows guest crash via Hyper-V panic device. + + Preconditions: + - PanicDevices feature gate enabled + - Windows VM created with hyperv panic device configured + + Steps: + 1. Trigger BSOD on Windows VM using NtRaiseHardError + 2. Wait for GuestPanicked event on VMI + + Expected: + - VMI emits GuestPanicked event when Windows crashes + """ wait_for_guest_panicked_event(vm=windows_vm_with_panic_device) From 9fec666f8975ac269f6e8b694b38fb63ac6ae5c9 Mon Sep 17 00:00:00 2001 From: Denys Shchedrivyi Date: Tue, 14 Apr 2026 18:17:48 -0700 Subject: [PATCH 3/4] Use vm.vmi.events() directly without TimeoutSampler wrapper Simplified event watching by using the built-in timeout mechanism of vm.vmi.events() instead of wrapping it in TimeoutSampler. The default 4-minute timeout is sufficient for crash detection. Addresses reviewer feedback to use vm.vmi.events() directly. Co-Authored-By: Claude Sonnet 4.5 Signed-off-by: Denys Shchedrivyi --- .../test_windows_crash_detection.py | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/tests/virt/node/hyperv_support/test_windows_crash_detection.py b/tests/virt/node/hyperv_support/test_windows_crash_detection.py index 34fd3fefad..1f253dde16 100644 --- a/tests/virt/node/hyperv_support/test_windows_crash_detection.py +++ b/tests/virt/node/hyperv_support/test_windows_crash_detection.py @@ -1,15 +1,18 @@ """ Windows crash detection with hyperv panic device + +Reference: +https://redhat.atlassian.net/browse/VIRTSTRAT-557 """ import logging import pytest from pyhelper_utils.shell import run_ssh_commands -from timeout_sampler import TimeoutExpiredError, TimeoutSampler +from timeout_sampler import TimeoutExpiredError from tests.os_params import WINDOWS_LATEST, WINDOWS_LATEST_LABELS -from utilities.constants import TIMEOUT_3MIN, TIMEOUT_5SEC, TIMEOUT_10SEC +from utilities.constants import TIMEOUT_10SEC from utilities.data_collector import collect_vnc_screenshot_for_vms from utilities.virt import running_vm, vm_instance_from_template @@ -42,19 +45,12 @@ def windows_crashed(windows_vm_with_panic_device): def wait_for_guest_panicked_event(vm): LOGGER.info(f"Waiting for GuestPanicked event for VM {vm.name}") - try: - for sample in TimeoutSampler( - wait_timeout=TIMEOUT_3MIN, - sleep=TIMEOUT_5SEC, - func=lambda: list(vm.vmi.events(timeout=TIMEOUT_5SEC, field_selector="reason==GuestPanicked")), - ): - if sample: - LOGGER.info("GuestPanicked event found") - return - except TimeoutExpiredError: - LOGGER.error(f"GuestPanicked event not found for VM {vm.name}") - collect_vnc_screenshot_for_vms(vm=vm) - raise + for event in vm.vmi.events(field_selector="reason==GuestPanicked"): + LOGGER.info(f"GuestPanicked event found: {event}") + return + LOGGER.error(f"GuestPanicked event not found for VM {vm.name}") + collect_vnc_screenshot_for_vms(vm=vm) + raise TimeoutExpiredError("GuestPanicked event not received") @pytest.fixture() From 1ea7cfaf1e90652a73fe8dda66d9aab2ffcf169d Mon Sep 17 00:00:00 2001 From: Denys Shchedrivyi Date: Mon, 20 Apr 2026 18:27:23 -0700 Subject: [PATCH 4/4] Add pytest marks added pytest marks for virt-sanity checks Signed-off-by: Denys Shchedrivyi --- .../virt/node/hyperv_support/test_windows_crash_detection.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/virt/node/hyperv_support/test_windows_crash_detection.py b/tests/virt/node/hyperv_support/test_windows_crash_detection.py index 1f253dde16..23a547b407 100644 --- a/tests/virt/node/hyperv_support/test_windows_crash_detection.py +++ b/tests/virt/node/hyperv_support/test_windows_crash_detection.py @@ -16,6 +16,11 @@ from utilities.data_collector import collect_vnc_screenshot_for_vms from utilities.virt import running_vm, vm_instance_from_template +pytestmark = [ + pytest.mark.special_infra, + pytest.mark.high_resource_vm, +] + LOGGER = logging.getLogger(__name__) BSOD_COMMAND = (