Skip to content

Commit 0877d22

Browse files
Xinyue-Wangclaude
andauthored
{AKS} Add --enable-upgrade-gate/--disable-upgrade-gate to aks-preview (#10448)
* {AKS} Add `--enable-upgrade-gate`/`--disable-upgrade-gate` to aks-preview Add upgrade gate (health-aware upgrade) flags for the 2026-07-02-preview API: - `az aks create`: `--enable-upgrade-gate` - `az aks update`: `--enable-upgrade-gate` / `--disable-upgrade-gate` - `az aks nodepool add/update`: `--enable-upgrade-gate` / `--disable-upgrade-gate` The flags set `upgradeSettings.upgradeGateSettings.enabled` on the managed cluster and agent pool respectively. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * {AKS} Validate --enable-upgrade-gate/--disable-upgrade-gate at parse time ManagedSystem and Machines node pools return from construct_agentpool_profile_preview before the upgrade gate getter runs, so passing both flags was silently accepted. Add a parser-level validator, mirroring the force-upgrade flags, so the pair is mutually exclusive on every code path for `aks update` and `aks nodepool add/update`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1 parent a56510b commit 0877d22

11 files changed

Lines changed: 634 additions & 2 deletions

‎src/aks-preview/HISTORY.rst‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ To release a new version, please select a new version number (usually plus 1 to
1111

1212
Pending
1313
+++++++
14+
* `az aks create`: Add `--enable-upgrade-gate` to enable health-aware upgrade gating for the cluster.
15+
* `az aks update`: Add `--enable-upgrade-gate` and `--disable-upgrade-gate` to enable or disable health-aware upgrade gating for the cluster.
16+
* `az aks nodepool add/update`: Add `--enable-upgrade-gate` and `--disable-upgrade-gate` to enable or disable health-aware upgrade gating for the node pool.
1417

1518
22.0.0b13
1619
+++++++++

‎src/aks-preview/azext_aks_preview/_help.py‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,7 +794,13 @@
794794
Provides scaled and performance-guaranteed control plane capacity for AKS clusters.
795795
Enables customers to select a control plane scaling size that delivers higher API server throughput,
796796
increased etcd capacity, and faster pod scheduling rates. Available values are 'H2', 'H4', and 'H8'.
797+
- name: --enable-upgrade-gate
798+
type: bool
799+
short-summary: Enable upgrade gate for the cluster. Agent pool upgrades wait for health signal validation and abort if unhealthy signals are observed.
800+
long-summary: This is a cluster-wide opt-in that applies to all agent pools in the cluster; an agent pool cannot opt out of it. Health signals are HealthSignal custom resources published by monitoring components running in the cluster. Force upgrade (--enable-force-upgrade) overrides the gate. For more information, see https://aka.ms/aks/upgrade-gate.
797801
examples:
802+
- name: Create a kubernetes cluster with upgrade gate enabled.
803+
text: az aks create -g MyResourceGroup -n MyManagedCluster --enable-upgrade-gate
798804
- name: Create a Kubernetes cluster with an existing SSH public key.
799805
text: az aks create -g MyResourceGroup -n MyManagedCluster --ssh-key-value /path/to/publickey
800806
- name: Create a Kubernetes cluster with a specific version.
@@ -1120,6 +1126,14 @@
11201126
- name: --upgrade-override-until
11211127
type: string
11221128
short-summary: Until when the cluster upgradeSettings overrides are effective. It needs to be in a valid date-time format that's within the next 30 days. For example, 2023-04-01T13:00:00Z. Note that if --force-upgrade is set to true and --upgrade-override-until is not set, by default it will be set to 3 days from now.
1129+
- name: --enable-upgrade-gate
1130+
type: bool
1131+
short-summary: Enable upgrade gate for the cluster. Agent pool upgrades wait for health signal validation and abort if unhealthy signals are observed.
1132+
long-summary: This is a cluster-wide opt-in that applies to all agent pools in the cluster; an agent pool cannot opt out of it. Health signals are HealthSignal custom resources published by monitoring components running in the cluster. Force upgrade (--enable-force-upgrade) overrides the gate. For more information, see https://aka.ms/aks/upgrade-gate.
1133+
- name: --disable-upgrade-gate
1134+
type: bool
1135+
short-summary: Disable upgrade gate for the cluster.
1136+
long-summary: Agent pools that explicitly enabled upgrade gate keep their own setting and remain gated.
11231137
- name: --enable-managed-identity
11241138
type: bool
11251139
short-summary: Update current cluster to managed identity to manage cluster resource group.
@@ -1655,6 +1669,8 @@
16551669
examples:
16561670
- name: Reconcile the cluster back to its current state.
16571671
text: az aks update -g MyResourceGroup -n MyManagedCluster
1672+
- name: Enable upgrade gate for a kubernetes cluster.
1673+
text: az aks update -g MyResourceGroup -n MyManagedCluster --enable-upgrade-gate
16581674
- name: Enable cluster-autoscaler within node count range [1,5]
16591675
text: az aks update --enable-cluster-autoscaler --min-count 1 --max-count 5 -g MyResourceGroup -n MyManagedCluster
16601676
- name: Disable cluster-autoscaler for an existing cluster
@@ -2701,6 +2717,14 @@
27012717
- name: --final-soak-duration
27022718
type: int
27032719
short-summary: Wait time (in minutes) after all old nodes are drained before removing them. Default is 60 minutes. Only for blue-green upgrades.
2720+
- name: --enable-upgrade-gate
2721+
type: bool
2722+
short-summary: Enable upgrade gate for the node pool. Upgrades of this node pool wait for health signal validation and abort if unhealthy signals are observed.
2723+
long-summary: When the cluster-level upgrade gate is enabled, a new node pool inherits it by default. Health signals are HealthSignal custom resources published by monitoring components running in the cluster. Force upgrade (--enable-force-upgrade) overrides the gate. For more information, see https://aka.ms/aks/upgrade-gate.
2724+
- name: --disable-upgrade-gate
2725+
type: bool
2726+
short-summary: Disable upgrade gate for the node pool.
2727+
long-summary: Rejected by the service when the cluster-level upgrade gate is enabled, since a node pool cannot opt out of a cluster-wide opt-in.
27042728
examples:
27052729
- name: Create a nodepool in an existing AKS cluster with ephemeral os enabled.
27062730
text: az aks nodepool add -g MyResourceGroup -n nodepool1 --cluster-name MyManagedCluster --node-osdisk-type Ephemeral --node-osdisk-size 48
@@ -2728,6 +2752,8 @@
27282752
text: az aks nodepool add -g MyResourceGroup -n nodepool1 --cluster-name MyManagedCluster --upgrade-strategy BlueGreen
27292753
- name: Create a node pool with an ordered mixed MIG profile layout
27302754
text: az aks nodepool add -g MyResourceGroup -n nodepool1 --cluster-name MyManagedCluster --enable-managed-gpu --gpu-mig-strategy Mixed --gpu-mig-profiles MIG1g MIG2g MIG2g MIG2g
2755+
- name: Create a node pool with upgrade gate enabled
2756+
text: az aks nodepool add -g MyResourceGroup -n nodepool1 --cluster-name MyManagedCluster --enable-upgrade-gate
27312757
"""
27322758

27332759
helps['aks nodepool scale'] = """
@@ -2943,13 +2969,23 @@
29432969
- name: --crg-id
29442970
type: string
29452971
short-summary: The Capacity Reservation Group (CRG) ID used to associate the existing nodepool with the existing Capacity Reservation Group resource.
2972+
- name: --enable-upgrade-gate
2973+
type: bool
2974+
short-summary: Enable upgrade gate for the node pool. Upgrades of this node pool wait for health signal validation and abort if unhealthy signals are observed.
2975+
long-summary: Health signals are HealthSignal custom resources published by monitoring components running in the cluster. Force upgrade (--enable-force-upgrade) overrides the gate. For more information, see https://aka.ms/aks/upgrade-gate.
2976+
- name: --disable-upgrade-gate
2977+
type: bool
2978+
short-summary: Disable upgrade gate for the node pool.
2979+
long-summary: Rejected by the service when the cluster-level upgrade gate is enabled, since a node pool cannot opt out of a cluster-wide opt-in. Use 'az aks update --disable-upgrade-gate' instead.
29462980
- name: --node-public-ip-prefix-ids
29472981
type: string
29482982
short-summary: Comma-separated list of public IP prefix resource IDs for dual-stack node public IPs (IPv4 and/or IPv6).
29492983
long-summary: At most one IPv4 and one IPv6 prefix may be specified. On an existing node pool this adds or replaces the assigned prefixes; an accepted change rolls the pool so existing nodes are recreated with the new public IPs. Requires the NodePublicIPv6PrefixPreview feature flag.
29502984
examples:
29512985
- name: Reconcile the nodepool back to its current state.
29522986
text: az aks nodepool update -g MyResourceGroup -n nodepool1 --cluster-name MyManagedCluster
2987+
- name: Enable upgrade gate for a node pool.
2988+
text: az aks nodepool update -g MyResourceGroup -n nodepool1 --cluster-name MyManagedCluster --enable-upgrade-gate
29532989
- name: Enable cluster-autoscaler within node count range [1,5]
29542990
text: az aks nodepool update --enable-cluster-autoscaler --min-count 1 --max-count 5 -g MyResourceGroup -n nodepool1 --cluster-name MyManagedCluster
29552991
- name: Disable cluster-autoscaler for an existing cluster

‎src/aks-preview/azext_aks_preview/_params.py‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@
257257
validate_system_node_subnet_id,
258258
validate_node_subnet_id,
259259
validate_force_upgrade_disable_and_enable_parameters,
260+
validate_upgrade_gate_disable_and_enable_parameters,
260261
validate_azure_service_mesh_revision,
261262
validate_artifact_streaming,
262263
validate_os_disk_full_caching,
@@ -1478,6 +1479,8 @@ def load_arguments(self, _):
14781479
help='The resource ID of the prepared image specification to use for provisioning nodes in the default '
14791480
'node pool.'
14801481
)
1482+
# upgrade gate
1483+
c.argument("enable_upgrade_gate", action="store_true", is_preview=True)
14811484

14821485
with self.argument_context("aks update") as c:
14831486
# managed cluster paramerters
@@ -1584,6 +1587,19 @@ def load_arguments(self, _):
15841587
validator=validate_force_upgrade_disable_and_enable_parameters,
15851588
)
15861589
c.argument("upgrade_override_until", is_preview=True)
1590+
# upgrade gate
1591+
c.argument(
1592+
"enable_upgrade_gate",
1593+
action="store_true",
1594+
is_preview=True,
1595+
validator=validate_upgrade_gate_disable_and_enable_parameters,
1596+
)
1597+
c.argument(
1598+
"disable_upgrade_gate",
1599+
action="store_true",
1600+
is_preview=True,
1601+
validator=validate_upgrade_gate_disable_and_enable_parameters,
1602+
)
15871603
c.argument(
15881604
"cluster_autoscaler_profile",
15891605
nargs="+",
@@ -2578,6 +2594,19 @@ def load_arguments(self, _):
25782594
validator=validate_prepared_image_specification_id,
25792595
help='The resource ID of the prepared image specification to use for provisioning nodes in the node pool.'
25802596
)
2597+
# upgrade gate
2598+
c.argument(
2599+
"enable_upgrade_gate",
2600+
action="store_true",
2601+
is_preview=True,
2602+
validator=validate_upgrade_gate_disable_and_enable_parameters,
2603+
)
2604+
c.argument(
2605+
"disable_upgrade_gate",
2606+
action="store_true",
2607+
is_preview=True,
2608+
validator=validate_upgrade_gate_disable_and_enable_parameters,
2609+
)
25812610

25822611
with self.argument_context("aks nodepool update") as c:
25832612
c.argument(
@@ -2746,6 +2775,19 @@ def load_arguments(self, _):
27462775
validator=validate_prepared_image_specification_id,
27472776
help='The resource ID of the prepared image specification to use for provisioning nodes in the node pool.'
27482777
)
2778+
# upgrade gate
2779+
c.argument(
2780+
"enable_upgrade_gate",
2781+
action="store_true",
2782+
is_preview=True,
2783+
validator=validate_upgrade_gate_disable_and_enable_parameters,
2784+
)
2785+
c.argument(
2786+
"disable_upgrade_gate",
2787+
action="store_true",
2788+
is_preview=True,
2789+
validator=validate_upgrade_gate_disable_and_enable_parameters,
2790+
)
27492791

27502792
with self.argument_context("aks nodepool upgrade") as c:
27512793
# upgrade strategy

‎src/aks-preview/azext_aks_preview/_validators.py‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,13 @@ def validate_force_upgrade_disable_and_enable_parameters(namespace):
859859
)
860860

861861

862+
def validate_upgrade_gate_disable_and_enable_parameters(namespace):
863+
if namespace.disable_upgrade_gate and namespace.enable_upgrade_gate:
864+
raise MutuallyExclusiveArgumentError(
865+
'Providing both --disable-upgrade-gate and --enable-upgrade-gate flags is invalid'
866+
)
867+
868+
862869
def sanitize_resource_id(resource_id):
863870
resource_id = resource_id.strip()
864871
if not resource_id.startswith("/"):

‎src/aks-preview/azext_aks_preview/agentpool_decorator.py‎

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,30 @@ def get_max_blocked_nodes(self) -> str:
620620
# this parameter does not need validation
621621
return max_blocked_nodes
622622

623+
def get_upgrade_gate_enabled(self) -> Union[bool, None]:
624+
"""Obtain the agent pool upgrade gate setting from --enable-upgrade-gate / --disable-upgrade-gate.
625+
626+
Only applies to standalone agent pool commands; in managed cluster mode (e.g. `az aks create`), the flags
627+
target the cluster-level setting and the server defaults new pools accordingly.
628+
629+
:return: True if enabling, False if disabling, None if neither flag is specified
630+
"""
631+
if self.agentpool_decorator_mode != AgentPoolDecoratorMode.STANDALONE:
632+
return None
633+
634+
enable_upgrade_gate = self.raw_param.get("enable_upgrade_gate")
635+
disable_upgrade_gate = self.raw_param.get("disable_upgrade_gate")
636+
637+
if enable_upgrade_gate and disable_upgrade_gate:
638+
raise MutuallyExclusiveArgumentError(
639+
"Cannot specify --enable-upgrade-gate and --disable-upgrade-gate at the same time."
640+
)
641+
if enable_upgrade_gate:
642+
return True
643+
if disable_upgrade_gate:
644+
return False
645+
return None
646+
623647
def get_enable_artifact_streaming(self) -> bool:
624648
"""Obtain the value of enable_artifact_streaming.
625649
:return: bool
@@ -1847,6 +1871,8 @@ def construct_agentpool_profile_preview(self) -> AgentPool:
18471871
agentpool = self.set_up_upgrade_strategy(agentpool)
18481872
# set up blue green upgrade settings
18491873
agentpool = self.set_up_blue_green_upgrade_settings(agentpool)
1874+
# set up upgrade gate settings
1875+
agentpool = self.set_up_upgrade_gate_settings(agentpool)
18501876
# set up prepared image specification
18511877
agentpool = self.set_up_prepared_image_specification(agentpool)
18521878
# DO NOT MOVE: keep this at the bottom, restore defaults
@@ -1905,6 +1931,22 @@ def set_up_upgrade_settings(self, agentpool: AgentPool) -> AgentPool:
19051931
agentpool.upgrade_settings = upgrade_settings
19061932
return agentpool
19071933

1934+
def set_up_upgrade_gate_settings(self, agentpool: AgentPool) -> AgentPool:
1935+
"""Set up upgrade gate settings for the AgentPool object.
1936+
1937+
:return: the AgentPool object
1938+
"""
1939+
self._ensure_agentpool(agentpool)
1940+
1941+
upgrade_gate_enabled = self.context.get_upgrade_gate_enabled()
1942+
if upgrade_gate_enabled is not None:
1943+
if agentpool.upgrade_settings is None:
1944+
agentpool.upgrade_settings = self.models.AgentPoolUpgradeSettings() # pylint: disable=no-member
1945+
agentpool.upgrade_settings.upgrade_gate_settings = (
1946+
self.models.UpgradeGateSettings(enabled=upgrade_gate_enabled) # pylint: disable=no-member
1947+
)
1948+
return agentpool
1949+
19081950
def set_up_blue_green_upgrade_settings(self, agentpool: AgentPool) -> AgentPool:
19091951
"""Set up blue-green upgrade settings for the AgentPool object.
19101952
@@ -2337,6 +2379,9 @@ def update_agentpool_profile_preview(self, agentpools: List[AgentPool] = None) -
23372379
# update blue-green upgrade settings
23382380
agentpool = self.update_blue_green_upgrade_settings(agentpool)
23392381

2382+
# update upgrade gate settings
2383+
agentpool = self.update_upgrade_gate_settings(agentpool)
2384+
23402385
# update gpu profile
23412386
agentpool = self.update_gpu_profile(agentpool)
23422387

@@ -2515,6 +2560,24 @@ def update_upgrade_settings(self, agentpool: AgentPool) -> AgentPool:
25152560

25162561
return agentpool
25172562

2563+
def update_upgrade_gate_settings(self, agentpool: AgentPool) -> AgentPool:
2564+
"""Update upgrade gate settings for the AgentPool object.
2565+
2566+
:return: the AgentPool object
2567+
"""
2568+
self._ensure_agentpool(agentpool)
2569+
2570+
upgrade_gate_enabled = self.context.get_upgrade_gate_enabled()
2571+
if upgrade_gate_enabled is not None:
2572+
if agentpool.upgrade_settings is None:
2573+
agentpool.upgrade_settings = self.models.AgentPoolUpgradeSettings() # pylint: disable=no-member
2574+
if agentpool.upgrade_settings.upgrade_gate_settings is None:
2575+
agentpool.upgrade_settings.upgrade_gate_settings = (
2576+
self.models.UpgradeGateSettings() # pylint: disable=no-member
2577+
)
2578+
agentpool.upgrade_settings.upgrade_gate_settings.enabled = upgrade_gate_enabled
2579+
return agentpool
2580+
25182581
def update_blue_green_upgrade_settings(self, agentpool: AgentPool) -> AgentPool:
25192582
"""Update blue-green upgrade settings for the AgentPool object.
25202583

‎src/aks-preview/azext_aks_preview/custom.py‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1487,6 +1487,8 @@ def aks_create(
14871487
enable_on_demand_monitor=False,
14881488
# prepared image specification
14891489
prepared_image_specification_id=None,
1490+
# upgrade gate
1491+
enable_upgrade_gate=False,
14901492
):
14911493
# DO NOT MOVE: get all the original parameters and save them as a dictionary
14921494
raw_parameters = locals()
@@ -1555,6 +1557,9 @@ def aks_update(
15551557
enable_force_upgrade=False,
15561558
disable_force_upgrade=False,
15571559
upgrade_override_until=None,
1560+
# upgrade gate
1561+
enable_upgrade_gate=False,
1562+
disable_upgrade_gate=False,
15581563
cluster_autoscaler_profile=None,
15591564
sku=None,
15601565
tier=None,
@@ -2344,6 +2349,9 @@ def aks_agentpool_add(
23442349
secondary_network_interfaces=None,
23452350
# prepared image specification
23462351
prepared_image_specification_id=None,
2352+
# upgrade gate
2353+
enable_upgrade_gate=False,
2354+
disable_upgrade_gate=False,
23472355
):
23482356
# DO NOT MOVE: get all the original parameters and save them as a dictionary
23492357
raw_parameters = locals()
@@ -2434,6 +2442,9 @@ def aks_agentpool_update(
24342442
crg_id=None,
24352443
# prepared image specification
24362444
prepared_image_specification_id=None,
2445+
# upgrade gate
2446+
enable_upgrade_gate=False,
2447+
disable_upgrade_gate=False,
24372448
):
24382449
# DO NOT MOVE: get all the original parameters and save them as a dictionary
24392450
raw_parameters = locals()

0 commit comments

Comments
 (0)