Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

{AKS} Update v2 managed cluster decorator - part 2 #4982

Merged
merged 4 commits into from
Jun 14, 2022
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
230 changes: 163 additions & 67 deletions src/aks-preview/azext_aks_preview/managed_cluster_decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@
)
from azure.cli.command_modules.acs._helpers import (
check_is_msi_cluster,
safe_list_get,
format_parameter_name_to_option_name,
safe_lower,
)
from azure.cli.command_modules.acs._validators import extract_comma_separated_string
from azure.cli.command_modules.acs._validators import (
extract_comma_separated_string,
)
from azure.cli.command_modules.acs.managed_cluster_decorator import (
AKSManagedClusterContext,
AKSManagedClusterCreateDecorator,
Expand All @@ -26,6 +28,7 @@
)
from azure.cli.core import AzCommandsLoader
from azure.cli.core.azclierror import (
ArgumentUsageError,
InvalidArgumentValueError,
MutuallyExclusiveArgumentError,
RequiredArgumentMissingError,
Expand All @@ -39,7 +42,9 @@

from azext_aks_preview._helpers import get_cluster_snapshot_by_snapshot_id
from azext_aks_preview._loadbalancer import create_load_balancer_profile
from azext_aks_preview._loadbalancer import update_load_balancer_profile as _update_load_balancer_profile
from azext_aks_preview._loadbalancer import (
update_load_balancer_profile as _update_load_balancer_profile,
)
from azext_aks_preview._podidentity import (
_fill_defaults_for_pod_identity_profile,
_is_pod_identity_addon_enabled,
Expand Down Expand Up @@ -816,13 +821,15 @@ def get_kubernetes_version(self) -> str:
return self._get_kubernetes_version(read_only=False)

def get_disk_driver(self) -> Optional[ManagedClusterStorageProfileDiskCSIDriver]:
"""Obtrain the value of storage_profile.disk_csi_driver
"""Obtain the value of storage_profile.disk_csi_driver

:return: Optional[ManagedClusterStorageProfileDiskCSIDriver]
"""
enable_disk_driver = self.raw_param.get("enable_disk_driver")
disable_disk_driver = self.raw_param.get("disable_disk_driver")
if not enable_disk_driver and not disable_disk_driver:
disk_driver_version = self.raw_param.get("disk_driver_version")

if not enable_disk_driver and not disable_disk_driver and not disk_driver_version:
return None
profile = self.models.ManagedClusterStorageProfileDiskCSIDriver()

Expand All @@ -832,25 +839,45 @@ def get_disk_driver(self) -> Optional[ManagedClusterStorageProfileDiskCSIDriver]
"--disable-disk-driver at the same time."
)

if disable_disk_driver and disk_driver_version:
raise ArgumentUsageError(
"The parameter --disable-disk-driver cannot be used "
"when --disk-driver-version is specified.")

if self.decorator_mode == DecoratorMode.UPDATE and disk_driver_version and not enable_disk_driver:
raise ArgumentUsageError(
"Parameter --enable-disk-driver is required "
"when --disk-driver-version is specified during update.")

if self.decorator_mode == DecoratorMode.CREATE:
if disable_disk_driver:
profile.enabled = False
else:
profile.enabled = True
if disk_driver_version:
profile.version = disk_driver_version

if self.decorator_mode == DecoratorMode.UPDATE:
if enable_disk_driver:
profile.enabled = True
if disk_driver_version:
profile.version = disk_driver_version
elif disable_disk_driver:
msg = "Please make sure there are no existing PVs and PVCs that are used by AzureDisk CSI driver before disabling."
if not self.get_yes() and not prompt_y_n(msg, default="n"):
raise DecoratorEarlyExitException()
profile.enabled = False

return profile

def get_file_driver(self) -> Optional[ManagedClusterStorageProfileFileCSIDriver]:
"""Obtrain the value of storage_profile.file_csi_driver
"""Obtain the value of storage_profile.file_csi_driver

:return: Optional[ManagedClusterStorageProfileFileCSIDriver]
"""
enable_file_driver = self.raw_param.get("enable_file_driver")
disable_file_driver = self.raw_param.get("disable_file_driver")

if not enable_file_driver and not disable_file_driver:
return None
profile = self.models.ManagedClusterStorageProfileFileCSIDriver()
Expand All @@ -869,19 +896,24 @@ def get_file_driver(self) -> Optional[ManagedClusterStorageProfileFileCSIDriver]
if enable_file_driver:
profile.enabled = True
elif disable_file_driver:
msg = "Please make sure there are no existing PVs and PVCs that are used by AzureFile CSI driver before disabling."
if not self.get_yes() and not prompt_y_n(msg, default="n"):
raise DecoratorEarlyExitException()
profile.enabled = False

return profile

def get_snapshot_controller(self) -> Optional[ManagedClusterStorageProfileSnapshotController]:
"""Obtrain the value of storage_profile.snapshot_controller
"""Obtain the value of storage_profile.snapshot_controller

:return: Optional[ManagedClusterStorageProfileSnapshotController]
"""
enable_snapshot_controller = self.raw_param.get("enable_snapshot_controller")
disable_snapshot_controller = self.raw_param.get("disable_snapshot_controller")

if not enable_snapshot_controller and not disable_snapshot_controller:
return None

profile = self.models.ManagedClusterStorageProfileSnapshotController()

if enable_snapshot_controller and disable_snapshot_controller:
Expand All @@ -898,12 +930,16 @@ def get_snapshot_controller(self) -> Optional[ManagedClusterStorageProfileSnapsh
if enable_snapshot_controller:
profile.enabled = True
elif disable_snapshot_controller:
msg = "Please make sure there are no existing VolumeSnapshots, VolumeSnapshotClasses and VolumeSnapshotContents " \
"that are used by the snapshot controller before disabling."
if not self.get_yes() and not prompt_y_n(msg, default="n"):
raise DecoratorEarlyExitException()
profile.enabled = False

return profile

def get_storage_profile(self) -> Optional[ManagedClusterStorageProfile]:
"""Obtrain the value of storage_profile.
"""Obtain the value of storage_profile.

:return: Optional[ManagedClusterStorageProfile]
"""
Expand Down Expand Up @@ -1040,6 +1076,76 @@ def get_dns_zone_resource_id(self) -> Union[str, None]:
# this parameter does not need validation
return dns_zone_resource_id

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

This function supports the option of enable_validation. When enabled, if both enable_keda and disable_keda are
specified, raise a MutuallyExclusiveArgumentError.

:return: bool
"""
# Read the original value passed by the command.
enable_keda = self.raw_param.get("enable_keda")

# In create mode, try to read the property value corresponding to the parameter from the `mc` object.
if self.decorator_mode == DecoratorMode.CREATE:
if (
self.mc and
self.mc.workload_auto_scaler_profile and
self.mc.workload_auto_scaler_profile.keda
):
enable_keda = self.mc.workload_auto_scaler_profile.keda.enabled

# This parameter does not need dynamic completion.
if enable_validation:
if enable_keda and self._get_disable_keda(enable_validation=False):
raise MutuallyExclusiveArgumentError(
"Cannot specify --enable-keda and --disable-keda at the same time."
)

return enable_keda

def get_enable_keda(self) -> bool:
"""Obtain the value of enable_keda.

This function will verify the parameter by default. If both enable_keda and disable_keda are specified, raise a
MutuallyExclusiveArgumentError.

:return: bool
"""
return self._get_enable_keda(enable_validation=True)

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

This function supports the option of enable_validation. When enabled, if both enable_keda and disable_keda are
specified, raise a MutuallyExclusiveArgumentError.

:return: bool
"""
# Read the original value passed by the command.
disable_keda = self.raw_param.get("disable_keda")

# This option is not supported in create mode, hence we do not read the property value from the `mc` object.
# This parameter does not need dynamic completion.
if enable_validation:
if disable_keda and self._get_enable_keda(enable_validation=False):
raise MutuallyExclusiveArgumentError(
"Cannot specify --enable-keda and --disable-keda at the same time."
)

return disable_keda

def get_disable_keda(self) -> bool:
"""Obtain the value of disable_keda.

This function will verify the parameter by default. If both enable_keda and disable_keda are specified, raise a
MutuallyExclusiveArgumentError.

:return: bool
"""
return self._get_disable_keda(enable_validation=True)


class AKSPreviewManagedClusterCreateDecorator(AKSManagedClusterCreateDecorator):
def __init__(
Expand Down Expand Up @@ -1282,6 +1388,8 @@ def set_up_storage_profile(self, mc: ManagedCluster) -> ManagedCluster:

:return: the ManagedCluster object
"""
self._ensure_mc(mc)

mc.storage_profile = self.context.get_storage_profile()

return mc
Expand All @@ -1291,6 +1399,8 @@ def set_up_ingress_web_app_routing(self, mc: ManagedCluster) -> ManagedCluster:

:return: the ManagedCluster object
"""
self._ensure_mc(mc)

addons = self.context.get_enable_addons()
if "web_application_routing" in addons:
if mc.ingress_profile is None:
Expand All @@ -1302,6 +1412,20 @@ def set_up_ingress_web_app_routing(self, mc: ManagedCluster) -> ManagedCluster:
)
return mc

def set_up_workload_auto_scaler_profile(self, mc: ManagedCluster) -> ManagedCluster:
"""Set up workload auto-scaler profile for the ManagedCluster object.

:return: the ManagedCluster object
"""
self._ensure_mc(mc)

if self.context.get_enable_keda():
if mc.workload_auto_scaler_profile is None:
mc.workload_auto_scaler_profile = self.models.ManagedClusterWorkloadAutoScalerProfile()
mc.workload_auto_scaler_profile.keda = self.models.ManagedClusterWorkloadAutoScalerProfileKeda(enabled=True)

return mc

def construct_mc_profile_preview(self, bypass_restore_defaults: bool = False) -> ManagedCluster:
"""The overall controller used to construct the default ManagedCluster profile.

Expand Down Expand Up @@ -1336,6 +1460,8 @@ def construct_mc_profile_preview(self, bypass_restore_defaults: bool = False) ->
mc = self.set_up_storage_profile(mc)
# set up ingress web app routing profile
mc = self.set_up_ingress_web_app_routing(mc)
# set up workload auto scaler profile
mc = self.set_up_workload_auto_scaler_profile(mc)

# DO NOT MOVE: keep this at the bottom, restore defaults
mc = self._restore_defaults_in_mc(mc)
Expand Down Expand Up @@ -1407,66 +1533,15 @@ def check_raw_parameters(self):
reconcilePrompt = 'no argument specified to update would you like to reconcile to current settings?'
if not prompt_y_n(reconcilePrompt, default="n"):
# Note: Uncomment the followings to automatically generate the error message.
# option_names = [
# '"{}"'.format(format_parameter_name_to_option_name(x))
# for x in self.context.raw_param.keys()
# if x not in excluded_keys
# ]
# error_msg = "Please specify one or more of {}.".format(
# " or ".join(option_names)
# )
# raise RequiredArgumentMissingError(error_msg)
raise RequiredArgumentMissingError(
'Please specify "--enable-cluster-autoscaler" or '
'"--disable-cluster-autoscaler" or '
'"--update-cluster-autoscaler" or '
'"--cluster-autoscaler-profile" or '
'"--enable-pod-security-policy" or '
'"--disable-pod-security-policy" or '
'"--api-server-authorized-ip-ranges" or '
'"--attach-acr" or '
'"--detach-acr" or '
'"--uptime-sla" or '
'"--no-uptime-sla" or '
'"--load-balancer-managed-outbound-ip-count" or '
'"--load-balancer-outbound-ips" or '
'"--load-balancer-outbound-ip-prefixes" or '
'"--nat-gateway-managed-outbound-ip-count" or '
'"--nat-gateway-idle-timeout" or '
'"--enable-aad" or '
'"--aad-tenant-id" or '
'"--aad-admin-group-object-ids" or '
'"--enable-ahub" or '
'"--disable-ahub" or '
'"--enable-managed-identity" or '
'"--enable-pod-identity" or '
'"--disable-pod-identity" or '
'"--auto-upgrade-channel" or '
'"--enable-secret-rotation" or '
'"--disable-secret-rotation" or '
'"--rotation-poll-interval" or '
'"--tags" or '
'"--windows-admin-password" or '
'"--enable-azure-rbac" or '
'"--disable-azure-rbac" or '
'"--enable-local-accounts" or '
'"--disable-local-accounts" or '
'"--enable-public-fqdn" or '
'"--disable-public-fqdn"'
'"--enble-windows-gmsa" or '
'"--nodepool-labels" or '
'"--enable-oidc-issuer" or '
'"--http-proxy-config" or '
'"--enable-disk-driver" or '
'"--disable-disk-driver" or '
'"--enable-file-driver" or '
'"--disable-file-driver" or '
'"--enable-snapshot-controller" or '
'"--disable-snapshot-controller" or '
'"--enable-azure-keyvault-kms" or '
'"--enable-workload-identity" or '
'"--disable-workload-identity".'
option_names = [
'"{}"'.format(format_parameter_name_to_option_name(x))
for x in self.context.raw_param.keys()
if x not in excluded_keys
]
error_msg = "Please specify one or more of {}.".format(
" or ".join(option_names)
)
raise RequiredArgumentMissingError(error_msg)

def update_load_balancer_profile(self, mc: ManagedCluster) -> ManagedCluster:
"""Update load balancer profile for the ManagedCluster object.
Expand Down Expand Up @@ -1624,6 +1699,25 @@ def update_storage_profile(self, mc: ManagedCluster) -> ManagedCluster:

return mc

def update_workload_auto_scaler_profile(self, mc: ManagedCluster) -> ManagedCluster:
"""Update workload auto-scaler profile for the ManagedCluster object.

:return: the ManagedCluster object
"""
self._ensure_mc(mc)

if self.context.get_enable_keda():
if mc.workload_auto_scaler_profile is None:
mc.workload_auto_scaler_profile = self.models.ManagedClusterWorkloadAutoScalerProfile()
mc.workload_auto_scaler_profile.keda = self.models.ManagedClusterWorkloadAutoScalerProfileKeda(enabled=True)

if self.context.get_disable_keda():
if mc.workload_auto_scaler_profile is None:
mc.workload_auto_scaler_profile = self.models.ManagedClusterWorkloadAutoScalerProfile()
mc.workload_auto_scaler_profile.keda = self.models.ManagedClusterWorkloadAutoScalerProfileKeda(enabled=False)

return mc

def update_mc_profile_preview(self) -> ManagedCluster:
"""The overall controller used to update the preview ManagedCluster profile.

Expand Down Expand Up @@ -1653,5 +1747,7 @@ def update_mc_profile_preview(self) -> ManagedCluster:
mc = self.update_azure_keyvault_kms(mc)
# update stroage profile
mc = self.update_storage_profile(mc)
# update workload auto scaler profile
mc = self.update_workload_auto_scaler_profile(mc)

return mc
Loading