Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/aks-preview/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ To release a new version, please select a new version number (usually plus 1 to

Pending
+++++++
* Add etag support (--if-match, --if-none-match) to some aks commands for optimistic concurrency control.

4.0.0b4
++++++++
Expand Down
40 changes: 40 additions & 0 deletions src/aks-preview/azext_aks_preview/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,12 @@
- name: --bootstrap-container-registry-resource-id
type: string
short-summary: Configure container registry resource ID. Must use "Cache" as bootstrap artifact source.
- name: --if-match
type: string
short-summary: The value provided will be compared to the ETag of the managed cluster, if it matches the operation will proceed. If it does not match, the request will be rejected to prevent accidental overwrites. This must not be specified when creating a new cluster.
- name: --if-none-match
type: string
short-summary: Set to '*' to allow a new cluster to be created, but to prevent updating an existing cluster. Other values will be ignored.
- name: --enable-static-egress-gateway
type: bool
short-summary: Enable Static Egress Gateway addon to the cluster.
Expand Down Expand Up @@ -770,6 +776,12 @@
type: string
short-summary: Until when the cluster upgradeSettings overrides are effective.
long-summary: 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.
- name: --if-match
type: string
short-summary: The value provided will be compared to the ETag of the managed cluster, if it matches the operation will proceed. If it does not match, the request will be rejected to prevent accidental overwrites. This must not be specified when creating a new cluster.
- name: --if-none-match
type: string
short-summary: Set to '*' to allow a new cluster to be created, but to prevent updating an existing cluster. Other values will be ignored.
examples:
- name: Upgrade a existing managed cluster to a managed cluster snapshot.
text: az aks upgrade -g MyResourceGroup -n MyManagedCluster --cluster-snapshot-id "/subscriptions/00000/resourceGroups/AnotherResourceGroup/providers/Microsoft.ContainerService/managedclustersnapshots/mysnapshot1"
Expand Down Expand Up @@ -890,6 +902,12 @@
- name: --aks-custom-headers
type: string
short-summary: Send custom headers. When specified, format should be Key1=Value1,Key2=Value2
- name: --if-match
type: string
short-summary: The value provided will be compared to the ETag of the managed cluster, if it matches the operation will proceed. If it does not match, the request will be rejected to prevent accidental overwrites. This must not be specified when creating a new cluster.
- name: --if-none-match
type: string
short-summary: Set to '*' to allow a new cluster to be created, but to prevent updating an existing cluster. Other values will be ignored.
- name: --auto-upgrade-channel
type: string
short-summary: Specify the upgrade channel for autoupgrade. It could be rapid, stable, patch, node-image or none, none means disable autoupgrade.
Expand Down Expand Up @@ -1831,6 +1849,12 @@
- name: --enable-vtpm
type: bool
short-summary: Enable vTPM on agent node pool. Must use VMSS agent pool type.
- name: --if-match
type: string
short-summary: The value provided will be compared to the ETag of the agentpool, if it matches the operation will proceed. If it does not match, the request will be rejected to prevent accidental overwrites. This must not be specified when creating a new agentpool.
- name: --if-none-match
type: string
short-summary: Set to '*' to allow a new agentpool to be created, but to prevent updating an existing agentpool. Other values will be ignored.
- name: --gateway-prefix-size
type: int
short-summary: The size of Public IPPrefix attached to the Gateway-mode node pool. The node pool must be in Gateway mode.
Expand Down Expand Up @@ -1895,6 +1919,12 @@
- name: --snapshot-id
type: string
short-summary: The source snapshot id used to upgrade this nodepool. Must use VMSS agent pool type.
- name: --if-match
type: string
short-summary: The value provided will be compared to the ETag of the node pool, if it matches the operation will proceed. If it does not match, the request will be rejected to prevent accidental overwrites. This must not be specified when creating a new agentpool. For upgrade node image version requests this will be ignored.
- name: --if-none-match
type: string
short-summary: Set to '*' to allow a new node pool to be created, but to prevent updating an existing node pool. Other values will be ignored.
"""

helps['aks nodepool update'] = """
Expand Down Expand Up @@ -1974,6 +2004,12 @@
- name: --disable-vtpm
type: bool
short-summary: Disable vTPM on an existing Trusted Launch enabled agent node pool.
- name: --if-match
type: string
short-summary: The value provided will be compared to the ETag of the node pool, if it matches the operation will proceed. If it does not match, the request will be rejected to prevent accidental overwrites. This must not be specified when creating a new agentpool.
- name: --if-none-match
type: string
short-summary: Set to '*' to allow a new node pool to be created, but to prevent updating an existing node pool. Other values will be ignored.
examples:
- name: Reconcile the nodepool back to its current state.
text: az aks nodepool update -g MyResourceGroup -n nodepool1 --cluster-name MyManagedCluster
Expand Down Expand Up @@ -2027,6 +2063,10 @@
- name: --ignore-pod-disruption-budget -i
type: bool
short-summary: (PREVIEW) ignore-pod-disruption-budget deletes an existing nodepool without considering Pod Disruption Budget.
- name: --if-match
type: string
short-summary: The value provided will be compared to the ETag of the node pool, if it matches the operation will proceed. If it does not match, the request will be rejected to prevent accidental overwrites. This must not be specified when creating a new agentpool.

examples:
- name: Delete an agent pool with ignore-pod-disruption-budget
text: az aks nodepool delete --resource-group MyResourceGroup --cluster-name MyManagedCluster --name nodepool1 --ignore-pod-disruption-budget=true
Expand Down
9 changes: 9 additions & 0 deletions src/aks-preview/azext_aks_preview/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -931,6 +931,8 @@ def load_arguments(self, _):
is_preview=True,
arg_type=get_enum_type(health_probe_modes),
)
c.argument("if_match")
c.argument("if_none_match")
# virtual machines
c.argument("vm_sizes", is_preview=True)

Expand Down Expand Up @@ -1138,6 +1140,8 @@ def load_arguments(self, _):
action="store_true",
)
c.argument("aks_custom_headers")
c.argument("if_match")
c.argument("if_none_match")
# extensions
# managed cluster
c.argument(
Expand Down Expand Up @@ -1536,6 +1540,8 @@ def load_arguments(self, _):
is_preview=True,
action="store_true"
)
c.argument("if_match")
c.argument("if_none_match")
c.argument(
"gateway_prefix_size",
type=int,
Expand Down Expand Up @@ -1623,6 +1629,8 @@ def load_arguments(self, _):
is_preview=True,
action="store_true"
)
c.argument("if_match")
c.argument("if_none_match")

with self.argument_context("aks nodepool upgrade") as c:
c.argument("max_surge", validator=validate_max_surge)
Expand All @@ -1645,6 +1653,7 @@ def load_arguments(self, _):
is_preview=True,
help="delete an AKS nodepool by ignoring PodDisruptionBudget setting",
)
c.argument("if_match")

with self.argument_context("aks nodepool delete-machines") as c:
c.argument(
Expand Down
66 changes: 64 additions & 2 deletions src/aks-preview/azext_aks_preview/agentpool_decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from typing import Dict, TypeVar, Union, List

from azure.cli.command_modules.acs._consts import AgentPoolDecoratorMode, DecoratorMode, DecoratorEarlyExitException

from azure.cli.command_modules.acs.agentpool_decorator import (
AKSAgentPoolAddDecorator,
AKSAgentPoolContext,
Expand All @@ -23,7 +22,10 @@
)
from azure.cli.core.commands import AzCliCommand
from azure.cli.core.profiles import ResourceType
from azure.cli.core.util import read_file_content
from azure.cli.core.util import (
read_file_content,
sdk_no_wait,
)
from knack.log import get_logger
from knack.prompting import prompt_y_n

Expand Down Expand Up @@ -612,6 +614,20 @@ def get_disable_vtpm(self) -> bool:

return self.raw_param.get("disable_vtpm")

def get_if_match(self) -> str:
"""Obtain the value of if_match.

:return: string
"""
return self.raw_param.get("if_match")

def get_if_none_match(self) -> str:
"""Obtain the value of if_none_match.

:return: string
"""
return self.raw_param.get("if_none_match")

def get_gateway_prefix_size(self) -> Union[int, None]:
"""Obtain the value of gateway_prefix_size.
:return: int or None
Expand Down Expand Up @@ -1128,3 +1144,49 @@ def update_upgrade_settings(self, agentpool: AgentPool) -> AgentPool:
agentpool.upgrade_settings = upgrade_settings

return agentpool

def update_agentpool(self, agentpool: AgentPool) -> AgentPool:
"""Send request to add a new agentpool.

The function "sdk_no_wait" will be called to use the Agentpool operations of ContainerServiceClient to send a
reqeust to update an existing agent pool of the cluster.

:return: the AgentPool object
"""
self._ensure_agentpool(agentpool)

return sdk_no_wait(
self.context.get_no_wait(),
self.client.begin_create_or_update,
self.context.get_resource_group_name(),
self.context.get_cluster_name(),
self.context.get_nodepool_name(),
agentpool,
if_match=self.context.get_if_match(),
if_none_match=self.context.get_if_none_match(),
headers=self.context.get_aks_custom_headers(),
)

# pylint: disable=protected-access
def add_agentpool(self, agentpool: AgentPool) -> AgentPool:
"""Send request to add a new agentpool.

The function "sdk_no_wait" will be called to use the Agentpool operations of ContainerServiceClient to send a
reqeust to add a new agent pool to the cluster.

:return: the AgentPool object
"""
self._ensure_agentpool(agentpool)

return sdk_no_wait(
self.context.get_no_wait(),
self.client.begin_create_or_update,
self.context.get_resource_group_name(),
self.context.get_cluster_name(),
# validated in "init_agentpool", skip to avoid duplicate api calls
self.context._get_nodepool_name(enable_validation=False),
agentpool,
if_match=self.context.get_if_match(),
if_none_match=self.context.get_if_none_match(),
headers=self.context.get_aks_custom_headers(),
)
32 changes: 28 additions & 4 deletions src/aks-preview/azext_aks_preview/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,8 @@ def aks_create(
enable_secure_boot=False,
enable_vtpm=False,
cluster_service_load_balancer_health_probe_mode=None,
if_match=None,
if_none_match=None,
# Static Egress Gateway
enable_static_egress_gateway=False,
# virtualmachines
Expand Down Expand Up @@ -849,6 +851,8 @@ def aks_update(
node_provisioning_mode=None,
ssh_access=None,
cluster_service_load_balancer_health_probe_mode=None,
if_match=None,
if_none_match=None,
# Static Egress Gateway
enable_static_egress_gateway=False,
disable_static_egress_gateway=False,
Expand Down Expand Up @@ -1048,7 +1052,9 @@ def aks_upgrade(cmd,
enable_force_upgrade=False,
disable_force_upgrade=False,
upgrade_override_until=None,
yes=False):
yes=False,
if_match=None,
if_none_match=None):
msg = 'Kubernetes may be unavailable during cluster upgrades.\n Are you sure you want to perform this operation?'
if not yes and not prompt_y_n(msg, default="n"):
return None
Expand Down Expand Up @@ -1152,7 +1158,15 @@ def aks_upgrade(cmd,

headers = get_aks_custom_headers(aks_custom_headers)

return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, name, instance, headers=headers)
return sdk_no_wait(
no_wait,
client.begin_create_or_update,
resource_group_name,
name,
instance,
headers=headers,
if_match=if_match,
if_none_match=if_none_match)


def _update_upgrade_settings(cmd, instance,
Expand Down Expand Up @@ -1303,6 +1317,8 @@ def aks_agentpool_add(
# trusted launch
enable_secure_boot=False,
enable_vtpm=False,
if_match=None,
if_none_match=None,
# static egress gateway - gateway-mode pool
gateway_prefix_size=None,
# virtualmachines
Expand Down Expand Up @@ -1367,6 +1383,8 @@ def aks_agentpool_update(
disable_secure_boot=False,
enable_vtpm=False,
disable_vtpm=False,
if_match=None,
if_none_match=None,
):
# DO NOT MOVE: get all the original parameters and save them as a dictionary
raw_parameters = locals()
Expand Down Expand Up @@ -1438,7 +1456,9 @@ def aks_agentpool_upgrade(cmd,
snapshot_id=None,
no_wait=False,
aks_custom_headers=None,
yes=False):
yes=False,
if_match=None,
if_none_match=None):
AgentPoolUpgradeSettings = cmd.get_models(
"AgentPoolUpgradeSettings",
resource_type=CUSTOM_MGMT_AKS_PREVIEW,
Expand Down Expand Up @@ -1533,6 +1553,8 @@ def aks_agentpool_upgrade(cmd,
nodepool_name,
instance,
headers=aks_custom_headers,
if_match=if_match,
if_none_match=if_none_match,
)


Expand Down Expand Up @@ -1628,7 +1650,8 @@ def aks_agentpool_delete(cmd, # pylint: disable=unused-argument
cluster_name,
nodepool_name,
ignore_pod_disruption_budget=None,
no_wait=False):
no_wait=False,
if_match=None):
agentpool_exists = False
instances = client.list(resource_group_name, cluster_name)
for agentpool_profile in instances:
Expand All @@ -1648,6 +1671,7 @@ def aks_agentpool_delete(cmd, # pylint: disable=unused-argument
resource_group_name,
cluster_name,
nodepool_name,
if_match=if_match,
ignore_pod_disruption_budget=ignore_pod_disruption_budget,
)

Expand Down
46 changes: 46 additions & 0 deletions src/aks-preview/azext_aks_preview/managed_cluster_decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@
RequiredArgumentMissingError,
UnknownError,
)
from azure.cli.core.util import sdk_no_wait
from azure.cli.core.commands import LongRunningOperation
from azure.cli.core.commands import AzCliCommand
from azure.cli.core.profiles import ResourceType
from azure.cli.core.util import get_file_json, read_file_content
Expand Down Expand Up @@ -886,6 +888,22 @@ def get_upgrade_override_until(self) -> Union[str, None]:
# this parameter does not need validation
return self.raw_param.get("upgrade_override_until")

def get_if_match(self) -> Union[str, None]:
"""Obtain the value of if_match.
:return: string or None
"""
# this parameter does not need dynamic completion
# this parameter does not need validation
return self.raw_param.get("if_match")

def get_if_none_match(self) -> Union[str, None]:
"""Obtain the value of if_none_match.
:return: string or None
"""
# this parameter does not need dynamic completion
# this parameter does not need validation
return self.raw_param.get("if_none_match")

def get_force_upgrade(self) -> Union[bool, None]:
"""Obtain the value of force_upgrade.
:return: bool or None
Expand Down Expand Up @@ -5438,3 +5456,31 @@ def postprocessing_after_mc_created(self, cluster: ManagedCluster) -> None:
raise CLIError('App Routing must be enabled to attach keyvault.\n')
else:
raise CLIError('Keyvault secrets provider addon must be enabled to attach keyvault.\n')

def put_mc(self, mc: ManagedCluster) -> ManagedCluster:
if self.check_is_postprocessing_required(mc):
# send request
poller = self.client.begin_create_or_update(
resource_group_name=self.context.get_resource_group_name(),
resource_name=self.context.get_name(),
parameters=mc,
if_match=self.context.get_if_match(),
if_none_match=self.context.get_if_none_match(),
headers=self.context.get_aks_custom_headers(),
)
self.immediate_processing_after_request(mc)
# poll until the result is returned
cluster = LongRunningOperation(self.cmd.cli_ctx)(poller)
self.postprocessing_after_mc_created(cluster)
else:
cluster = sdk_no_wait(
self.context.get_no_wait(),
self.client.begin_create_or_update,
resource_group_name=self.context.get_resource_group_name(),
resource_name=self.context.get_name(),
parameters=mc,
if_match=self.context.get_if_match(),
if_none_match=self.context.get_if_none_match(),
headers=self.context.get_aks_custom_headers(),
)
return cluster
Loading