Skip to content
Closed
5 changes: 5 additions & 0 deletions src/aks-preview/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ To release a new version, please select a new version number (usually plus 1 to
Pending
+++++++

0.5.161
+++++++
* Support `premium` cluster sku tier in `az aks create` and `az aks update` commands
* Add option `--k8s-support-plan` to `az aks create` and `az aks update` commands

0.5.160
+++++++
* Custom ips and managed ips can be assigned to aks cluster outbound resources
Expand Down
1 change: 1 addition & 0 deletions src/aks-preview/azext_aks_preview/_consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
# ManagedClusterSKU Tier
CONST_MANAGED_CLUSTER_SKU_TIER_FREE = "free"
CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD = "standard"
CONST_MANAGED_CLUSTER_SKU_TIER_PREMIUM = "premium"

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. Continue?"
# load balancer backend pool type
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 @@ -302,6 +302,9 @@
- name: --node-resource-group
type: string
short-summary: The node resource group is the resource group where all customer's resources will be created in, such as virtual machines.
- name: --k8s-support-plan
type: string
short-summary: Choose from "KubernetesOfficial" or "AKSLongTermSupport", with "AKSLongTermSupport" you get 1 extra year of CVE patchs.
- name: --nrg-lockdown-restriction-level
type: string
short-summary: Restriction level on the managed node resource group.
Expand Down Expand Up @@ -841,6 +844,9 @@
- name: --rotation-poll-interval
type: string
short-summary: Set interval of rotation poll. Use with azure-keyvault-secrets-provider addon.
- name: --k8s-support-plan
type: string
short-summary: Choose from "KubernetesOfficial" or "AKSLongTermSupport", with "AKSLongTermSupport" you get 1 extra year of CVE patchs.
- name: --enable-disk-driver
type: bool
short-summary: Enable AzureDisk CSI Driver.
Expand Down
8 changes: 7 additions & 1 deletion src/aks-preview/azext_aks_preview/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import platform

from argcomplete.completers import FilesCompleter
from azext_aks_preview._client_factory import CUSTOM_MGMT_AKS_PREVIEW
from azext_aks_preview._completers import (
get_k8s_upgrades_completion_list,
get_k8s_versions_completion_list,
Expand Down Expand Up @@ -48,6 +49,7 @@
CONST_LOAD_BALANCER_SKU_STANDARD,
CONST_MANAGED_CLUSTER_SKU_TIER_FREE,
CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD,
CONST_MANAGED_CLUSTER_SKU_TIER_PREMIUM,
CONST_NETWORK_DATAPLANE_AZURE,
CONST_NETWORK_DATAPLANE_CILIUM,
CONST_NETWORK_PLUGIN_AZURE,
Expand Down Expand Up @@ -168,6 +170,7 @@
tags_type,
zones_type,
)
from azure.cli.core.profiles import ResourceType
from knack.arguments import CLIArgumentType

# candidates for enumeration
Expand All @@ -190,7 +193,7 @@

# consts for ManagedCluster
load_balancer_skus = [CONST_LOAD_BALANCER_SKU_BASIC, CONST_LOAD_BALANCER_SKU_STANDARD]
sku_tiers = [CONST_MANAGED_CLUSTER_SKU_TIER_FREE, CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD]
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]
network_dataplanes = [CONST_NETWORK_DATAPLANE_AZURE, CONST_NETWORK_DATAPLANE_CILIUM]
Expand Down Expand Up @@ -258,6 +261,7 @@
def load_arguments(self, _):

acr_arg_type = CLIArgumentType(metavar='ACR_NAME_OR_RESOURCE_ID')
k8s_support_plans = self.get_models("KubernetesSupportPlan", resource_type=CUSTOM_MGMT_AKS_PREVIEW, operation_group='managed_clusters')

# AKS command argument configuration
with self.argument_context('aks') as c:
Expand Down Expand Up @@ -338,6 +342,7 @@ def load_arguments(self, _):
c.argument('attach_acr', acr_arg_type)
c.argument('skip_subnet_role_assignment', action='store_true')
c.argument('node_resource_group')
c.argument('k8s_support_plan', arg_type=get_enum_type(k8s_support_plans))
c.argument('enable_defender', action='store_true')
c.argument('defender_config', validator=validate_defender_config_parameter)
c.argument('disk_driver_version', arg_type=get_enum_type(disk_driver_versions))
Expand Down Expand Up @@ -489,6 +494,7 @@ def load_arguments(self, _):
c.argument('aad_tenant_id')
c.argument('aad_admin_group_object_ids')
c.argument('enable_oidc_issuer', action='store_true')
c.argument('k8s_support_plan', arg_type=get_enum_type(k8s_support_plans))
c.argument('windows_admin_password')
c.argument('enable_ahub')
c.argument('disable_ahub')
Expand Down
6 changes: 4 additions & 2 deletions src/aks-preview/azext_aks_preview/_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@
from math import isclose, isnan

import azure.cli.core.keys as keys
from azure.mgmt.containerservice.models import KubernetesSupportPlan
from azext_aks_preview._consts import (
ADDONS,
CONST_LOAD_BALANCER_BACKEND_POOL_TYPE_NODE_IP,
CONST_LOAD_BALANCER_BACKEND_POOL_TYPE_NODE_IPCONFIGURATION,
CONST_MANAGED_CLUSTER_SKU_TIER_FREE,
CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD,
CONST_MANAGED_CLUSTER_SKU_TIER_PREMIUM,
CONST_OS_SKU_AZURELINUX,
CONST_OS_SKU_CBLMARINER,
CONST_OS_SKU_MARINER,
Expand Down Expand Up @@ -206,8 +208,8 @@ def validate_sku_tier(namespace):
if namespace.tier is not None:
if namespace.tier == '':
return
if namespace.tier.lower() not in (CONST_MANAGED_CLUSTER_SKU_TIER_FREE, CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD):
raise InvalidArgumentValueError("--tier can only be free or standard")
if namespace.tier.lower() not in (CONST_MANAGED_CLUSTER_SKU_TIER_FREE, CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD, CONST_MANAGED_CLUSTER_SKU_TIER_PREMIUM):
raise InvalidArgumentValueError("--tier can only be free, standard, or premium")


def validate_nodepool_taints(namespace):
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 @@ -484,6 +484,7 @@ def aks_create(
attach_acr=None,
skip_subnet_role_assignment=False,
node_resource_group=None,
k8s_support_plan=None,
nrg_lockdown_restriction_level=None,
enable_defender=False,
defender_config=None,
Expand Down Expand Up @@ -669,6 +670,7 @@ def aks_update(
aad_tenant_id=None,
aad_admin_group_object_ids=None,
enable_oidc_issuer=False,
k8s_support_plan=None,
windows_admin_password=None,
enable_ahub=False,
disable_ahub=False,
Expand Down
70 changes: 70 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 @@ -9,6 +9,8 @@
from types import SimpleNamespace
from typing import Any, Dict, List, Optional, Tuple, TypeVar, Union

from azure.mgmt.containerservice.models import KubernetesSupportPlan

from azure.cli.command_modules.acs._consts import (
DecoratorEarlyExitException,
DecoratorMode,
Expand Down Expand Up @@ -56,6 +58,7 @@
CONST_LOAD_BALANCER_SKU_BASIC,
CONST_MANAGED_CLUSTER_SKU_TIER_FREE,
CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD,
CONST_MANAGED_CLUSTER_SKU_TIER_PREMIUM,
CONST_NETWORK_PLUGIN_AZURE,
CONST_NETWORK_PLUGIN_MODE_OVERLAY,
CONST_NETWORK_DATAPLANE_CILIUM,
Expand Down Expand Up @@ -2251,6 +2254,10 @@ def update_azure_service_mesh_profile(self) -> ServiceMeshProfile:
else:
return self.mc.service_mesh_profile

def _get_k8s_support_plan(self) -> KubernetesSupportPlan:
support_plan = self.raw_param.get("k8s_support_plan")
return support_plan

def _get_uptime_sla(self, enable_validation: bool = False) -> bool:
"""Internal function to obtain the value of uptime_sla.

Expand Down Expand Up @@ -2341,6 +2348,24 @@ def get_tier(self) -> str:

return tierStr

def get_k8s_support_plan(self) -> Union[str, None]:
"""Obtain the value of kubernetes_support_plan.

:return: string or None
"""
# default to None
support_plan = None
# try to read the property value corresponding to the parameter from the `mc` object
if self.mc and hasattr(self.mc, "support_plan") and self.mc.support_plan is not None:
support_plan = self.mc.support_plan

# if specified by customer, use the specified value
support_plan = self.raw_param.get("k8s_support_plan")

# this parameter does not need dynamic completion
# this parameter does not need validation
return support_plan

def get_nodepool_taints(self) -> Union[List[str], None]:
"""Obtain the value of nodepool_labels.

Expand Down Expand Up @@ -2814,6 +2839,26 @@ def set_up_sku(self, mc: ManagedCluster) -> ManagedCluster:
name="Base",
tier="Standard"
)

if self.context.get_tier() == CONST_MANAGED_CLUSTER_SKU_TIER_PREMIUM:
mc.sku = self.models.ManagedClusterSKU(
name="Base",
tier="Premium"
)
return mc

def set_up_k8s_support_plan(self, mc: ManagedCluster) -> ManagedCluster:
"""Set up supportPlan for the ManagedCluster object.
:return: the ManagedCluster object
"""
self._ensure_mc(mc)

support_plan = self.context.get_k8s_support_plan()
if support_plan == KubernetesSupportPlan.AKS_LONG_TERM_SUPPORT:
if mc is None or mc.sku is None or mc.sku.tier.lower() != CONST_MANAGED_CLUSTER_SKU_TIER_PREMIUM.lower():
raise InvalidArgumentValueError("Long term support is only available for premium tier clusters.")

mc.support_plan = support_plan
return mc

def set_up_cost_analysis(self, mc: ManagedCluster) -> ManagedCluster:
Expand Down Expand Up @@ -2880,6 +2925,8 @@ def construct_mc_profile_preview(self, bypass_restore_defaults: bool = False) ->
mc = self.set_up_guardrails_profile(mc)
# set up azure service mesh profile
mc = self.set_up_azure_service_mesh_profile(mc)
# setup k8s support plan
mc = self.set_up_k8s_support_plan(mc)
# set up azure monitor profile
mc = self.set_up_azure_monitor_profile(mc)
# set up metrics profile
Expand Down Expand Up @@ -3338,6 +3385,20 @@ def update_workload_identity_profile(self, mc: ManagedCluster) -> ManagedCluster

return mc

def update_k8s_support_plan(self, mc: ManagedCluster) -> ManagedCluster:
"""Update supportPlan for the ManagedCluster object.
:return: the ManagedCluster object
"""
self._ensure_mc(mc)

support_plan = self.context.get_k8s_support_plan()
if support_plan == KubernetesSupportPlan.AKS_LONG_TERM_SUPPORT:
if mc is None or mc.sku is None or mc.sku.tier.lower() != CONST_MANAGED_CLUSTER_SKU_TIER_PREMIUM.lower():
raise RequiredArgumentMissingError("Long term support is only available for premium tier clusters.")

mc.support_plan = support_plan
return mc

def update_image_cleaner(self, mc: ManagedCluster) -> ManagedCluster:
"""Update security profile imageCleaner for the ManagedCluster object.

Expand Down Expand Up @@ -3663,6 +3724,13 @@ 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_uptime_sla() or self.context.get_tier() == CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD:
mc.sku = self.models.ManagedClusterSKU(
name="Base",
Expand Down Expand Up @@ -3817,6 +3885,8 @@ def update_mc_profile_preview(self) -> ManagedCluster:
mc = self.update_nodepool_taints_mc(mc)
# update network_observability in network_profile
mc = self.update_enable_network_observability_in_network_profile(mc)
# update kubernetes support plan
mc = self.update_k8s_support_plan(mc)
# update metrics profile
mc = self.update_metrics_profile(mc)

Expand Down
Loading