Skip to content

Commit 3d3f70c

Browse files
authored
[AKS] az aks create/update: Add --sku parameter to support for automatic feature (#31981)
1 parent 2efe55a commit 3d3f70c

File tree

10 files changed

+7231
-28
lines changed

10 files changed

+7231
-28
lines changed

src/azure-cli/azure/cli/command_modules/acs/_consts.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@
6767
CONST_LOAD_BALANCER_SKU_BASIC = "basic"
6868
CONST_LOAD_BALANCER_SKU_STANDARD = "standard"
6969

70+
# ManagedClusterSKU Name
71+
CONST_MANAGED_CLUSTER_SKU_NAME_BASE = "base"
72+
CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC = "automatic"
73+
7074
# ManagedClusterSKU Tier
7175
CONST_MANAGED_CLUSTER_SKU_TIER_FREE = "free"
7276
CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD = "standard"

src/azure-cli/azure/cli/command_modules/acs/_help.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,9 @@
326326
- name: --enable-high-log-scale-mode
327327
type: bool
328328
short-summary: Enable High Log Scale Mode for Container Logs.
329+
- name: --sku
330+
type: string
331+
short-summary: Specify SKU name for managed clusters. Use '--sku base' enables a base managed cluster. Use '--sku automatic' enables an automatic managed cluster.
329332
- name: --tier
330333
type: string
331334
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.
@@ -717,6 +720,9 @@
717720
- name: --max-count
718721
type: int
719722
short-summary: Maximum nodes count used for autoscaler, when "--enable-cluster-autoscaler" specified. Please specify the value in the range of [1, 1000]
723+
- name: --sku
724+
type: string
725+
short-summary: Specify SKU name for managed clusters. Use '--sku base' enables a base managed cluster. Use '--sku automatic' enables an automatic managed cluster.
720726
- name: --tier
721727
type: string
722728
short-summary: Specify SKU tier for managed clusters. '--tier standard' enables a standard managed cluster service with a financially backed SLA. '--tier free' changes a standard managed cluster to a free one.

src/azure-cli/azure/cli/command_modules/acs/_params.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
CONST_WEEKINDEX_FIRST, CONST_WEEKINDEX_SECOND,
4747
CONST_WEEKINDEX_THIRD, CONST_WEEKINDEX_FOURTH,
4848
CONST_WEEKINDEX_LAST,
49+
CONST_MANAGED_CLUSTER_SKU_NAME_BASE,
50+
CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC,
4951
CONST_LOAD_BALANCER_BACKEND_POOL_TYPE_NODE_IP,
5052
CONST_LOAD_BALANCER_BACKEND_POOL_TYPE_NODE_IP_CONFIGURATION,
5153
CONST_AZURE_SERVICE_MESH_INGRESS_MODE_EXTERNAL,
@@ -174,6 +176,7 @@
174176

175177
# consts for ManagedCluster
176178
load_balancer_skus = [CONST_LOAD_BALANCER_SKU_BASIC, CONST_LOAD_BALANCER_SKU_STANDARD]
179+
sku_names = [CONST_MANAGED_CLUSTER_SKU_NAME_BASE, CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC]
177180
sku_tiers = [CONST_MANAGED_CLUSTER_SKU_TIER_FREE, CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD, CONST_MANAGED_CLUSTER_SKU_TIER_PREMIUM]
178181
network_plugins = [CONST_NETWORK_PLUGIN_KUBENET, CONST_NETWORK_PLUGIN_AZURE, CONST_NETWORK_PLUGIN_NONE]
179182
network_plugin_modes = [CONST_NETWORK_PLUGIN_MODE_OVERLAY]
@@ -371,6 +374,7 @@ def load_arguments(self, _):
371374
c.argument('node_os_upgrade_channel', arg_type=get_enum_type(node_os_upgrade_channels))
372375
c.argument('cluster_autoscaler_profile', nargs='+', options_list=["--cluster-autoscaler-profile", "--ca-profile"],
373376
help="Comma-separated list of key=value pairs for configuring cluster autoscaler. Pass an empty string to clear the profile.")
377+
c.argument('sku', arg_type=get_enum_type(sku_names))
374378
c.argument('tier', arg_type=get_enum_type(sku_tiers), validator=validate_sku_tier)
375379
c.argument('fqdn_subdomain')
376380
c.argument('api_server_authorized_ip_ranges', validator=validate_ip_ranges)
@@ -598,6 +602,7 @@ def load_arguments(self, _):
598602
c.argument('auto_upgrade_channel', arg_type=get_enum_type(auto_upgrade_channels))
599603
c.argument('cluster_autoscaler_profile', nargs='+', options_list=["--cluster-autoscaler-profile", "--ca-profile"],
600604
help="Comma-separated list of key=value pairs for configuring cluster autoscaler. Pass an empty string to clear the profile.")
605+
c.argument('sku', arg_type=get_enum_type(sku_names))
601606
c.argument('tier', arg_type=get_enum_type(sku_tiers), validator=validate_sku_tier)
602607
c.argument('api_server_authorized_ip_ranges', validator=validate_ip_ranges)
603608
# advanced networking

src/azure-cli/azure/cli/command_modules/acs/agentpool_decorator.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
CONST_DEFAULT_WINDOWS_NODE_VM_SIZE,
1818
CONST_DEFAULT_VMS_VM_SIZE,
1919
CONST_DEFAULT_WINDOWS_VMS_VM_SIZE,
20+
CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC,
2021
CONST_NODEPOOL_MODE_SYSTEM,
2122
CONST_NODEPOOL_MODE_USER,
2223
CONST_SCALE_DOWN_MODE_DELETE,
@@ -621,6 +622,10 @@ def _get_node_vm_size(self, read_only: bool = False) -> str:
621622
node_vm_size = CONST_DEFAULT_WINDOWS_NODE_VM_SIZE
622623
else:
623624
node_vm_size = CONST_DEFAULT_NODE_VM_SIZE
625+
sku = self.raw_param.get("sku")
626+
# if --node-vm-size is not specified, but --sku automatic is explicitly specified
627+
if sku is not None and sku == CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC:
628+
node_vm_size = ""
624629

625630
# this parameter does not need validation
626631
return node_vm_size

src/azure-cli/azure/cli/command_modules/acs/custom.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,7 @@ def aks_create(
651651
auto_upgrade_channel=None,
652652
node_os_upgrade_channel=None,
653653
cluster_autoscaler_profile=None,
654+
sku=None,
654655
tier=None,
655656
fqdn_subdomain=None,
656657
api_server_authorized_ip_ranges=None,
@@ -860,6 +861,7 @@ def aks_update(
860861
auto_upgrade_channel=None,
861862
node_os_upgrade_channel=None,
862863
cluster_autoscaler_profile=None,
864+
sku=None,
863865
tier=None,
864866
api_server_authorized_ip_ranges=None,
865867
enable_public_fqdn=False,

src/azure-cli/azure/cli/command_modules/acs/managed_cluster_decorator.py

Lines changed: 91 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@
1515

1616
from azure.mgmt.containerservice.models import KubernetesSupportPlan
1717

18+
from azure.cli.command_modules.acs._client_factory import get_graph_client
1819
from azure.cli.command_modules.acs._consts import (
1920
CONST_LOAD_BALANCER_SKU_BASIC,
2021
CONST_LOAD_BALANCER_SKU_STANDARD,
22+
CONST_MANAGED_CLUSTER_SKU_NAME_BASE,
23+
CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC,
2124
CONST_MANAGED_CLUSTER_SKU_TIER_FREE,
2225
CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD,
2326
CONST_MANAGED_CLUSTER_SKU_TIER_PREMIUM,
@@ -71,6 +74,7 @@
7174
from azure.cli.command_modules.acs._resourcegroup import get_rg_location
7275
from azure.cli.command_modules.acs._roleassignments import (
7376
add_role_assignment,
77+
add_role_assignment_executor,
7478
ensure_aks_acr,
7579
ensure_cluster_identity_permission_on_kubelet_identity,
7680
subnet_role_assignment_exists,
@@ -316,6 +320,7 @@ def external_functions(self) -> SimpleNamespace:
316320
external_functions["get_user_assigned_identity_by_resource_id"] = get_user_assigned_identity_by_resource_id
317321
external_functions["get_rg_location"] = get_rg_location
318322
external_functions["add_role_assignment"] = add_role_assignment
323+
external_functions["add_role_assignment_executor"] = add_role_assignment_executor
319324
external_functions["add_ingress_appgw_addon_role_assignment"] = add_ingress_appgw_addon_role_assignment
320325
external_functions["add_monitoring_role_assignment"] = add_monitoring_role_assignment
321326
external_functions["add_virtual_node_role_assignment"] = add_virtual_node_role_assignment
@@ -2270,6 +2275,20 @@ def get_ip_families(self) -> Union[List[str], None]:
22702275
# this parameter does not need validation
22712276
return ip_families
22722277

2278+
def get_sku_name(self) -> str:
2279+
# read the original value passed by the command
2280+
skuName = self.raw_param.get("sku")
2281+
if skuName is None:
2282+
if (
2283+
self.mc and
2284+
self.mc.sku and
2285+
getattr(self.mc.sku, 'name', None) is not None
2286+
):
2287+
skuName = vars(self.mc.sku)['name'].lower()
2288+
else:
2289+
skuName = CONST_MANAGED_CLUSTER_SKU_NAME_BASE
2290+
return skuName
2291+
22732292
def _get_outbound_type(
22742293
self,
22752294
enable_validation: bool = False,
@@ -2313,6 +2332,12 @@ def _get_outbound_type(
23132332
if not read_from_mc and not isBasicSKULb and outbound_type is None:
23142333
outbound_type = CONST_OUTBOUND_TYPE_LOAD_BALANCER
23152334

2335+
skuName = self.get_sku_name()
2336+
isVnetSubnetIdEmpty = self.get_vnet_subnet_id() in ["", None]
2337+
if skuName is not None and skuName == CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC and isVnetSubnetIdEmpty:
2338+
# outbound_type of Automatic SKU should be ManagedNATGateway if no subnet id provided.
2339+
outbound_type = CONST_OUTBOUND_TYPE_MANAGED_NAT_GATEWAY
2340+
23162341
# validation
23172342
# Note: The parameters involved in the validation are not verified in their own getters.
23182343
if enable_validation:
@@ -2781,6 +2806,10 @@ def _get_enable_addons(self, enable_validation: bool = False) -> List[str]:
27812806
# normalize
27822807
enable_addons = enable_addons.split(',') if enable_addons else []
27832808

2809+
sku_name = self.get_sku_name()
2810+
if sku_name == CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC:
2811+
enable_addons.append("monitoring")
2812+
27842813
# validation
27852814
if enable_validation:
27862815
# check duplicate addons
@@ -2956,6 +2985,9 @@ def get_enable_msi_auth_for_monitoring(self) -> Union[bool, None]:
29562985
) == "true"
29572986
)
29582987

2988+
sku_name = self.get_sku_name()
2989+
if sku_name == CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC:
2990+
return True
29592991
# this parameter does not need dynamic completion
29602992
# this parameter does not need validation
29612993
return enable_msi_auth_for_monitoring
@@ -3973,7 +4005,8 @@ def _get_apiserver_subnet_id(self, enable_validation: bool = False) -> Union[str
39734005
(
39744006
enable_apiserver_vnet_integration is None or
39754007
enable_apiserver_vnet_integration is False
3976-
)
4008+
) and
4009+
self.get_sku_name() != CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC
39774010
):
39784011
raise RequiredArgumentMissingError(
39794012
'"--apiserver-subnet-id" requires "--enable-apiserver-vnet-integration".')
@@ -5191,6 +5224,9 @@ def _get_disable_local_accounts(self, enable_validation: bool = False) -> bool:
51915224
self.mc.disable_local_accounts is not None
51925225
):
51935226
disable_local_accounts = self.mc.disable_local_accounts
5227+
sku_name = self.get_sku_name()
5228+
if sku_name == CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC:
5229+
disable_local_accounts = True
51945230

51955231
# this parameter does not need dynamic completion
51965232
# validation
@@ -5369,6 +5405,9 @@ def _get_enable_azure_monitor_metrics(self, enable_validation: bool = False) ->
53695405
self.mc.azure_monitor_profile.metrics
53705406
):
53715407
enable_azure_monitor_metrics = self.mc.azure_monitor_profile.metrics.enabled
5408+
skuName = self.get_sku_name()
5409+
if skuName == CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC:
5410+
enable_azure_monitor_metrics = True
53725411
# This parameter does not need dynamic completion.
53735412
if enable_validation:
53745413
if enable_azure_monitor_metrics and self._get_disable_azure_monitor_metrics(False):
@@ -6868,17 +6907,24 @@ def set_up_sku(self, mc: ManagedCluster) -> ManagedCluster:
68686907
"""
68696908
self._ensure_mc(mc)
68706909

6871-
if self.context.get_tier() == CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD:
6872-
mc.sku = self.models.ManagedClusterSKU(
6873-
name="Base",
6874-
tier="Standard"
6875-
)
6910+
mc.sku = self.models.ManagedClusterSKU()
6911+
skuName = self.context.get_sku_name()
6912+
tier = self.context.get_tier()
68766913

6877-
if self.context.get_tier() == CONST_MANAGED_CLUSTER_SKU_TIER_PREMIUM:
6878-
mc.sku = self.models.ManagedClusterSKU(
6879-
name="Base",
6880-
tier="Premium"
6881-
)
6914+
if skuName == CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC:
6915+
mc.sku.name = "Automatic"
6916+
# default tier for automatic sku is standard
6917+
mc.sku.tier = "Standard"
6918+
else:
6919+
mc.sku.name = "Base"
6920+
6921+
if tier == CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD:
6922+
mc.sku.tier = "Standard"
6923+
if tier == CONST_MANAGED_CLUSTER_SKU_TIER_PREMIUM:
6924+
mc.sku.tier = "Premium"
6925+
# backfill the tier to "Free" if it's not set
6926+
if mc.sku.tier is None:
6927+
mc.sku.tier = "Free"
68826928
return mc
68836929

68846930
def set_up_extended_location(self, mc: ManagedCluster) -> ManagedCluster:
@@ -7385,6 +7431,21 @@ def postprocessing_after_mc_created(self, cluster: ManagedCluster) -> None:
73857431
self.context.get_name(),
73867432
)
73877433

7434+
# Add role assignments for automatic sku
7435+
if cluster.sku is not None and cluster.sku.name == "Automatic":
7436+
try:
7437+
user = get_graph_client(self.cmd.cli_ctx).signed_in_user_get()
7438+
except Exception as e: # pylint: disable=broad-except
7439+
logger.warning("Could not get signed in user: %s", str(e))
7440+
else:
7441+
self.context.external_functions.add_role_assignment_executor( # type: ignore # pylint: disable=protected-access
7442+
self.cmd,
7443+
"Azure Kubernetes Service RBAC Cluster Admin",
7444+
user["id"],
7445+
scope=cluster.id,
7446+
resolve_assignee=False,
7447+
)
7448+
73887449
def put_mc(self, mc: ManagedCluster) -> ManagedCluster:
73897450
active_cloud = get_active_cloud(self.cmd.cli_ctx)
73907451
if active_cloud.profile != "latest":
@@ -7714,24 +7775,26 @@ def update_sku(self, mc: ManagedCluster) -> ManagedCluster:
77147775
"""
77157776
self._ensure_mc(mc)
77167777

7717-
# Premium without LTS is ok (not vice versa)
7718-
if self.context.get_tier() == CONST_MANAGED_CLUSTER_SKU_TIER_PREMIUM:
7719-
mc.sku = self.models.ManagedClusterSKU(
7720-
name="Base",
7721-
tier="Premium"
7722-
)
7723-
7724-
if self.context.get_tier() == CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD:
7725-
mc.sku = self.models.ManagedClusterSKU(
7726-
name="Base",
7727-
tier="Standard"
7728-
)
7778+
# there are existing MCs with nil sku, that is Base/Free
7779+
if mc.sku is None:
7780+
mc.sku = self.models.ManagedClusterSKU()
7781+
skuName = self.context.get_sku_name()
7782+
tier = self.context.get_tier()
7783+
if skuName == CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC:
7784+
mc.sku.name = "Automatic"
7785+
else:
7786+
mc.sku.name = "Base"
77297787

7730-
if self.context.get_tier() == CONST_MANAGED_CLUSTER_SKU_TIER_FREE:
7731-
mc.sku = self.models.ManagedClusterSKU(
7732-
name="Base",
7733-
tier="Free"
7734-
)
7788+
# Premium without LTS is ok (not vice versa)
7789+
if tier == CONST_MANAGED_CLUSTER_SKU_TIER_PREMIUM:
7790+
mc.sku.tier = "Premium"
7791+
if tier == CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD:
7792+
mc.sku.tier = "Standard"
7793+
if tier == CONST_MANAGED_CLUSTER_SKU_TIER_FREE:
7794+
mc.sku.tier = "Free"
7795+
# backfill the tier to "Free" if it's not set
7796+
if mc.sku.tier is None:
7797+
mc.sku.tier = "Free"
77357798
return mc
77367799

77377800
def update_outbound_type_in_network_profile(self, mc: ManagedCluster) -> ManagedCluster:

0 commit comments

Comments
 (0)