Skip to content

Commit

Permalink
add --sku to az aks create/update command
Browse files Browse the repository at this point in the history
  • Loading branch information
charlili1234 committed Apr 5, 2024
1 parent 5ba9895 commit 2a8094d
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 20 deletions.
4 changes: 4 additions & 0 deletions src/aks-preview/azext_aks_preview/_consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@
CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD = "standard"
CONST_MANAGED_CLUSTER_SKU_TIER_PREMIUM = "premium"

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

CONST_OUTBOUND_MIGRATION_MULTIZONE_TO_NATGATEWAY_MSG = (
"Warning: this AKS cluster has multi-zonal nodepools, but NAT Gateway is not currently zone redundant. "
"Migrating outbound connectivity to NAT Gateway could lead to a reduction in zone redundancy for this cluster. "
Expand Down
6 changes: 6 additions & 0 deletions src/aks-preview/azext_aks_preview/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,9 @@
- name: --enable-vtpm
type: bool
short-summary: Enable vTPM on all node pools in the cluster. Must use VMSS agent pool type.
- name: --sku
type: string
short-summary: Specify SKU name for managed clusters. '--sku base' enables blah blah. '--sku automatic' blah blah.
examples:
- name: Create a Kubernetes cluster with an existing SSH public key.
text: az aks create -g MyResourceGroup -n MyManagedCluster --ssh-key-value /path/to/publickey
Expand Down Expand Up @@ -1165,6 +1168,9 @@
- name: --ssh-access
type: string
short-summary: Update SSH setting for all node pools in this cluster. Use "disabled" to disable SSH access, "localuser" to enable SSH access using private key.
- name: --sku
type: string
short-summary: Specify SKU name for managed clusters. '--sku base' enables blah blah. '--sku automatic' blah blah.
examples:
- name: Reconcile the cluster back to its current state.
text: az aks update -g MyResourceGroup -n MyManagedCluster
Expand Down
10 changes: 10 additions & 0 deletions src/aks-preview/azext_aks_preview/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@
CONST_NODE_PROVISIONING_MODE_AUTO,
CONST_SSH_ACCESS_LOCALUSER,
CONST_SSH_ACCESS_DISABLED,
CONST_MANAGED_CLUSTER_SKU_NAME_BASE,
CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC,
)
from azext_aks_preview._validators import (
validate_acr,
Expand Down Expand Up @@ -177,6 +179,7 @@
validate_azure_service_mesh_revision,
validate_artifact_streaming,
validate_custom_endpoints,
validate_sku_name,
)
from azext_aks_preview.azurecontainerstorage._consts import (
CONST_ACSTOR_ALL,
Expand Down Expand Up @@ -241,6 +244,10 @@
CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD,
CONST_MANAGED_CLUSTER_SKU_TIER_PREMIUM,
]
sku_names = [
CONST_MANAGED_CLUSTER_SKU_NAME_BASE,
CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC,
]
network_plugins = [
CONST_NETWORK_PLUGIN_KUBENET,
CONST_NETWORK_PLUGIN_AZURE,
Expand Down Expand Up @@ -502,6 +509,9 @@ def load_arguments(self, _):
c.argument(
"tier", arg_type=get_enum_type(sku_tiers), validator=validate_sku_tier
)
c.argument(
"sku", is_preview=True, arg_type=get_enum_type(sku_names), validator=validate_sku_name
)
c.argument("fqdn_subdomain")
c.argument("api_server_authorized_ip_ranges", validator=validate_ip_ranges)
c.argument("enable_private_cluster", action="store_true")
Expand Down
12 changes: 12 additions & 0 deletions src/aks-preview/azext_aks_preview/_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
CONST_OS_SKU_MARINER,
CONST_NETWORK_POD_IP_ALLOCATION_MODE_DYNAMIC_INDIVIDUAL,
CONST_NETWORK_POD_IP_ALLOCATION_MODE_STATIC_BLOCK,
CONST_MANAGED_CLUSTER_SKU_NAME_BASE,
CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC,
)
from azext_aks_preview._helpers import _fuzzy_match
from knack.log import get_logger
Expand Down Expand Up @@ -219,6 +221,16 @@ def validate_sku_tier(namespace):
raise InvalidArgumentValueError("--tier can only be free, standard, or premium")


def validate_sku_name(namespace):
"""Validates the sku name string."""
if namespace.sku is not None:
if namespace.sku.lower() not in (
CONST_MANAGED_CLUSTER_SKU_NAME_BASE,
CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC,
):
raise InvalidArgumentValueError("--sku can only be base or automatic")


def validate_nodepool_taints(namespace):
"""Validates that provided node taints is a valid format"""
if hasattr(namespace, 'nodepool_taints'):
Expand Down
2 changes: 2 additions & 0 deletions src/aks-preview/azext_aks_preview/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,7 @@ def aks_create(
# trusted launch
enable_secure_boot=False,
enable_vtpm=False,
sku=None,
):
# DO NOT MOVE: get all the original parameters and save them as a dictionary
raw_parameters = locals()
Expand Down Expand Up @@ -826,6 +827,7 @@ def aks_update(
azure_container_storage_nodepools=None,
node_provisioning_mode=None,
ssh_access=None,
sku=None,
):
# DO NOT MOVE: get all the original parameters and save them as a dictionary
raw_parameters = locals()
Expand Down
73 changes: 53 additions & 20 deletions src/aks-preview/azext_aks_preview/managed_cluster_decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
CONST_SECRET_ROTATION_ENABLED,
CONST_PRIVATE_DNS_ZONE_CONTRIBUTOR_ROLE,
CONST_DNS_ZONE_CONTRIBUTOR_ROLE,
CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC,
CONST_MANAGED_CLUSTER_SKU_NAME_BASE,
)
from azext_aks_preview._helpers import (
check_is_apiserver_vnet_integration_cluster,
Expand Down Expand Up @@ -300,6 +302,22 @@ 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
self.mc.sku.name is not None
):
skuName = 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 @@ -354,6 +372,10 @@ def _get_outbound_type(
outbound_type != CONST_OUTBOUND_TYPE_USER_DEFINED_ROUTING
):
outbound_type = CONST_OUTBOUND_TYPE_LOAD_BALANCER
skuName = self.get_sku_name()
if skuName is not None and skuName == CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC:
# outbound_type of Automatic SKU should be ManagedNATGateway if not provided.
outbound_type = CONST_OUTBOUND_TYPE_MANAGED_NAT_GATEWAY

# validation
# Note: The parameters involved in the validation are not verified in their own getters.
Expand Down Expand Up @@ -3171,17 +3193,25 @@ def set_up_sku(self, mc: ManagedCluster) -> ManagedCluster:
"""
self._ensure_mc(mc)

mc.sku = self.models.ManagedClusterSKU()
skuName = self.context.get_sku_name()
if skuName is not None and skuName == CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC:
mc.sku.name="Automatic"
# passive Kind should always to match sku.name
mc.kind="Automatic"
mc.sku.tier="Standard"
else:
mc.sku.name="Base"
# passive Kind should always match sku.name
mc.kind="Base"
mc.sku.tier="Free"

if self.context.get_uptime_sla() or self.context.get_tier() == CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD:
mc.sku = self.models.ManagedClusterSKU( # pylint: disable=no-member
name="Base",
tier="Standard"
)
mc.sku.tier="Standard"

if self.context.get_tier() == CONST_MANAGED_CLUSTER_SKU_TIER_PREMIUM:
mc.sku = self.models.ManagedClusterSKU( # pylint: disable=no-member
name="Base",
tier="Premium"
)
mc.sku.tier="Premium"

return mc

def set_up_k8s_support_plan(self, mc: ManagedCluster) -> ManagedCluster:
Expand Down Expand Up @@ -4429,25 +4459,28 @@ def update_sku(self, mc: ManagedCluster) -> ManagedCluster:
:return: the ManagedCluster object
"""
self._ensure_mc(mc)
skuName = self.context.get_sku_name()
mc.sku = self.models.ManagedClusterSKU()
if skuName is not None and skuName == CONST_MANAGED_CLUSTER_SKU_NAME_AUTOMATIC:
mc.sku.name="Automatic"
# passive Kind should always to match sku.name
mc.kind = "Automatic"
mc.sku.tier="Standard"
else:
mc.sku.name="Base"
# passive Kind should always match sku.name
mc.kind="Base"

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

if self.context.get_uptime_sla() or self.context.get_tier() == CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD:
mc.sku = self.models.ManagedClusterSKU( # pylint: disable=no-member
name="Base",
tier="Standard"
)
mc.sku.tier="Standard"

if self.context.get_no_uptime_sla() or self.context.get_tier() == CONST_MANAGED_CLUSTER_SKU_TIER_FREE:
mc.sku = self.models.ManagedClusterSKU( # pylint: disable=no-member
name="Base",
tier="Free"
)
mc.sku.tier="Free"

return mc

def update_upgrade_settings(self, mc: ManagedCluster) -> ManagedCluster:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3249,6 +3249,13 @@ def test_aks_nodepool_delete_with_ignore_pod_disruption_budget(
checks=[self.is_empty()],
)

#@AllowLargeResponse()
#@AKSCustomResourceGroupPreparer(
# random_name_length=17, name_prefix="clitest", location="eastus"
#)
#def test_aks_automatic_sku(self, resource_group, resource_group_location):
#add recording tests for Automatic sku cluster create/scacle/switch to Base sku etc

@AllowLargeResponse()
@AKSCustomResourceGroupPreparer(
random_name_length=17, name_prefix="clitest", location="westus2"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8161,6 +8161,7 @@ def test_update_supportPlan(self):
normalClusterCalculated = noopDecorator3.update_k8s_support_plan(normalCluster)
self.assertEqual(normalClusterCalculated, normalCluster)

# add some UTs regarding sku.Name

if __name__ == "__main__":
unittest.main()

0 comments on commit 2a8094d

Please sign in to comment.