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
5 changes: 5 additions & 0 deletions src/aks-preview/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,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
* Add `az aks machine list` command to fetch list of machines in an agentpool.
* Add `az aks machine show` command to fetch information about a specific machine in an agentpool.

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 @@ -485,6 +485,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 @@ -670,6 +671,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