From f8a37e9b672d6894abd44108fc98b098dc673ec8 Mon Sep 17 00:00:00 2001 From: Raheel Abdul Faizy Date: Tue, 30 Jun 2026 11:26:24 -0700 Subject: [PATCH] [AI Generated] BugFix: vm_resize security_profile filter and clearer skip Two related fixes in the VM resize test path: 1. azure Resize feature: when selecting a candidate VM size to resize to, also filter out SKUs whose advertised security_profile SetSpace does not include the source VM's deployed security profile (CVM / TrustedLaunch / Standard). Without this filter the random picker can choose a non-CVM SKU for a CVM-deployed VM and every Azure update call is rejected with PropertyChangeNotAllowed, exhausting all retries. 2. VmResize test suite: when the retry loop ends without a successful resize, raise SkippedException including the last Azure error instead of asserting 'fail to find proper vm size'. This is an environment limitation (no compatible candidate was picked across retries), not a defect in the system under test. --- lisa/microsoft/testsuites/core/vm_resize.py | 18 ++++++- lisa/sut_orchestrator/azure/features.py | 59 +++++++++++++++++++++ 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/lisa/microsoft/testsuites/core/vm_resize.py b/lisa/microsoft/testsuites/core/vm_resize.py index 178b4f3a0f..335d5f9379 100644 --- a/lisa/microsoft/testsuites/core/vm_resize.py +++ b/lisa/microsoft/testsuites/core/vm_resize.py @@ -127,9 +127,12 @@ def _verify_vm_resize( start_stop.stop() retry = 1 maxretry = 20 + expected_vm_capability: Optional[NodeSpace] = None + origin_vm_size: str = "" + final_vm_size: str = "" + last_error: str = "" while retry < maxretry: try: - expected_vm_capability: Optional[NodeSpace] = None expected_vm_capability, origin_vm_size, final_vm_size = resize.resize( resize_action ) @@ -150,6 +153,7 @@ def _verify_vm_resize( in str(e) or "Following SKUs have failed for Capacity Restrictions" in str(e) ): + last_error = str(e) retry = retry + 1 else: raise e @@ -157,7 +161,17 @@ def _verify_vm_resize( finally: if not hot_resize: start_stop.start() - assert expected_vm_capability, "fail to find proper vm size" + if not expected_vm_capability: + # The retry loop exhausted without a successful resize. This is an + # environment limitation (no compatible candidate happened to be + # picked across all retries), not a defect in the system under + # test, so surface it as SKIPPED rather than the misleading + # "fail to find proper vm size" assertion. + raise SkippedException( + f"no resize-compatible VM size succeeded after {maxretry - 1} " + f"attempts for action {resize_action}. last Azure error: " + f"{last_error or 'unknown'}" + ) test_result.information["final_vm_size"] = final_vm_size test_result.information["origin_vm_size"] = origin_vm_size diff --git a/lisa/sut_orchestrator/azure/features.py b/lisa/sut_orchestrator/azure/features.py index 5e243d6141..d9ac2ce0c7 100644 --- a/lisa/sut_orchestrator/azure/features.py +++ b/lisa/sut_orchestrator/azure/features.py @@ -2546,12 +2546,68 @@ def _check_actual_disk_controller_type( return True + def _get_actual_security_profile(self) -> Optional[SecurityProfileType]: + # Read the security profile the source VM was actually deployed with + # (a concrete value), as opposed to what the SKU advertises in its + # capability SetSpace. Resizing a CVM-deployed VM to a SKU whose + # advertised SetSpace includes CVM AND Standard is fine; resizing + # to a SKU that only advertises Standard will be rejected by Azure + # with PropertyChangeNotAllowed. + if not self._node.capability.features: + return None + for feature in self._node.capability.features: + if feature.type != SecurityProfileSettings.type: + continue + if not isinstance(feature, SecurityProfileSettings): + continue + sp = feature.security_profile + if isinstance(sp, SecurityProfileType): + return sp + if isinstance(sp, search_space.SetSpace): + items = list(sp) + if len(items) == 1: + return items[0] + return None + return None + + def _compare_security_profile( + self, + candidate_size: "AzureCapability", + actual_security_profile: Optional[SecurityProfileType], + ) -> bool: + # The candidate SKU must support the source VM's deployed security + # profile (CVM, TrustedLaunch/SecureBoot, Stateless, Standard). + # Without this filter, the random selector can pick a non-CVM SKU as + # a resize target for a CVM VM, and every retry will fail with + # PropertyChangeNotAllowed. + if not actual_security_profile: + return True + assert candidate_size.capability + assert candidate_size.capability.features + candidate_sp = next( + ( + feature + for feature in candidate_size.capability.features + if feature.type == SecurityProfileSettings.type + ), + None, + ) + if not isinstance(candidate_sp, SecurityProfileSettings): + return True + cand_profiles = candidate_sp.security_profile + if isinstance(cand_profiles, search_space.SetSpace): + return actual_security_profile in cand_profiles + if isinstance(cand_profiles, SecurityProfileType): + return cand_profiles == actual_security_profile + return True + def _is_candidate_size_valid( self, candidate_size: "AzureCapability", current_vm_size: "AzureCapability", resize_action: ResizeAction, actual_disk_controller_type: Optional[schema.DiskControllerType], + actual_security_profile: Optional[SecurityProfileType], ) -> bool: return ( self._compare_architecture(candidate_size, current_vm_size) @@ -2562,6 +2618,7 @@ def _is_candidate_size_valid( and self._check_actual_disk_controller_type( candidate_size, actual_disk_controller_type ) + and self._compare_security_profile(candidate_size, actual_security_profile) and self._compare_size_generation(candidate_size, current_vm_size) and self._compare_network_interface(candidate_size, current_vm_size) and self._compare_core_count(candidate_size, current_vm_size, resize_action) @@ -2626,6 +2683,7 @@ def _select_vm_size( assert current_vm_size.capability.features actual_disk_controller_type = self._get_actual_disk_controller_type() + actual_security_profile = self._get_actual_security_profile() # Filter candidate vm sizes that can't be resized to avail_eligible_intersect = [ @@ -2636,6 +2694,7 @@ def _select_vm_size( current_vm_size, resize_action, actual_disk_controller_type, + actual_security_profile, ) ]