Skip to content

Commit

Permalink
Add support for KEDA workload auto-scaler
Browse files Browse the repository at this point in the history
  • Loading branch information
JatinSanghvi committed Jun 3, 2022
1 parent 6dbf738 commit 10be9f6
Show file tree
Hide file tree
Showing 10 changed files with 2,742 additions and 5 deletions.
4 changes: 4 additions & 0 deletions src/aks-preview/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ To release a new version, please select a new version number (usually plus 1 to
Pending
+++++++

0.5.79
++++++

* Add support for KEDA workload auto-scaler.
* Fix `az aks addon list`, `az aks addon list-available` and `az aks addon show` commands when dealing with the web application routing addon.
* Update to use 2022-05-02-preview api version.

Expand Down
9 changes: 9 additions & 0 deletions src/aks-preview/azext_aks_preview/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,9 @@
- name: --enable-custom-ca-trust
type: bool
short-summary: Enable Custom CA Trust on agent node pool.
- name: --enable-keda
type: bool
short-summary: Enable KEDA workload auto-scaler.
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 @@ -761,6 +764,12 @@
- name: --apiserver-subnet-id
type: string
short-summary: The ID of a subnet in an existing VNet into which to assign control plane apiserver pods(requires --enable-apiserver-vnet-integration)
- name: --enable-keda
type: bool
short-summary: Enable KEDA workload auto-scaler.
- name: --disable-keda
type: bool
short-summary: Disable KEDA workload auto-scaler.
examples:
- name: Reconcile the cluster back to its current state.
text: az aks update -g MyResourceGroup -n MyManagedCluster
Expand Down
3 changes: 3 additions & 0 deletions src/aks-preview/azext_aks_preview/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ def load_arguments(self, _):
c.argument('dns-zone-resource-id')
# no validation for aks create because it already only supports Linux.
c.argument('enable_custom_ca_trust', action='store_true')
c.argument('enable_keda', action='store_true', is_preview=True)

with self.argument_context('aks update') as c:
# managed cluster paramerters
Expand Down Expand Up @@ -380,6 +381,8 @@ def load_arguments(self, _):
c.argument('azure_keyvault_kms_key_id', validator=validate_azure_keyvault_kms_key_id, is_preview=True)
c.argument('enable_apiserver_vnet_integration', action='store_true', is_preview=True)
c.argument('apiserver_subnet_id', validator=validate_apiserver_subnet_id, is_preview=True)
c.argument('enable_keda', action='store_true', is_preview=True)
c.argument('disable_keda', action='store_true', is_preview=True)

with self.argument_context('aks scale') as c:
c.argument('nodepool_name',
Expand Down
3 changes: 3 additions & 0 deletions src/aks-preview/azext_aks_preview/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,7 @@ def aks_create(cmd,
apiserver_subnet_id=None,
dns_zone_resource_id=None,
enable_custom_ca_trust=False,
enable_keda=False,
yes=False):
# DO NOT MOVE: get all the original parameters and save them as a dictionary
raw_parameters = locals()
Expand Down Expand Up @@ -911,6 +912,8 @@ def aks_update(cmd, # pylint: disable=too-many-statements,too-many-branches,
azure_keyvault_kms_key_id=None,
enable_apiserver_vnet_integration=False,
apiserver_subnet_id=None,
enable_keda=False,
disable_keda=False,
):
# DO NOT MOVE: get all the original parameters and save them as a dictionary
raw_parameters = locals()
Expand Down
126 changes: 124 additions & 2 deletions src/aks-preview/azext_aks_preview/decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@
AzureKeyVaultKms = TypeVar('AzureKeyVaultKms')
ManagedClusterIngressProfile = TypeVar('ManagedClusterIngressProfile')
ManagedClusterIngressProfileWebAppRouting = TypeVar('ManagedClusterIngressProfileWebAppRouting')
ManagedClusterWorkloadAutoScalerProfile = TypeVar('ManagedClusterWorkloadAutoScalerProfile')
ManagedClusterWorkloadAutoScalerProfileKeda = TypeVar('ManagedClusterWorkloadAutoScalerProfileKeda')


# pylint: disable=too-many-instance-attributes,too-few-public-methods
Expand Down Expand Up @@ -186,6 +188,16 @@ def __init__(self, cmd: AzCommandsLoader, resource_type: ResourceType):
resource_type=self.resource_type,
operation_group="managed_clusters",
)
self.ManagedClusterWorkloadAutoScalerProfile = self.__cmd.get_models(
"ManagedClusterWorkloadAutoScalerProfile",
resource_type=self.resource_type,
operation_group="managed_clusters",
)
self.ManagedClusterWorkloadAutoScalerProfileKeda = self.__cmd.get_models(
"ManagedClusterWorkloadAutoScalerProfileKeda",
resource_type=self.resource_type,
operation_group="managed_clusters",
)
# holder for nat gateway related models
self.__nat_gateway_models = None
# holder for pod identity related models
Expand Down Expand Up @@ -2141,6 +2153,76 @@ def get_apiserver_subnet_id(self) -> Union[str, None]:
"""
return self._get_apiserver_subnet_id(enable_validation=True)

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 AKSPreviewCreateDecorator(AKSCreateDecorator):
# pylint: disable=super-init-not-called
Expand Down Expand Up @@ -2558,6 +2640,21 @@ def set_up_api_server_access_profile(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
"""
if not isinstance(mc, self.models.ManagedCluster):
raise CLIInternalError(f"Unexpected mc object with type '{type(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_preview_profile(self) -> ManagedCluster:
"""The overall controller used to construct the preview ManagedCluster profile.
Expand Down Expand Up @@ -2590,6 +2687,8 @@ def construct_mc_preview_profile(self) -> ManagedCluster:

mc = self.set_up_storage_profile(mc)

mc = self.set_up_workload_auto_scaler_profile(mc)

return mc

def create_mc_preview(self, mc: ManagedCluster) -> ManagedCluster:
Expand Down Expand Up @@ -2742,7 +2841,7 @@ def check_raw_parameters(self):
'"--disable-local-accounts" or '
'"--enable-public-fqdn" or '
'"--disable-public-fqdn"'
'"--enble-windows-gmsa" or '
'"--enable-windows-gmsa" or '
'"--nodepool-labels" or '
'"--enable-oidc-issuer" or '
'"--http-proxy-config" or '
Expand All @@ -2755,7 +2854,9 @@ def check_raw_parameters(self):
'"--disable-snapshot-controller" or '
'"--enable-azure-keyvault-kms" or '
'"--enable-workload-identity" or '
'"--disable-workload-identity".'
'"--disable-workload-identity" or '
'"--enable-keda" or '
'"--disable-keda".'
)

def update_load_balancer_profile(self, mc: ManagedCluster) -> ManagedCluster:
Expand Down Expand Up @@ -2980,6 +3081,25 @@ def update_api_server_access_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 patch_mc(self, mc: ManagedCluster) -> ManagedCluster:
"""Helper function to patch the ManagedCluster object.
Expand Down Expand Up @@ -3027,6 +3147,8 @@ def update_mc_preview_profile(self) -> ManagedCluster:

mc = self.update_storage_profile(mc)

mc = self.update_workload_auto_scaler_profile(mc)

return mc

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

0 comments on commit 10be9f6

Please sign in to comment.