From b417d2441b6ae230b14691a6649e00cb19ca392b Mon Sep 17 00:00:00 2001 From: xuexu6666 Date: Wed, 1 Jul 2026 17:31:13 -0500 Subject: [PATCH 1/2] {AKS} skip Machines mode agent pool during upgrade Port Azure/azure-cli-extensions#9916 into the core acs module: az aks upgrade now skips Machines mode agent pools during --node-image-only and Kubernetes version upgrade (they do not support these operations at the agent pool level), instead of surfacing the raw RP OperationNotAllowed error. Adds unit tests and a HISTORY entry. --- src/azure-cli/HISTORY.rst | 1 + .../azure/cli/command_modules/acs/_consts.py | 1 + .../azure/cli/command_modules/acs/custom.py | 9 ++++ .../acs/tests/latest/test_custom.py | 46 +++++++++++++++++++ 4 files changed, 57 insertions(+) diff --git a/src/azure-cli/HISTORY.rst b/src/azure-cli/HISTORY.rst index 7bbafa33310..5f60eedfe7f 100644 --- a/src/azure-cli/HISTORY.rst +++ b/src/azure-cli/HISTORY.rst @@ -16,6 +16,7 @@ Release History **AKS** +* `az aks upgrade`: Skip Machines mode agent pools during `--node-image-only` and Kubernetes version upgrade, which do not support these operations, instead of surfacing the raw RP OperationNotAllowed error * `az aks nodepool upgrade`: Fix `--max-unavailable` being silently ignored (#33215) * `az aks maintenanceconfiguration add/update`: Add support for maintenanceWindow format in default maintenance configuration (#33431) * `az aks check-acr`: Support national/sovereign clouds where nodes report `cloud=AzureStackCloud` by pointing canipull at the on-node `akscustom.json` environment file (#33551) diff --git a/src/azure-cli/azure/cli/command_modules/acs/_consts.py b/src/azure-cli/azure/cli/command_modules/acs/_consts.py index 5244002b05e..227790750ee 100644 --- a/src/azure-cli/azure/cli/command_modules/acs/_consts.py +++ b/src/azure-cli/azure/cli/command_modules/acs/_consts.py @@ -26,6 +26,7 @@ CONST_NODEPOOL_MODE_SYSTEM = "System" CONST_NODEPOOL_MODE_USER = "User" CONST_NODEPOOL_MODE_GATEWAY = "Gateway" +CONST_NODEPOOL_MODE_MACHINES = "Machines" # os type CONST_DEFAULT_NODE_OS_TYPE = "Linux" diff --git a/src/azure-cli/azure/cli/command_modules/acs/custom.py b/src/azure-cli/azure/cli/command_modules/acs/custom.py index ea653eb45bd..5a89ab7f4f9 100644 --- a/src/azure-cli/azure/cli/command_modules/acs/custom.py +++ b/src/azure-cli/azure/cli/command_modules/acs/custom.py @@ -61,6 +61,7 @@ CONST_MONITORING_ADDON_NAME, CONST_MONITORING_LOG_ANALYTICS_WORKSPACE_RESOURCE_ID, CONST_MONITORING_USING_AAD_MSI_AUTH, + CONST_NODEPOOL_MODE_MACHINES, CONST_NODEPOOL_MODE_USER, CONST_OPEN_SERVICE_MESH_ADDON_NAME, CONST_ROTATION_POLL_INTERVAL, @@ -1320,6 +1321,10 @@ def aks_upgrade(cmd, if vmas_cluster: raise CLIError('This cluster is using AvailabilitySet. Node image upgrade only operation ' 'can only be applied on VirtualMachineScaleSets or VirtualMachines cluster.') + # Skip Machines mode pools to avoid a known client-side error: these pools are containers of individual machines and do not support node image version upgrade. + if agent_pool_profile.mode == CONST_NODEPOOL_MODE_MACHINES: + logger.warning("Skipping node image upgrade for agent pool '%s': Machines mode pools do not support node image version upgrade.", agent_pool_profile.name) + continue agent_pool_client = cf_agent_pools(cmd.cli_ctx) _upgrade_single_nodepool_image_version(True, agent_pool_client, resource_group_name, name, agent_pool_profile.name) @@ -1381,6 +1386,10 @@ def aks_upgrade(cmd, if upgrade_all: for agent_profile in (instance.agent_pool_profiles or []): + # Skip Machines mode pools to avoid a known client-side error: these pools are containers of individual machines and do not support Kubernetes version upgrade. + if agent_profile.mode == CONST_NODEPOOL_MODE_MACHINES: + logger.warning("Skipping Kubernetes version upgrade for agent pool '%s': Machines mode pools do not support Kubernetes version upgrade.", agent_profile.name) + continue agent_profile.orchestrator_version = kubernetes_version agent_profile.creation_data = None diff --git a/src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_custom.py b/src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_custom.py index c2f7cc14c83..694278de645 100644 --- a/src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_custom.py +++ b/src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_custom.py @@ -30,6 +30,7 @@ aks_agentpool_upgrade, aks_enable_addons, aks_stop, + aks_upgrade, is_monitoring_addon_enabled, k8s_install_kubectl, k8s_install_kubelogin, @@ -971,6 +972,51 @@ def test_aks_stop(self): ) self.assertEqual(aks_stop(self.cmd, self.client, "rg", "name", False), None) + def test_aks_upgrade_node_image_only_skips_machines_mode_pool(self): + """Machines mode pools must be skipped during --node-image-only to avoid a known client-side error.""" + machines_pool = self.models.ManagedClusterAgentPoolProfile(name="machinespool", mode="Machines", type="VirtualMachines") + vmss_pool = self.models.ManagedClusterAgentPoolProfile(name="nodepool1", mode="User", type="VirtualMachineScaleSets") + mc = self.models.ManagedCluster(location="test_location") + mc.agent_pool_profiles = [machines_pool, vmss_pool] + mc.pod_identity_profile = None + mc.kubernetes_version = "1.24.0" + mc.provisioning_state = "Succeeded" + mc.max_agent_pools = 10 + + self.client.get = mock.Mock(return_value=mc) + + with mock.patch("azure.cli.command_modules.acs.custom.cf_agent_pools") as mock_cf, \ + mock.patch("azure.cli.command_modules.acs.custom._upgrade_single_nodepool_image_version") as mock_upgrade: + mock_cf.return_value = mock.Mock() + + aks_upgrade(self.cmd, self.client, "rg", "name", node_image_only=True, yes=True) + + # Only the VMSS pool should be upgraded; the Machines mode pool must be skipped. + upgraded_pools = [call.args[4] for call in mock_upgrade.call_args_list] + self.assertNotIn("machinespool", upgraded_pools) + self.assertIn("nodepool1", upgraded_pools) + + def test_aks_upgrade_kubernetes_version_skips_machines_mode_pool(self): + """Machines mode pools must be skipped during Kubernetes version upgrade to avoid a known client-side error.""" + machines_pool = self.models.ManagedClusterAgentPoolProfile(name="machinespool", mode="Machines", type="VirtualMachines") + vmss_pool = self.models.ManagedClusterAgentPoolProfile(name="nodepool1", mode="User", type="VirtualMachineScaleSets") + mc = self.models.ManagedCluster(location="test_location") + mc.agent_pool_profiles = [machines_pool, vmss_pool] + mc.pod_identity_profile = None + mc.kubernetes_version = "1.24.0" + mc.provisioning_state = "Succeeded" + mc.max_agent_pools = 10 + mc.service_principal_profile = None + + self.client.get = mock.Mock(return_value=mc) + self.client.begin_create_or_update = mock.Mock(return_value=None) + + aks_upgrade(self.cmd, self.client, "rg", "name", kubernetes_version="1.25.0", yes=True) + + # Machines mode pool must not have orchestrator_version set; VMSS pool must be upgraded. + self.assertIsNone(machines_pool.orchestrator_version) + self.assertEqual(vmss_pool.orchestrator_version, "1.25.0") + class TestRunCommand(unittest.TestCase): def test_get_command_context_invalid_file(self): From b93849d84f1473ef8600367e5a7b70c660e91316 Mon Sep 17 00:00:00 2001 From: xuexu6666 Date: Wed, 1 Jul 2026 21:51:35 -0500 Subject: [PATCH 2/2] Address review feedback: case-insensitive Machines check, drop manual HISTORY - Make the Machines-mode comparison case-insensitive and None-safe in both the --node-image-only and Kubernetes version upgrade loops (per reviewer). - Remove the manually-added HISTORY.rst entry; the release note is generated from the PR title/description. --- src/azure-cli/HISTORY.rst | 1 - src/azure-cli/azure/cli/command_modules/acs/custom.py | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/azure-cli/HISTORY.rst b/src/azure-cli/HISTORY.rst index 5f60eedfe7f..7bbafa33310 100644 --- a/src/azure-cli/HISTORY.rst +++ b/src/azure-cli/HISTORY.rst @@ -16,7 +16,6 @@ Release History **AKS** -* `az aks upgrade`: Skip Machines mode agent pools during `--node-image-only` and Kubernetes version upgrade, which do not support these operations, instead of surfacing the raw RP OperationNotAllowed error * `az aks nodepool upgrade`: Fix `--max-unavailable` being silently ignored (#33215) * `az aks maintenanceconfiguration add/update`: Add support for maintenanceWindow format in default maintenance configuration (#33431) * `az aks check-acr`: Support national/sovereign clouds where nodes report `cloud=AzureStackCloud` by pointing canipull at the on-node `akscustom.json` environment file (#33551) diff --git a/src/azure-cli/azure/cli/command_modules/acs/custom.py b/src/azure-cli/azure/cli/command_modules/acs/custom.py index 5a89ab7f4f9..bd8c3051d9c 100644 --- a/src/azure-cli/azure/cli/command_modules/acs/custom.py +++ b/src/azure-cli/azure/cli/command_modules/acs/custom.py @@ -1322,7 +1322,7 @@ def aks_upgrade(cmd, raise CLIError('This cluster is using AvailabilitySet. Node image upgrade only operation ' 'can only be applied on VirtualMachineScaleSets or VirtualMachines cluster.') # Skip Machines mode pools to avoid a known client-side error: these pools are containers of individual machines and do not support node image version upgrade. - if agent_pool_profile.mode == CONST_NODEPOOL_MODE_MACHINES: + if (agent_pool_profile.mode or "").lower() == CONST_NODEPOOL_MODE_MACHINES.lower(): logger.warning("Skipping node image upgrade for agent pool '%s': Machines mode pools do not support node image version upgrade.", agent_pool_profile.name) continue agent_pool_client = cf_agent_pools(cmd.cli_ctx) @@ -1387,7 +1387,7 @@ def aks_upgrade(cmd, if upgrade_all: for agent_profile in (instance.agent_pool_profiles or []): # Skip Machines mode pools to avoid a known client-side error: these pools are containers of individual machines and do not support Kubernetes version upgrade. - if agent_profile.mode == CONST_NODEPOOL_MODE_MACHINES: + if (agent_profile.mode or "").lower() == CONST_NODEPOOL_MODE_MACHINES.lower(): logger.warning("Skipping Kubernetes version upgrade for agent pool '%s': Machines mode pools do not support Kubernetes version upgrade.", agent_profile.name) continue agent_profile.orchestrator_version = kubernetes_version