Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AKS] Add Etags in AKS CLI #30309

Merged
merged 24 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
ab78b37
Etags in AKS CLI
Nov 12, 2024
48e5afe
Update src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_…
InduSridhar Nov 12, 2024
34c14c0
Update src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_…
InduSridhar Nov 12, 2024
9504b90
Update src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_…
InduSridhar Nov 12, 2024
ecc14eb
Update src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_…
InduSridhar Nov 12, 2024
2263342
Update src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_…
InduSridhar Nov 12, 2024
46dd5ed
Add etag headers to put_mc
Nov 12, 2024
22a648e
Add etags headers for put_mc for create
Nov 12, 2024
6687e29
change create command etag header
Nov 12, 2024
8ade20d
change create nodepool etag header
Nov 20, 2024
66858b2
Merge branch 'dev' into etags-aks-cli
InduSridhar Nov 25, 2024
3a2b0d7
Supporting old api version
Dec 4, 2024
41cbf48
Merge branch 'etags-aks-cli' of https://github.com/InduSridhar/azure-…
Dec 4, 2024
102647f
Merge branch 'dev' into etags-aks-cli
InduSridhar Dec 4, 2024
fe62b35
Fixing lint issues and adding tests
Dec 4, 2024
13e6da1
Merge branch 'etags-aks-cli' of https://github.com/InduSridhar/azure-…
Dec 4, 2024
167e182
Lint fix
Dec 5, 2024
3a0ff85
Solving for old api version
Dec 9, 2024
f97925a
Fix CLI live tests
Dec 12, 2024
b124464
Adding latest check for nodepool delete
Dec 16, 2024
44e1817
Fix tests for getters for ifmatch and ifnonematch
Dec 18, 2024
fc13ea0
Changing test names to avoid recursion
Dec 19, 2024
de60b06
Update src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_…
InduSridhar Dec 20, 2024
518e9c6
Update src/azure-cli/azure/cli/command_modules/acs/tests/latest/test_…
InduSridhar Dec 20, 2024
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
36 changes: 36 additions & 0 deletions src/azure-cli/azure/cli/command_modules/acs/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,12 @@
- name: --enable-vtpm
type: bool
short-summary: Enable vTPM on all node pools in the cluster. Must use VMSS agent pool type.
- 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: Create a Kubernetes cluster with an existing SSH public key.
Expand Down Expand Up @@ -943,6 +949,12 @@
- name: --disable-cost-analysis
type: bool
short-summary: Disable exporting Kubernetes Namespace and Deployment details to the Cost Analysis views in the Azure portal.
- 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: Reconcile the cluster back to its current state.
Expand Down Expand Up @@ -1591,6 +1603,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.

examples:
- name: Create a nodepool in an existing AKS cluster with ephemeral os enabled.
Expand Down Expand Up @@ -1715,6 +1733,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 @@ -1751,6 +1775,12 @@
- name: --aks-custom-headers
type: string
short-summary: Comma-separated key-value pairs to specify custom headers.
- 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 stop'] = """
Expand Down Expand Up @@ -1919,6 +1949,12 @@
- name: --tier
type: string
short-summary: Specify SKU tier for managed clusters. '--tier standard' enables a standard managed cluster service with a financially backed SLA. '--tier free' does not have a financially backed SLA. '--tier premium' is required for '--k8s-support-plan AKSLongTermSupport'.
- 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 managed Kubernetes cluster to a newer version. (autogenerated)
Expand Down
8 changes: 8 additions & 0 deletions src/azure-cli/azure/cli/command_modules/acs/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,8 @@ def load_arguments(self, _):
c.argument('enable_cost_analysis', action='store_true')
c.argument('enable_vtpm', action="store_true")
c.argument('enable_secure_boot', action="store_true")
c.argument("if_match")
c.argument("if_none_match")

with self.argument_context('aks update') as c:
# managed cluster paramerters
Expand Down Expand Up @@ -610,6 +612,8 @@ def load_arguments(self, _):
c.argument('yes', options_list=['--yes', '-y'], help='Do not prompt for confirmation.', action='store_true')
c.argument('enable_cost_analysis', action='store_true')
c.argument('disable_cost_analysis', action='store_true')
c.argument("if_match")
c.argument("if_none_match")

with self.argument_context('aks disable-addons', resource_type=ResourceType.MGMT_CONTAINERSERVICE, operation_group='managed_clusters') as c:
c.argument('addons', options_list=['--addons', '-a'])
Expand Down Expand Up @@ -763,6 +767,8 @@ def load_arguments(self, _):
help='space-separated tags: key[=value] [key[=value] ...].')
c.argument('enable_vtpm', action='store_true')
c.argument('enable_secure_boot', action='store_true')
c.argument("if_match")
c.argument("if_none_match")

with self.argument_context('aks nodepool update', resource_type=ResourceType.MGMT_CONTAINERSERVICE, operation_group='agent_pools') as c:
c.argument('enable_cluster_autoscaler', options_list=[
Expand Down Expand Up @@ -790,6 +796,8 @@ def load_arguments(self, _):
c.argument('disable_vtpm', action='store_true')
c.argument('enable_secure_boot', action='store_true')
c.argument('disable_secure_boot', 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 Down
Original file line number Diff line number Diff line change
Expand Up @@ -1504,6 +1504,19 @@ def get_disable_windows_outbound_nat(self) -> bool:
"""
return self._get_disable_windows_outbound_nat()

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")

class AKSAgentPoolAddDecorator:
def __init__(
Expand Down Expand Up @@ -1924,6 +1937,8 @@ def add_agentpool(self, agentpool: AgentPool) -> AgentPool:
# 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(),
)

Expand Down Expand Up @@ -2228,5 +2243,7 @@ def update_agentpool(self, agentpool: AgentPool) -> AgentPool:
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(),
InduSridhar marked this conversation as resolved.
Show resolved Hide resolved
headers=self.context.get_aks_custom_headers(),
)
27 changes: 22 additions & 5 deletions src/azure-cli/azure/cli/command_modules/acs/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,8 @@ def aks_create(
no_wait=False,
aks_custom_headers=None,
node_public_ip_tags=None,
if_match=None,
if_none_match=None,
# metrics profile
enable_cost_analysis=False,
# trusted launch
Expand Down Expand Up @@ -788,6 +790,8 @@ def aks_update(
yes=False,
no_wait=False,
aks_custom_headers=None,
if_match=None,
if_none_match=None,
# metrics profile
enable_cost_analysis=False,
disable_cost_analysis=False,
Expand Down Expand Up @@ -826,7 +830,9 @@ def aks_upgrade(cmd,
upgrade_override_until=None,
tier=None,
k8s_support_plan=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 @@ -919,7 +925,7 @@ def aks_upgrade(cmd,
# null out the SP profile because otherwise validation complains
instance.service_principal_profile = None

return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, name, instance)
return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, name, instance, if_match=if_match, if_none_match=if_none_match)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add workaround for the old cloud profile



def _update_upgrade_settings(cmd, instance,
Expand Down Expand Up @@ -2339,6 +2345,9 @@ def aks_agentpool_add(
# trusted launch
enable_vtpm=False,
enable_secure_boot=False,
# etag headers
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 @@ -2394,6 +2403,9 @@ def aks_agentpool_update(
disable_vtpm=False,
enable_secure_boot=False,
disable_secure_boot=False,
# etag headers
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 @@ -2432,7 +2444,9 @@ def aks_agentpool_upgrade(cmd, client, resource_group_name, cluster_name,
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=ResourceType.MGMT_CONTAINERSERVICE,
Expand Down Expand Up @@ -2519,6 +2533,8 @@ def aks_agentpool_upgrade(cmd, client, resource_group_name, cluster_name,
nodepool_name,
instance,
headers=aks_custom_headers,
if_match=if_match,
if_none_match=if_none_match,
)


Expand Down Expand Up @@ -2592,7 +2608,8 @@ def aks_agentpool_stop(cmd, # pylint: disable=unused-argument

def aks_agentpool_delete(cmd, client, resource_group_name, cluster_name,
nodepool_name,
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 @@ -2604,7 +2621,7 @@ def aks_agentpool_delete(cmd, client, resource_group_name, cluster_name,
raise CLIError("Node pool {} doesnt exist, "
"use 'aks nodepool list' to get current node pool list".format(nodepool_name))

return sdk_no_wait(no_wait, client.begin_delete, resource_group_name, cluster_name, nodepool_name)
return sdk_no_wait(no_wait, client.begin_delete, resource_group_name, cluster_name, nodepool_name, if_match=if_match)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add workaround for the old cloud profile



def aks_agentpool_operation_abort(cmd,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5178,6 +5178,21 @@ def get_disable_cost_analysis(self) -> bool:
# because it's already checked in _get_enable_cost_analysis
return self.raw_param.get("disable_cost_analysis")

def get_if_match(self) -> Union[str, None]:
InduSridhar marked this conversation as resolved.
Show resolved Hide resolved
"""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")

class AKSManagedClusterCreateDecorator(BaseAKSManagedClusterDecorator):
def __init__(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1787,12 +1787,14 @@ def test_aks_nodepool_create_scale_delete(self, resource_group, resource_group_l
'new_tags': new_tags,
'labels': labels,
'nodepool1_name': nodepool1_name,
'nodepool2_name': nodepool2_name
'nodepool2_name': nodepool2_name,
'if_match': '*',
'if_none_match': '*',
})

# create
create_cmd = 'aks create --resource-group={resource_group} --name={name} --location={location} ' \
'--dns-name-prefix={dns_name_prefix} --node-count=1 --ssh-key-value={ssh_key_value} ' \
'--dns-name-prefix={dns_name_prefix} --node-count=1 --ssh-key-value={ssh_key_value} --if-none_match={if_none_match}' \
InduSridhar marked this conversation as resolved.
Show resolved Hide resolved
'--service-principal={service_principal} --client-secret={client_secret}'
self.cmd(create_cmd, checks=[
self.exists('fqdn'),
Expand Down Expand Up @@ -1826,7 +1828,7 @@ def test_aks_nodepool_create_scale_delete(self, resource_group, resource_group_l
os.remove(temp_path)

# nodepool add
self.cmd('aks nodepool add --resource-group={resource_group} --cluster-name={name} --name={nodepool2_name} --labels {labels} --node-count=1 --tags {tags}', checks=[
self.cmd('aks nodepool add --resource-group={resource_group} --cluster-name={name} --name={nodepool2_name} --labels {labels} --node-count=1 --tags {tags} --if-match={if_match}', checks=[
self.check('provisioningState', 'Succeeded')
])

Expand Down Expand Up @@ -1873,17 +1875,23 @@ def test_aks_nodepool_create_scale_delete(self, resource_group, resource_group_l
])

# nodepool update
self.cmd('aks nodepool update --resource-group={resource_group} --cluster-name={name} --name={nodepool2_name} --tags {new_tags}', checks=[
self.cmd('aks nodepool update --resource-group={resource_group} --cluster-name={name} --name={nodepool2_name} --tags {new_tags} --if-match={if_match}', checks=[
self.check('tags.key2', 'value2')
])

self.kwargs.update(
{
"if_match": "",
}
)

# #nodepool delete
self.cmd(
'aks nodepool delete --resource-group={resource_group} --cluster-name={name} --name={nodepool2_name} --no-wait', checks=[self.is_empty()])
'aks nodepool delete --resource-group={resource_group} --cluster-name={name} --name={nodepool2_name} --no-wait --if-match={if_match}', checks=[self.is_empty()])

# delete
self.cmd(
'aks delete -g {resource_group} -n {name} --yes --no-wait', checks=[self.is_empty()])
'aks delete -g {resource_group} -n {name} --yes --no-wait --if-match={if_match}', checks=[self.is_empty()])

@AllowLargeResponse()
@AKSCustomResourceGroupPreparer(random_name_length=17, name_prefix='clitest', location='westus2')
Expand Down Expand Up @@ -10424,19 +10432,21 @@ def test_aks_upgrade_upgrade_settings(self, resource_group, resource_group_locat
'name': aks_name,
'location': resource_group_location,
'ssh_key_value': self.generate_ssh_keys(),
'if_match': '*',
'if_none_match': '*',
})

# create
create_cmd = 'aks create --resource-group={resource_group} --name={name} --location={location} ' \
'--enable-managed-identity ' \
'--ssh-key-value={ssh_key_value}'
'--ssh-key-value={ssh_key_value} --if_match={if_match}'
InduSridhar marked this conversation as resolved.
Show resolved Hide resolved
self.cmd(create_cmd, checks=[
self.check('provisioningState', 'Succeeded'),
self.not_exists('upgradeSettings')
])

# upgrade upgrade settings
self.cmd('aks upgrade --resource-group={resource_group} --name={name} --upgrade-override-until 2020-01-01T22:30:17+00:00 --yes', checks=[
self.cmd('aks upgrade --resource-group={resource_group} --name={name} --upgrade-override-until 2020-01-01T22:30:17+00:00 --yes --if_match={if_match}', checks=[
InduSridhar marked this conversation as resolved.
Show resolved Hide resolved
self.check('provisioningState', 'Succeeded'),
self.not_exists('upgradeSettings.overrideSettings.forceUpgrade'),
self.exists('upgradeSettings.overrideSettings.until')
Expand All @@ -10457,9 +10467,15 @@ def test_aks_upgrade_upgrade_settings(self, resource_group, resource_group_locat
self.check('upgradeSettings.overrideSettings.until', '2020-02-22T22:30:17+00:00')
])

self.kwargs.update(
{
"if_match": "",
}
)

# delete
self.cmd(
'aks delete -g {resource_group} -n {name} --yes --no-wait', checks=[self.is_empty()])
'aks delete -g {resource_group} -n {name} --yes --no-wait --if_match={if_match}', checks=[self.is_empty()])
InduSridhar marked this conversation as resolved.
Show resolved Hide resolved

@AllowLargeResponse()
@AKSCustomResourceGroupPreparer(random_name_length=17, name_prefix='clitest', location='westus2')
Expand Down