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
4 changes: 4 additions & 0 deletions src/azure-cli/azure/cli/command_modules/acs/_consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@
CONST_LOAD_BALANCER_SKU_BASIC = "basic"
CONST_LOAD_BALANCER_SKU_STANDARD = "standard"

# ManagedClusterSKU Name
CONST_MANAGED_CLUSTER_SKU_NAME_BASE = "base"
CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC = "automatic"

# ManagedClusterSKU Tier
CONST_MANAGED_CLUSTER_SKU_TIER_FREE = "free"
CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD = "standard"
Expand Down
6 changes: 6 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 @@ -326,6 +326,9 @@
- name: --enable-high-log-scale-mode
type: bool
short-summary: Enable High Log Scale Mode for Container Logs.
- name: --sku
type: string
short-summary: Specify SKU name for managed clusters. Use '--sku base' enables a base managed cluster. Use '--sku automatic' enables an automatic managed cluster.
- 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.
Expand Down Expand Up @@ -717,6 +720,9 @@
- name: --max-count
type: int
short-summary: Maximum nodes count used for autoscaler, when "--enable-cluster-autoscaler" specified. Please specify the value in the range of [1, 1000]
- name: --sku
type: string
short-summary: Specify SKU name for managed clusters. Use '--sku base' enables a base managed cluster. Use '--sku automatic' enables an automatic managed cluster.
- 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' changes a standard managed cluster to a free one.
Expand Down
5 changes: 5 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 @@ -46,6 +46,8 @@
CONST_WEEKINDEX_FIRST, CONST_WEEKINDEX_SECOND,
CONST_WEEKINDEX_THIRD, CONST_WEEKINDEX_FOURTH,
CONST_WEEKINDEX_LAST,
CONST_MANAGED_CLUSTER_SKU_NAME_BASE,
CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC,
CONST_LOAD_BALANCER_BACKEND_POOL_TYPE_NODE_IP,
CONST_LOAD_BALANCER_BACKEND_POOL_TYPE_NODE_IP_CONFIGURATION,
CONST_AZURE_SERVICE_MESH_INGRESS_MODE_EXTERNAL,
Expand Down Expand Up @@ -174,6 +176,7 @@

# consts for ManagedCluster
load_balancer_skus = [CONST_LOAD_BALANCER_SKU_BASIC, CONST_LOAD_BALANCER_SKU_STANDARD]
sku_names = [CONST_MANAGED_CLUSTER_SKU_NAME_BASE, CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC]
sku_tiers = [CONST_MANAGED_CLUSTER_SKU_TIER_FREE, CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD, CONST_MANAGED_CLUSTER_SKU_TIER_PREMIUM]
network_plugins = [CONST_NETWORK_PLUGIN_KUBENET, CONST_NETWORK_PLUGIN_AZURE, CONST_NETWORK_PLUGIN_NONE]
network_plugin_modes = [CONST_NETWORK_PLUGIN_MODE_OVERLAY]
Expand Down Expand Up @@ -371,6 +374,7 @@ def load_arguments(self, _):
c.argument('node_os_upgrade_channel', arg_type=get_enum_type(node_os_upgrade_channels))
c.argument('cluster_autoscaler_profile', nargs='+', options_list=["--cluster-autoscaler-profile", "--ca-profile"],
help="Comma-separated list of key=value pairs for configuring cluster autoscaler. Pass an empty string to clear the profile.")
c.argument('sku', arg_type=get_enum_type(sku_names))
c.argument('tier', arg_type=get_enum_type(sku_tiers), validator=validate_sku_tier)
c.argument('fqdn_subdomain')
c.argument('api_server_authorized_ip_ranges', validator=validate_ip_ranges)
Expand Down Expand Up @@ -594,6 +598,7 @@ def load_arguments(self, _):
c.argument('auto_upgrade_channel', arg_type=get_enum_type(auto_upgrade_channels))
c.argument('cluster_autoscaler_profile', nargs='+', options_list=["--cluster-autoscaler-profile", "--ca-profile"],
help="Comma-separated list of key=value pairs for configuring cluster autoscaler. Pass an empty string to clear the profile.")
c.argument('sku', arg_type=get_enum_type(sku_names))
c.argument('tier', arg_type=get_enum_type(sku_tiers), validator=validate_sku_tier)
c.argument('api_server_authorized_ip_ranges', validator=validate_ip_ranges)
# advanced networking
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
CONST_DEFAULT_WINDOWS_NODE_VM_SIZE,
CONST_DEFAULT_VMS_VM_SIZE,
CONST_DEFAULT_WINDOWS_VMS_VM_SIZE,
CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC,
CONST_NODEPOOL_MODE_SYSTEM,
CONST_NODEPOOL_MODE_USER,
CONST_SCALE_DOWN_MODE_DELETE,
Expand Down Expand Up @@ -621,6 +622,10 @@ def _get_node_vm_size(self, read_only: bool = False) -> str:
node_vm_size = CONST_DEFAULT_WINDOWS_NODE_VM_SIZE
else:
node_vm_size = CONST_DEFAULT_NODE_VM_SIZE
sku = self.raw_param.get("sku")
# if --node-vm-size is not specified, but --sku automatic is explicitly specified
if sku is not None and sku == CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC:
node_vm_size = ""

# this parameter does not need validation
return node_vm_size
Expand Down
2 changes: 2 additions & 0 deletions src/azure-cli/azure/cli/command_modules/acs/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,7 @@ def aks_create(
auto_upgrade_channel=None,
node_os_upgrade_channel=None,
cluster_autoscaler_profile=None,
sku=None,
tier=None,
fqdn_subdomain=None,
api_server_authorized_ip_ranges=None,
Expand Down Expand Up @@ -859,6 +860,7 @@ def aks_update(
auto_upgrade_channel=None,
node_os_upgrade_channel=None,
cluster_autoscaler_profile=None,
sku=None,
tier=None,
api_server_authorized_ip_ranges=None,
enable_public_fqdn=False,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@

from azure.mgmt.containerservice.models import KubernetesSupportPlan

from azure.cli.command_modules.acs._client_factory import get_graph_client
from azure.cli.command_modules.acs._consts import (
CONST_LOAD_BALANCER_SKU_BASIC,
CONST_LOAD_BALANCER_SKU_STANDARD,
CONST_MANAGED_CLUSTER_SKU_NAME_BASE,
CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC,
CONST_MANAGED_CLUSTER_SKU_TIER_FREE,
CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD,
CONST_MANAGED_CLUSTER_SKU_TIER_PREMIUM,
Expand Down Expand Up @@ -66,6 +69,7 @@
from azure.cli.command_modules.acs._resourcegroup import get_rg_location
from azure.cli.command_modules.acs._roleassignments import (
add_role_assignment,
add_role_assignment_executor,
ensure_aks_acr,
ensure_cluster_identity_permission_on_kubelet_identity,
subnet_role_assignment_exists,
Expand Down Expand Up @@ -309,6 +313,7 @@ def external_functions(self) -> SimpleNamespace:
external_functions["get_user_assigned_identity_by_resource_id"] = get_user_assigned_identity_by_resource_id
external_functions["get_rg_location"] = get_rg_location
external_functions["add_role_assignment"] = add_role_assignment
external_functions["add_role_assignment_executor"] = add_role_assignment_executor
external_functions["add_ingress_appgw_addon_role_assignment"] = add_ingress_appgw_addon_role_assignment
external_functions["add_monitoring_role_assignment"] = add_monitoring_role_assignment
external_functions["add_virtual_node_role_assignment"] = add_virtual_node_role_assignment
Expand Down Expand Up @@ -2261,6 +2266,20 @@ def get_ip_families(self) -> Union[List[str], None]:
# this parameter does not need validation
return ip_families

def get_sku_name(self) -> str:
# read the original value passed by the command
skuName = self.raw_param.get("sku")
if skuName is None:
if (
self.mc and
self.mc.sku and
getattr(self.mc.sku, 'name', None) is not None
):
skuName = vars(self.mc.sku)['name'].lower()
else:
skuName = CONST_MANAGED_CLUSTER_SKU_NAME_BASE
return skuName

def _get_outbound_type(
self,
enable_validation: bool = False,
Expand Down Expand Up @@ -2304,6 +2323,12 @@ def _get_outbound_type(
if not read_from_mc and not isBasicSKULb and outbound_type is None:
outbound_type = CONST_OUTBOUND_TYPE_LOAD_BALANCER

skuName = self.get_sku_name()
isVnetSubnetIdEmpty = self.get_vnet_subnet_id() in ["", None]
if skuName is not None and skuName == CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC and isVnetSubnetIdEmpty:
# outbound_type of Automatic SKU should be ManagedNATGateway if no subnet id provided.
outbound_type = CONST_OUTBOUND_TYPE_MANAGED_NAT_GATEWAY

# validation
# Note: The parameters involved in the validation are not verified in their own getters.
if enable_validation:
Expand Down Expand Up @@ -2772,6 +2797,10 @@ def _get_enable_addons(self, enable_validation: bool = False) -> List[str]:
# normalize
enable_addons = enable_addons.split(',') if enable_addons else []

sku_name = self.get_sku_name()
if sku_name == CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC:
enable_addons.append("monitoring")

# validation
if enable_validation:
# check duplicate addons
Expand Down Expand Up @@ -2947,6 +2976,9 @@ def get_enable_msi_auth_for_monitoring(self) -> Union[bool, None]:
) == "true"
)

sku_name = self.get_sku_name()
if sku_name == CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC:
return True
# this parameter does not need dynamic completion
# this parameter does not need validation
return enable_msi_auth_for_monitoring
Expand Down Expand Up @@ -3964,7 +3996,8 @@ def _get_apiserver_subnet_id(self, enable_validation: bool = False) -> Union[str
(
enable_apiserver_vnet_integration is None or
enable_apiserver_vnet_integration is False
)
) and
self.get_sku_name() != CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC
):
raise RequiredArgumentMissingError(
'"--apiserver-subnet-id" requires "--enable-apiserver-vnet-integration".')
Expand Down Expand Up @@ -5182,6 +5215,9 @@ def _get_disable_local_accounts(self, enable_validation: bool = False) -> bool:
self.mc.disable_local_accounts is not None
):
disable_local_accounts = self.mc.disable_local_accounts
sku_name = self.get_sku_name()
if sku_name == CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC:
disable_local_accounts = True

# this parameter does not need dynamic completion
# validation
Expand Down Expand Up @@ -5360,6 +5396,9 @@ def _get_enable_azure_monitor_metrics(self, enable_validation: bool = False) ->
self.mc.azure_monitor_profile.metrics
):
enable_azure_monitor_metrics = self.mc.azure_monitor_profile.metrics.enabled
skuName = self.get_sku_name()
if skuName == CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC:
enable_azure_monitor_metrics = True
# This parameter does not need dynamic completion.
if enable_validation:
if enable_azure_monitor_metrics and self._get_disable_azure_monitor_metrics(False):
Expand Down Expand Up @@ -6831,17 +6870,24 @@ def set_up_sku(self, mc: ManagedCluster) -> ManagedCluster:
"""
self._ensure_mc(mc)

if self.context.get_tier() == CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD:
mc.sku = self.models.ManagedClusterSKU(
name="Base",
tier="Standard"
)
mc.sku = self.models.ManagedClusterSKU()
skuName = self.context.get_sku_name()
tier = self.context.get_tier()

if self.context.get_tier() == CONST_MANAGED_CLUSTER_SKU_TIER_PREMIUM:
mc.sku = self.models.ManagedClusterSKU(
name="Base",
tier="Premium"
)
if skuName == CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC:
mc.sku.name = "Automatic"
# default tier for automatic sku is standard
mc.sku.tier = "Standard"
else:
mc.sku.name = "Base"

if tier == CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD:
mc.sku.tier = "Standard"
if tier == CONST_MANAGED_CLUSTER_SKU_TIER_PREMIUM:
mc.sku.tier = "Premium"
# backfill the tier to "Free" if it's not set
if mc.sku.tier is None:
mc.sku.tier = "Free"
return mc

def set_up_extended_location(self, mc: ManagedCluster) -> ManagedCluster:
Expand Down Expand Up @@ -7339,6 +7385,21 @@ def postprocessing_after_mc_created(self, cluster: ManagedCluster) -> None:
existing_ephemeral_nvme_perf_tier,
)

# Add role assignments for automatic sku
if cluster.sku is not None and cluster.sku.name == "Automatic":
try:
user = get_graph_client(self.cmd.cli_ctx).signed_in_user_get()
except Exception as e: # pylint: disable=broad-except
logger.warning("Could not get signed in user: %s", str(e))
else:
self.context.external_functions.add_role_assignment_executor( # type: ignore # pylint: disable=protected-access
self.cmd,
"Azure Kubernetes Service RBAC Cluster Admin",
user["id"],
scope=cluster.id,
resolve_assignee=False,
)

def put_mc(self, mc: ManagedCluster) -> ManagedCluster:
active_cloud = get_active_cloud(self.cmd.cli_ctx)
if active_cloud.profile != "latest":
Expand Down Expand Up @@ -7668,24 +7729,26 @@ def update_sku(self, mc: ManagedCluster) -> ManagedCluster:
"""
self._ensure_mc(mc)

# Premium without LTS is ok (not vice versa)
if self.context.get_tier() == CONST_MANAGED_CLUSTER_SKU_TIER_PREMIUM:
mc.sku = self.models.ManagedClusterSKU(
name="Base",
tier="Premium"
)

if self.context.get_tier() == CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD:
mc.sku = self.models.ManagedClusterSKU(
name="Base",
tier="Standard"
)
# there are existing MCs with nil sku, that is Base/Free
if mc.sku is None:
mc.sku = self.models.ManagedClusterSKU()
skuName = self.context.get_sku_name()
tier = self.context.get_tier()
if skuName == CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC:
mc.sku.name = "Automatic"
else:
mc.sku.name = "Base"

if self.context.get_tier() == CONST_MANAGED_CLUSTER_SKU_TIER_FREE:
mc.sku = self.models.ManagedClusterSKU(
name="Base",
tier="Free"
)
# Premium without LTS is ok (not vice versa)
if tier == CONST_MANAGED_CLUSTER_SKU_TIER_PREMIUM:
mc.sku.tier = "Premium"
if tier == CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD:
mc.sku.tier = "Standard"
if tier == CONST_MANAGED_CLUSTER_SKU_TIER_FREE:
mc.sku.tier = "Free"
# backfill the tier to "Free" if it's not set
if mc.sku.tier is None:
mc.sku.tier = "Free"
return mc

def update_outbound_type_in_network_profile(self, mc: ManagedCluster) -> ManagedCluster:
Expand Down
Loading
Loading