Skip to content

Commit

Permalink
aks-preview-extension: Add --max-unavailablemto the `az aks nodepool …
Browse files Browse the repository at this point in the history
…add/update/upgrade` commands (#8478)
  • Loading branch information
Jenniferyingni authored Feb 25, 2025
1 parent 72332f5 commit d81c74f
Show file tree
Hide file tree
Showing 10 changed files with 1,905 additions and 2 deletions.
4 changes: 4 additions & 0 deletions src/aks-preview/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ If there is no rush to release a new version, please just add a description of t

To release a new version, please select a new version number (usually plus 1 to last patch version, X.Y.Z -> Major.Minor.Patch, more details in `\doc <https://semver.org/>`_), and then add a new section named as the new version number in this file, the content should include the new modifications and everything from the *Pending* section. Finally, update the `VERSION` variable in `setup.py` with this new version number.

13.0.0b7
+++++++
* Add `--max-unavailable` to the `az aks nodepool add/update/upgrade` commands.

13.0.0b6
+++++++
* `az aks create/update`: Update parameter description of `--custom-ca-certificates`.
Expand Down
9 changes: 9 additions & 0 deletions src/aks-preview/azext_aks_preview/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -1775,6 +1775,9 @@
- name: --node-soak-duration
type: int
short-summary: The amount of time (in minutes) to wait after draining a node and before reimaging it and moving on to next node.
- name: --max-unavailable
type: string
short-summary: The maximum number or percentage of nodes that can be simultaneously unavailable during upgrade. When specified, it represents the number or percent used, eg. 1 or 5%
- name: --kubelet-config
type: string
short-summary: Kubelet configurations for agent nodes.
Expand Down Expand Up @@ -1911,6 +1914,9 @@
- name: --node-soak-duration
type: int
short-summary: The amount of time (in minutes) to wait after draining a node and before reimaging it and moving on to next node.
- name: --max-unavailable
type: string
short-summary: The maximum number or percentage of nodes that can be simultaneously unavailable during upgrade. When specified, it represents the number or percent used, eg. 1 or 5%
- name: --aks-custom-headers
type: string
short-summary: Send custom headers. When specified, format should be Key1=Value1,Key2=Value2
Expand Down Expand Up @@ -1960,6 +1966,9 @@
- name: --node-soak-duration
type: int
short-summary: The amount of time (in minutes) to wait after draining a node and before reimaging it and moving on to next node.
- name: --max-unavailable
type: string
short-summary: The maximum number or percentage of nodes that can be simultaneously unavailable during upgrade. When specified, it represents the number or percent used, eg. 1 or 5%
- name: --mode
type: string
short-summary: The mode for a node pool which defines a node pool's primary function. If set as "System", AKS prefers system pods scheduling to node pools with mode `System`. Learn more at https://aka.ms/aks/nodepool/mode.
Expand Down
4 changes: 4 additions & 0 deletions src/aks-preview/azext_aks_preview/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@
validate_custom_endpoints,
validate_bootstrap_container_registry_resource_id,
validate_gateway_prefix_size,
validate_max_unavailable,
)
from azext_aks_preview.azurecontainerstorage._consts import (
CONST_ACSTOR_ALL,
Expand Down Expand Up @@ -1469,6 +1470,7 @@ def load_arguments(self, _):
c.argument("drain_timeout", type=int)
c.argument("node_soak_duration", type=int)
c.argument("undrainable_node_behavior")
c.argument("max_unavailable", validator=validate_max_unavailable)
c.argument("mode", arg_type=get_enum_type(node_mode_types))
c.argument("scale_down_mode", arg_type=get_enum_type(scale_down_modes))
c.argument("max_pods", type=int, options_list=["--max-pods", "-m"])
Expand Down Expand Up @@ -1587,6 +1589,7 @@ def load_arguments(self, _):
c.argument("drain_timeout", type=int)
c.argument("node_soak_duration", type=int)
c.argument("undrainable_node_behavior")
c.argument("max_unavailable", validator=validate_max_unavailable)
c.argument("mode", arg_type=get_enum_type(node_mode_types))
c.argument("scale_down_mode", arg_type=get_enum_type(scale_down_modes))
# extensions
Expand Down Expand Up @@ -1657,6 +1660,7 @@ def load_arguments(self, _):
c.argument("drain_timeout", type=int)
c.argument("node_soak_duration", type=int)
c.argument("undrainable_node_behavior")
c.argument("max_unavailable", validator=validate_max_unavailable)
c.argument("snapshot_id", validator=validate_snapshot_id)
c.argument(
"yes",
Expand Down
16 changes: 16 additions & 0 deletions src/aks-preview/azext_aks_preview/_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,22 @@ def validate_max_surge(namespace):
raise CLIError("--max-surge should be an int or percentage")


def validate_max_unavailable(namespace):
"""validates parameters max unavailable are positive integers or percents."""
if namespace.max_unavailable is None:
return
int_or_percent = namespace.max_unavailable
if int_or_percent.endswith('%'):
int_or_percent = int_or_percent.rstrip('%')

try:
if int(int_or_percent) < 0:
raise CLIError("--max-unavailable must be positive")
except ValueError:
# pylint: disable=raise-missing-from
raise CLIError("--max-unavailable should be an int or percentage")


def validate_assign_identity(namespace):
if namespace.assign_identity is not None:
if namespace.assign_identity == '':
Expand Down
28 changes: 28 additions & 0 deletions src/aks-preview/azext_aks_preview/agentpool_decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,26 @@ def get_undrainable_node_behavior(self) -> str:
# this parameter does not need validation
return undrainable_node_behavior

def get_max_unavailable(self) -> str:
"""Obtain the value of max_unavailable.
:return: string
"""
# read the original value passed by the command
max_unavailable = self.raw_param.get("max_unavailable")
# In create mode, try to read the property value corresponding to the parameter from the `agentpool` object
if self.decorator_mode == DecoratorMode.CREATE:
if (
self.agentpool and
self.agentpool.upgrade_settings and
self.agentpool.upgrade_settings.max_unavailable is not None
):
max_unavailable = self.agentpool.upgrade_settings.max_unavailable

# this parameter does not need dynamic completion
# this parameter does not need validation
return max_unavailable

def get_enable_artifact_streaming(self) -> bool:
"""Obtain the value of enable_artifact_streaming.
:return: bool
Expand Down Expand Up @@ -1042,6 +1062,10 @@ def set_up_upgrade_settings(self, agentpool: AgentPool) -> AgentPool:
if undrainable_node_behavior:
upgrade_settings.undrainable_node_behavior = undrainable_node_behavior

max_unavailable = self.context.get_max_unavailable()
if max_unavailable:
upgrade_settings.max_unavailable = max_unavailable

agentpool.upgrade_settings = upgrade_settings
return agentpool

Expand Down Expand Up @@ -1267,6 +1291,10 @@ def update_upgrade_settings(self, agentpool: AgentPool) -> AgentPool:
upgrade_settings.undrainable_node_behavior = undrainable_node_behavior
agentpool.upgrade_settings = upgrade_settings

max_unavailable = self.context.get_max_unavailable()
if max_unavailable:
upgrade_settings.max_unavailable = max_unavailable

return agentpool

def update_agentpool(self, agentpool: AgentPool) -> AgentPool:
Expand Down
8 changes: 7 additions & 1 deletion src/aks-preview/azext_aks_preview/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -1181,6 +1181,7 @@ def aks_agentpool_add(
drain_timeout=None,
node_soak_duration=None,
undrainable_node_behavior=None,
max_unavailable=None,
mode=CONST_NODEPOOL_MODE_USER,
scale_down_mode=CONST_SCALE_DOWN_MODE_DELETE,
max_pods=0,
Expand Down Expand Up @@ -1262,6 +1263,7 @@ def aks_agentpool_update(
drain_timeout=None,
node_soak_duration=None,
undrainable_node_behavior=None,
max_unavailable=None,
mode=None,
scale_down_mode=None,
no_wait=False,
Expand Down Expand Up @@ -1353,6 +1355,7 @@ def aks_agentpool_upgrade(cmd,
drain_timeout=None,
node_soak_duration=None,
undrainable_node_behavior=None,
max_unavailable=None,
snapshot_id=None,
no_wait=False,
aks_custom_headers=None,
Expand All @@ -1372,7 +1375,8 @@ def aks_agentpool_upgrade(cmd,
)

# Note: we exclude this option because node image upgrade can't accept nodepool put fields like max surge
if (max_surge or drain_timeout or node_soak_duration or undrainable_node_behavior) and node_image_only:
hasUpgradeSetting = max_surge or drain_timeout or node_soak_duration or undrainable_node_behavior or max_unavailable
if hasUpgradeSetting and node_image_only:
raise MutuallyExclusiveArgumentError(
"Conflicting flags. Unable to specify max-surge/drain-timeout/node-soak-duration with node-image-only."
"If you want to use max-surge/drain-timeout/node-soak-duration with a node image upgrade, please first "
Expand Down Expand Up @@ -1437,6 +1441,8 @@ def aks_agentpool_upgrade(cmd,
instance.upgrade_settings.node_soak_duration_in_minutes = node_soak_duration
if undrainable_node_behavior:
instance.upgrade_settings.undrainable_node_behavior = undrainable_node_behavior
if max_unavailable:
instance.upgrade_settings.max_unavailable = max_unavailable

# custom headers
aks_custom_headers = extract_comma_separated_string(
Expand Down
Loading

0 comments on commit d81c74f

Please sign in to comment.