diff --git a/src/aks-preview/azext_aks_preview/__init__.py b/src/aks-preview/azext_aks_preview/__init__.py index 52b9354c89f..7172e879767 100644 --- a/src/aks-preview/azext_aks_preview/__init__.py +++ b/src/aks-preview/azext_aks_preview/__init__.py @@ -27,23 +27,20 @@ def __init__(self, cli_ctx=None): register_aks_preview_resource_type() acs_custom = CliCommandType(operations_tmpl='azext_aks_preview.custom#{}') - super(ContainerServiceCommandsLoader, self).__init__(cli_ctx=cli_ctx, - custom_command_type=acs_custom, - resource_type=CUSTOM_MGMT_AKS_PREVIEW) + super().__init__( + cli_ctx=cli_ctx, + custom_command_type=acs_custom, + resource_type=CUSTOM_MGMT_AKS_PREVIEW, + ) def load_command_table(self, args): - super(ContainerServiceCommandsLoader, self).load_command_table(args) + super().load_command_table(args) from azext_aks_preview.commands import load_command_table load_command_table(self, args) return self.command_table def load_arguments(self, command): - from sys import version_info - if version_info[0] < 3: - super(ContainerServiceCommandsLoader, self).load_arguments(command) - else: - super().load_arguments(command) - + super().load_arguments(command) from azext_aks_preview._params import load_arguments load_arguments(self, command) diff --git a/src/aks-preview/azext_aks_preview/_client_factory.py b/src/aks-preview/azext_aks_preview/_client_factory.py index 23f5ca8277b..1079efbe18f 100644 --- a/src/aks-preview/azext_aks_preview/_client_factory.py +++ b/src/aks-preview/azext_aks_preview/_client_factory.py @@ -99,7 +99,7 @@ def get_auth_management_client(cli_ctx, scope=None, **_): if matched: subscription_id = matched.groupdict()['subscription'] else: - raise CLIError("{} does not contain subscription Id.".format(scope)) + raise CLIError(f"{scope} does not contain subscription Id.") return get_mgmt_service_client(cli_ctx, ResourceType.MGMT_AUTHORIZATION, subscription_id=subscription_id) @@ -129,23 +129,22 @@ def get_resource_by_name(cli_ctx, resource_name, resource_type): if not elements: from azure.cli.core._profile import Profile profile = Profile(cli_ctx=cli_ctx) - message = "The resource with name '{}' and type '{}' could not be found".format( - resource_name, resource_type) + message = f"The resource with name '{resource_name}' and type '{resource_type}' could not be found" try: subscription = profile.get_subscription( cli_ctx.data['subscription_id']) raise CLIError( - "{} in subscription '{} ({})'.".format(message, subscription['name'], subscription['id'])) - except (KeyError, TypeError): - raise CLIError( - "{} in the current subscription.".format(message)) + f"{message} in subscription '{subscription['name']} ({subscription['id']})'." + ) + except (KeyError, TypeError) as exc: + raise CLIError(f"{message} in the current subscription.") from exc elif len(elements) == 1: return elements[0] else: raise CLIError( - "More than one resources with type '{}' are found with name '{}'.".format( - resource_type, resource_name)) + f"More than one resources with type '{resource_type}' are found with name '{resource_name}'." + ) def get_msi_client(cli_ctx, subscription_id=None): @@ -154,7 +153,11 @@ def get_msi_client(cli_ctx, subscription_id=None): def get_providers_client_factory(cli_ctx, subscription_id=None): - return get_mgmt_service_client(cli_ctx, ResourceType.MGMT_RESOURCE_RESOURCES, subscription_id=subscription_id).providers + return get_mgmt_service_client( + cli_ctx, + ResourceType.MGMT_RESOURCE_RESOURCES, + subscription_id=subscription_id + ).providers def get_keyvault_client(cli_ctx, subscription_id=None): diff --git a/src/aks-preview/azext_aks_preview/_completers.py b/src/aks-preview/azext_aks_preview/_completers.py index b5a0511d5b5..080b08caae3 100644 --- a/src/aks-preview/azext_aks_preview/_completers.py +++ b/src/aks-preview/azext_aks_preview/_completers.py @@ -88,4 +88,5 @@ def _get_location_from_resource_group(cli_ctx, resource_group_name): # Print a warning if the user hit [TAB] but the `--resource-group` argument was incorrect. # For example: "Warning: Resource group 'bogus' could not be found." from argcomplete import warn - warn('Warning: {}'.format(err.message)) + warn(f'Warning: {err.message}') + return None diff --git a/src/aks-preview/azext_aks_preview/_consts.py b/src/aks-preview/azext_aks_preview/_consts.py index 2da0577b47a..e599c35a446 100644 --- a/src/aks-preview/azext_aks_preview/_consts.py +++ b/src/aks-preview/azext_aks_preview/_consts.py @@ -67,7 +67,11 @@ 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?" +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 CONST_LOAD_BALANCER_BACKEND_POOL_TYPE_NODE_IP = "nodeIP" CONST_LOAD_BALANCER_BACKEND_POOL_TYPE_NODE_IPCONFIGURATION = "nodeIPConfiguration" @@ -77,8 +81,8 @@ CONST_PRIVATE_DNS_ZONE_NONE = "none" # used to set identity profile (for kubelet) -CONST_MANAGED_IDENTITY_OPERATOR_ROLE = 'Managed Identity Operator' -CONST_MANAGED_IDENTITY_OPERATOR_ROLE_ID = 'f1a07417-d97a-45cb-824c-7a7467783830' +CONST_MANAGED_IDENTITY_OPERATOR_ROLE = "Managed Identity Operator" +CONST_MANAGED_IDENTITY_OPERATOR_ROLE_ID = "f1a07417-d97a-45cb-824c-7a7467783830" # consts for upgrade channel CONST_RAPID_UPGRADE_CHANNEL = "rapid" @@ -168,31 +172,42 @@ # all supported addons ADDONS = { - 'http_application_routing': CONST_HTTP_APPLICATION_ROUTING_ADDON_NAME, - 'monitoring': CONST_MONITORING_ADDON_NAME, - 'virtual-node': CONST_VIRTUAL_NODE_ADDON_NAME, - 'kube-dashboard': CONST_KUBE_DASHBOARD_ADDON_NAME, - 'azure-policy': CONST_AZURE_POLICY_ADDON_NAME, - 'ingress-appgw': CONST_INGRESS_APPGW_ADDON_NAME, + "http_application_routing": CONST_HTTP_APPLICATION_ROUTING_ADDON_NAME, + "monitoring": CONST_MONITORING_ADDON_NAME, + "virtual-node": CONST_VIRTUAL_NODE_ADDON_NAME, + "kube-dashboard": CONST_KUBE_DASHBOARD_ADDON_NAME, + "azure-policy": CONST_AZURE_POLICY_ADDON_NAME, + "ingress-appgw": CONST_INGRESS_APPGW_ADDON_NAME, "confcom": CONST_CONFCOM_ADDON_NAME, - 'open-service-mesh': CONST_OPEN_SERVICE_MESH_ADDON_NAME, - 'azure-keyvault-secrets-provider': CONST_AZURE_KEYVAULT_SECRETS_PROVIDER_ADDON_NAME, - 'gitops': CONST_GITOPS_ADDON_NAME, - 'web_application_routing': CONST_WEB_APPLICATION_ROUTING_KEY_NAME + "open-service-mesh": CONST_OPEN_SERVICE_MESH_ADDON_NAME, + "azure-keyvault-secrets-provider": CONST_AZURE_KEYVAULT_SECRETS_PROVIDER_ADDON_NAME, + "gitops": CONST_GITOPS_ADDON_NAME, + "web_application_routing": CONST_WEB_APPLICATION_ROUTING_KEY_NAME, } ADDONS_DESCRIPTIONS = { - CONST_HTTP_APPLICATION_ROUTING_ADDON_NAME: '- configure ingress with automatic public DNS name creation', - CONST_MONITORING_ADDON_NAME: '- turn on Log Analytics monitoring. Uses the Log Analytics Default Workspace if it exists, else creates one. Specify "--workspace-resource-id" to use an existing workspace.\nIf monitoring addon is enabled --no-wait argument will have no effect.', - CONST_VIRTUAL_NODE_ADDON_NAME: '- enable AKS Virtual Node. Requires --aci-subnet-name to provide the name of an existing subnet for the Virtual Node to use.\naci-subnet-name must be in the same vnet which is specified by --vnet-subnet-id (required as well).', - CONST_KUBE_DASHBOARD_ADDON_NAME: '- n/a', - CONST_AZURE_POLICY_ADDON_NAME: '- enable Azure policy. The Azure Policy add-on for AKS enables at-scale enforcements and safeguards on your clusters in a centralized, consistent manner.\nLearn more at aka.ms/aks/policy.', - CONST_INGRESS_APPGW_ADDON_NAME: '- enable Application Gateway Ingress Controller addon (PREVIEW).', - CONST_CONFCOM_ADDON_NAME: '- enable confcom addon, this will enable SGX device plugin by default (PREVIEW).', - CONST_OPEN_SERVICE_MESH_ADDON_NAME: '- enable Open Service Mesh addon (PREVIEW).', - CONST_AZURE_KEYVAULT_SECRETS_PROVIDER_ADDON_NAME: '- enable Azure Keyvault Secrets Provider addon.', - CONST_GITOPS_ADDON_NAME: '- enable GitOps (PREVIEW).', - CONST_WEB_APPLICATION_ROUTING_KEY_NAME: '- enable web application routing (PREVIEW).' + CONST_HTTP_APPLICATION_ROUTING_ADDON_NAME: "- configure ingress with automatic public DNS name creation", + CONST_MONITORING_ADDON_NAME: ( + "- turn on Log Analytics monitoring. Uses the Log Analytics Default Workspace if it exists, " + 'else creates one. Specify "--workspace-resource-id" to use an existing workspace.\n' + "If monitoring addon is enabled --no-wait argument will have no effect." + ), + CONST_VIRTUAL_NODE_ADDON_NAME: ( + "- enable AKS Virtual Node. Requires --aci-subnet-name to provide the name of an existing subnet for " + "the Virtual Node to use.\naci-subnet-name must be in the same vnet which is specified by " + "--vnet-subnet-id (required as well)." + ), + CONST_KUBE_DASHBOARD_ADDON_NAME: "- n/a", + CONST_AZURE_POLICY_ADDON_NAME: ( + "- enable Azure policy. The Azure Policy add-on for AKS enables at-scale enforcements and safeguards on " + "your clusters in a centralized, consistent manner.\nLearn more at aka.ms/aks/policy." + ), + CONST_INGRESS_APPGW_ADDON_NAME: "- enable Application Gateway Ingress Controller addon (PREVIEW).", + CONST_CONFCOM_ADDON_NAME: "- enable confcom addon, this will enable SGX device plugin by default (PREVIEW).", + CONST_OPEN_SERVICE_MESH_ADDON_NAME: "- enable Open Service Mesh addon (PREVIEW).", + CONST_AZURE_KEYVAULT_SECRETS_PROVIDER_ADDON_NAME: "- enable Azure Keyvault Secrets Provider addon.", + CONST_GITOPS_ADDON_NAME: "- enable GitOps (PREVIEW).", + CONST_WEB_APPLICATION_ROUTING_KEY_NAME: "- enable web application routing (PREVIEW).", } # consts for credential @@ -218,22 +233,24 @@ # Moving away from 1:n release to avoid unwanted breaking changes with auto upgrades. CONST_DRAFT_CLI_VERSION = "v0.0.22" -CONST_CUSTOM_CA_TEST_CERT = '-----BEGIN CERTIFICATE-----\n' \ - 'MIICljCCAX4CCQC9zUAgqqqrWzANBgkqhkiG9w0BAQsFADANMQswCQYDVQQGEwJQ\n' \ - 'TDAeFw0yMjA5MTQwNjIzMjdaFw0yMjA5MTUwNjIzMjdaMA0xCzAJBgNVBAYTAlBM\n' \ - 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAopKNIIbvvcPCw9fc4KLX\n' \ - 'KDtRZobp5L+/1hCN+3OGhk5NvSTpSUrFifxqc0o3IF7YkO3K1n2jAvCMXO16Bf9b\n' \ - 'OAR7VkCrwGFVkXNjM4wvXAX8CNNvjqd1zDPXSKdE7Wd8k3fTzx6nGUM0UgljIPhH\n' \ - 'yh4a4Zujd5Ig2P/ZSX0pGJm47JTtMu7MDFHVM5wRWcCrN/H0TCYPIvEOs0B8AZxc\n' \ - 'p3TF7A6veT5U9pVhQ3Xl9JN6LvvLqPxG3ea10rdv9DYzaiXmSY3ujI3Ri1Q11uWC\n' \ - 'dtrFIpFu5cHW2OBW+jBXxL0v8xQmkxTLik4BR/PLCl30wxKQNsq3pjDgu0mutKuu\n' \ - '5wIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAVEAIs/hLwTVCwpEXdoXR24LelNNuB\n' \ - '/8ptK6lyjE11XwfMN3yy7F2oB1lrA4rI3j9obpDsHDJBNB13bi/lKgvAcbIn/Tyu\n' \ - 'RKThtUdPgxNnqDUyxnb3OofMF3gB8ePTu+jZpd3zrlEuxdl40ByATCSyOgR6DHMt\n' \ - 'SDd+joypnOHFAeSM+V0AaTelXSCK9OAWSAp5e6S76a6lRx+D5Xl3hBedBI0tX59h\n' \ - 'tEYNEGZaRElFU79WcEF0cH+ZW0+jJ95xE3thZffRz6QI6yF63m8aC9l9bbdJS2zg\n' \ - 'Yv8W+lCZi//ODeOBUugr++z9uj+vGk47JDSpV0n4JOun3ALUDJ0gqmcS\n' \ - '-----END CERTIFICATE-----' +CONST_CUSTOM_CA_TEST_CERT = ( + "-----BEGIN CERTIFICATE-----\n" + "MIICljCCAX4CCQC9zUAgqqqrWzANBgkqhkiG9w0BAQsFADANMQswCQYDVQQGEwJQ\n" + "TDAeFw0yMjA5MTQwNjIzMjdaFw0yMjA5MTUwNjIzMjdaMA0xCzAJBgNVBAYTAlBM\n" + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAopKNIIbvvcPCw9fc4KLX\n" + "KDtRZobp5L+/1hCN+3OGhk5NvSTpSUrFifxqc0o3IF7YkO3K1n2jAvCMXO16Bf9b\n" + "OAR7VkCrwGFVkXNjM4wvXAX8CNNvjqd1zDPXSKdE7Wd8k3fTzx6nGUM0UgljIPhH\n" + "yh4a4Zujd5Ig2P/ZSX0pGJm47JTtMu7MDFHVM5wRWcCrN/H0TCYPIvEOs0B8AZxc\n" + "p3TF7A6veT5U9pVhQ3Xl9JN6LvvLqPxG3ea10rdv9DYzaiXmSY3ujI3Ri1Q11uWC\n" + "dtrFIpFu5cHW2OBW+jBXxL0v8xQmkxTLik4BR/PLCl30wxKQNsq3pjDgu0mutKuu\n" + "5wIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAVEAIs/hLwTVCwpEXdoXR24LelNNuB\n" + "/8ptK6lyjE11XwfMN3yy7F2oB1lrA4rI3j9obpDsHDJBNB13bi/lKgvAcbIn/Tyu\n" + "RKThtUdPgxNnqDUyxnb3OofMF3gB8ePTu+jZpd3zrlEuxdl40ByATCSyOgR6DHMt\n" + "SDd+joypnOHFAeSM+V0AaTelXSCK9OAWSAp5e6S76a6lRx+D5Xl3hBedBI0tX59h\n" + "tEYNEGZaRElFU79WcEF0cH+ZW0+jJ95xE3thZffRz6QI6yF63m8aC9l9bbdJS2zg\n" + "Yv8W+lCZi//ODeOBUugr++z9uj+vGk47JDSpV0n4JOun3ALUDJ0gqmcS\n" + "-----END CERTIFICATE-----" +) # consts for maintenance configuration schedule type CONST_DAILY_MAINTENANCE_SCHEDULE = "Daily" diff --git a/src/aks-preview/azext_aks_preview/_format.py b/src/aks-preview/azext_aks_preview/_format.py index b77e8797b83..82c4b9f5c06 100644 --- a/src/aks-preview/azext_aks_preview/_format.py +++ b/src/aks-preview/azext_aks_preview/_format.py @@ -136,28 +136,6 @@ def find_preview_versions(versions_bag): return parsed.search(result, Options(dict_cls=OrderedDict, custom_functions=_custom_functions(preview))) -def aks_versions_table_format(result): - """Format get-versions results as a summary for display with "-o table".""" - - # get preview orchestrator version - preview = {} - - def find_preview_versions(): - for orchestrator in result.get('orchestrators', []): - if orchestrator.get('isPreview', False): - preview[orchestrator['orchestratorVersion']] = True - find_preview_versions() - - parsed = compile_jmes("""orchestrators[].{ - kubernetesVersion: orchestratorVersion | set_preview(@), - upgrades: upgrades[].orchestratorVersion || [`None available`] | sort_versions(@) | set_preview_array(@) | join(`, `, @) - }""") - # use ordered dicts so headers are predictable - results = parsed.search(result, Options( - dict_cls=OrderedDict, custom_functions=_custom_functions(preview))) - return sorted(results, key=lambda x: version_to_tuple(x.get('kubernetesVersion')), reverse=True) - - def version_to_tuple(version): """Removes preview suffix""" if version.endswith('(preview)'): @@ -181,7 +159,7 @@ def _custom_functions(preview_versions): class CustomFunctions(functions.Functions): # pylint: disable=too-few-public-methods @ functions.signature({'types': ['array']}) - def _func_sort_versions(self, versions): # pylint: disable=no-self-use + def _func_sort_versions(self, versions): """Custom JMESPath `sort_versions` function that sorts an array of strings as software versions""" try: return sorted(versions, key=version_to_tuple) @@ -196,26 +174,26 @@ def _func_set_preview_array(self, versions): for i, _ in enumerate(versions): versions[i] = self._func_set_preview(versions[i]) return versions - except(TypeError, ValueError): + except (TypeError, ValueError): return versions @ functions.signature({'types': ['string']}) - def _func_set_preview(self, version): # pylint: disable=no-self-use + def _func_set_preview(self, version): """Custom JMESPath `set_preview` function that suffixes preview version""" try: if preview_versions.get(version, False): return version + '(preview)' return version - except(TypeError, ValueError): + except (TypeError, ValueError): return version @ functions.signature({'types': ['object']}) - def _func_pprint_labels(self, labels): # pylint: disable=no-self-use + def _func_pprint_labels(self, labels): """Custom JMESPath `pprint_labels` function that pretty print labels""" if not labels: return '' return ' '.join([ - '{}={}'.format(k, labels[k]) + f'{k}={labels[k]}' for k in sorted(labels.keys()) ]) diff --git a/src/aks-preview/azext_aks_preview/_help.py b/src/aks-preview/azext_aks_preview/_help.py index f6fc9efa350..f72febe505c 100644 --- a/src/aks-preview/azext_aks_preview/_help.py +++ b/src/aks-preview/azext_aks_preview/_help.py @@ -4,6 +4,7 @@ # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- +# pylint: disable=too-many-lines import os.path from knack.help_files import helps @@ -14,7 +15,7 @@ '$HOME', '.azure', 'aksServicePrincipal.json') # AKS command help -helps['aks create'] = """ +helps['aks create'] = f""" type: command short-summary: Create a new managed Kubernetes cluster. parameters: @@ -25,7 +26,7 @@ type: string short-summary: Service principal used for authentication to Azure APIs. long-summary: If not specified, a new service principal is created and cached at - {sp_cache} to be used by subsequent `az aks` commands. + {AKS_SERVICE_PRINCIPAL_CACHE} to be used by subsequent `az aks` commands. - name: --skip-subnet-role-assignment type: bool short-summary: Skip role assignment for subnet (advanced networking). @@ -656,7 +657,7 @@ - name: Create a kubernetes cluster with Azure Monitor Metrics enabled. text: az aks create -g MyResourceGroup -n MyManagedCluster --enable-azuremonitormetrics -""".format(sp_cache=AKS_SERVICE_PRINCIPAL_CACHE) +""" helps['aks scale'] = """ type: command diff --git a/src/aks-preview/azext_aks_preview/_helpers.py b/src/aks-preview/azext_aks_preview/_helpers.py index f33af5b1ba8..32b9add8154 100644 --- a/src/aks-preview/azext_aks_preview/_helpers.py +++ b/src/aks-preview/azext_aks_preview/_helpers.py @@ -8,21 +8,25 @@ import re import stat import tempfile +from typing import TypeVar + import yaml -from typing import Any, List, TypeVar +from azext_aks_preview._client_factory import ( + get_mc_snapshots_client, + get_nodepool_snapshots_client, +) from azure.cli.command_modules.acs._helpers import map_azure_error_to_cli_error -from azure.cli.core.azclierror import InvalidArgumentValueError, ResourceNotFoundError, FileOperationError +from azure.cli.command_modules.acs._validators import extract_comma_separated_string +from azure.cli.core.azclierror import ( + FileOperationError, + InvalidArgumentValueError, + ResourceNotFoundError, +) from azure.core.exceptions import AzureError from knack.log import get_logger from knack.prompting import NoTTYException, prompt_y_n from knack.util import CLIError -from azext_aks_preview._client_factory import get_nodepool_snapshots_client, get_mc_snapshots_client - -from azure.cli.command_modules.acs._validators import ( - extract_comma_separated_string, -) - logger = get_logger(__name__) # type variables @@ -103,8 +107,7 @@ def _merge_kubernetes_configurations(existing_file, addition_file, replace, cont continue if addition is None: - raise CLIError( - 'failed to load additional configuration from {}'.format(addition_file)) + raise CLIError(f'failed to load additional configuration from {addition_file}') if existing is None: existing = addition @@ -116,6 +119,7 @@ def _merge_kubernetes_configurations(existing_file, addition_file, replace, cont # check that ~/.kube/config is only read- and writable by its owner if platform.system() != "Windows" and not os.path.islink(existing_file): + # pylint: disable=consider-using-f-string existing_file_perms = "{:o}".format(stat.S_IMODE(os.lstat(existing_file).st_mode)) if not existing_file_perms.endswith("600"): logger.warning( @@ -124,25 +128,24 @@ def _merge_kubernetes_configurations(existing_file, addition_file, replace, cont existing_file_perms, ) - with open(existing_file, 'w+') as stream: + with open(existing_file, 'w+', encoding="utf-8") as stream: yaml.safe_dump(existing, stream, default_flow_style=False) current_context = addition.get('current-context', 'UNKNOWN') - msg = 'Merged "{}" as current context in {}'.format( - current_context, existing_file) + msg = f'Merged "{current_context}" as current context in {existing_file}' logger.warning(msg) def _load_kubernetes_configuration(filename): try: - with open(filename) as stream: + with open(filename, encoding="utf-8") as stream: return yaml.safe_load(stream) except (IOError, OSError) as ex: if getattr(ex, 'errno', 0) == errno.ENOENT: - raise CLIError('{} does not exist'.format(filename)) + raise CLIError(f'{filename} does not exist') from ex raise except (yaml.parser.ParserError, UnicodeDecodeError) as ex: - raise CLIError('Error parsing {} ({})'.format(filename, str(ex))) + raise CLIError(f'Error parsing {filename} ({str(ex)})') from ex def _handle_merge(existing, addition, key, replace): @@ -150,10 +153,8 @@ def _handle_merge(existing, addition, key, replace): return if key not in existing: raise FileOperationError( - "No such key '{}' in existing config, please confirm whether it is a valid config file. " - "May back up this config file, delete it and retry the command.".format( - key - ) + f"No such key '{key}' in existing config, please confirm whether it is a valid config file. " + "May back up this config file, delete it and retry the command." ) if not existing.get(key): existing[key] = addition[key] @@ -195,7 +196,7 @@ def similar_word(a, b): a_len = len(a) b_len = len(b) if a_len > b_len: # @a should always be the shorter string - return similar_word(b, a) + return similar_word(b, a) # pylint: disable=arguments-out-of-order if a in b: return True if b_len - a_len > 1: @@ -237,7 +238,7 @@ def get_nodepool_snapshot_by_snapshot_id(cli_ctx, snapshot_id): resource_group_name = match.group(2) snapshot_name = match.group(3) return get_nodepool_snapshot(cli_ctx, subscription_id, resource_group_name, snapshot_name) - raise InvalidArgumentValueError("Cannot parse snapshot name from provided resource id '{}'.".format(snapshot_id)) + raise InvalidArgumentValueError(f"Cannot parse snapshot name from provided resource id '{snapshot_id}'.") def get_nodepool_snapshot(cli_ctx, subscription_id, resource_group_name, snapshot_name): @@ -247,8 +248,9 @@ def get_nodepool_snapshot(cli_ctx, subscription_id, resource_group_name, snapsho # track 2 sdk raise exception from azure.core.exceptions except AzureError as ex: if "not found" in ex.message: - raise ResourceNotFoundError("Snapshot '{}' not found.".format(snapshot_name)) - raise map_azure_error_to_cli_error(ex) + # pylint: disable=raise-missing-from + raise ResourceNotFoundError(f"Snapshot '{snapshot_name}' not found.") + raise map_azure_error_to_cli_error(ex) from ex return snapshot @@ -265,7 +267,8 @@ def get_cluster_snapshot_by_snapshot_id(cli_ctx, snapshot_id): snapshot_name = match.group(3) return get_cluster_snapshot(cli_ctx, subscription_id, resource_group_name, snapshot_name) raise InvalidArgumentValueError( - "Cannot parse snapshot name from provided resource id {}.".format(snapshot_id)) + f"Cannot parse snapshot name from provided resource id {snapshot_id}." + ) def get_cluster_snapshot(cli_ctx, subscription_id, resource_group_name, snapshot_name): @@ -275,8 +278,9 @@ def get_cluster_snapshot(cli_ctx, subscription_id, resource_group_name, snapshot # track 2 sdk raise exception from azure.core.exceptions except AzureError as ex: if "not found" in ex.message: - raise ResourceNotFoundError("Managed cluster snapshot '{}' not found.".format(snapshot_name)) - raise map_azure_error_to_cli_error(ex) + # pylint: disable=raise-missing-from + raise ResourceNotFoundError(f"Managed cluster snapshot '{snapshot_name}' not found.") + raise map_azure_error_to_cli_error(ex) from ex return snapshot diff --git a/src/aks-preview/azext_aks_preview/_loadbalancer.py b/src/aks-preview/azext_aks_preview/_loadbalancer.py index 4acc2ebfa25..6d2aeb4b97d 100644 --- a/src/aks-preview/azext_aks_preview/_loadbalancer.py +++ b/src/aks-preview/azext_aks_preview/_loadbalancer.py @@ -9,49 +9,120 @@ logger = get_logger(__name__) -def update_load_balancer_profile(managed_outbound_ip_count, managed_outbound_ipv6_count, outbound_ips, - outbound_ip_prefixes, outbound_ports, idle_timeout, backend_pool_type, profile, models): +def update_load_balancer_profile( + managed_outbound_ip_count, + managed_outbound_ipv6_count, + outbound_ips, + outbound_ip_prefixes, + outbound_ports, + idle_timeout, + backend_pool_type, + profile, + models, +): """parse and update an existing load balancer profile""" - if not (is_load_balancer_profile_provided(managed_outbound_ip_count, managed_outbound_ipv6_count, outbound_ips, - outbound_ip_prefixes, outbound_ports, idle_timeout) or backend_pool_type): + if not ( + is_load_balancer_profile_provided( + managed_outbound_ip_count, + managed_outbound_ipv6_count, + outbound_ips, + outbound_ip_prefixes, + outbound_ports, + idle_timeout, + ) + or backend_pool_type + ): return profile if not profile: if isinstance(models, SimpleNamespace): ManagedClusterLoadBalancerProfile = models.ManagedClusterLoadBalancerProfile else: - ManagedClusterLoadBalancerProfile = models.get("ManagedClusterLoadBalancerProfile") + ManagedClusterLoadBalancerProfile = models.get( + "ManagedClusterLoadBalancerProfile" + ) profile = ManagedClusterLoadBalancerProfile() - return configure_load_balancer_profile(managed_outbound_ip_count, managed_outbound_ipv6_count, outbound_ips, - outbound_ip_prefixes, outbound_ports, idle_timeout, backend_pool_type, profile, models) - - -def create_load_balancer_profile(managed_outbound_ip_count, managed_outbound_ipv6_count, outbound_ips, - outbound_ip_prefixes, outbound_ports, idle_timeout, backend_pool_type, models): + return configure_load_balancer_profile( + managed_outbound_ip_count, + managed_outbound_ipv6_count, + outbound_ips, + outbound_ip_prefixes, + outbound_ports, + idle_timeout, + backend_pool_type, + profile, + models, + ) + + +def create_load_balancer_profile( + managed_outbound_ip_count, + managed_outbound_ipv6_count, + outbound_ips, + outbound_ip_prefixes, + outbound_ports, + idle_timeout, + backend_pool_type, + models, +): """parse and build load balancer profile""" - if not (is_load_balancer_profile_provided(managed_outbound_ip_count, managed_outbound_ipv6_count, outbound_ips, - outbound_ip_prefixes, outbound_ports, idle_timeout) or backend_pool_type): + if not ( + is_load_balancer_profile_provided( + managed_outbound_ip_count, + managed_outbound_ipv6_count, + outbound_ips, + outbound_ip_prefixes, + outbound_ports, + idle_timeout, + ) + or backend_pool_type + ): return None if isinstance(models, SimpleNamespace): ManagedClusterLoadBalancerProfile = models.ManagedClusterLoadBalancerProfile else: - ManagedClusterLoadBalancerProfile = models.get("ManagedClusterLoadBalancerProfile") + ManagedClusterLoadBalancerProfile = models.get( + "ManagedClusterLoadBalancerProfile" + ) profile = ManagedClusterLoadBalancerProfile() - return configure_load_balancer_profile(managed_outbound_ip_count, managed_outbound_ipv6_count, outbound_ips, - outbound_ip_prefixes, outbound_ports, idle_timeout, backend_pool_type, profile, models) - - -def configure_load_balancer_profile(managed_outbound_ip_count, managed_outbound_ipv6_count, outbound_ips, - outbound_ip_prefixes, outbound_ports, idle_timeout, backend_pool_type, profile, models): + return configure_load_balancer_profile( + managed_outbound_ip_count, + managed_outbound_ipv6_count, + outbound_ips, + outbound_ip_prefixes, + outbound_ports, + idle_timeout, + backend_pool_type, + profile, + models, + ) + + +def configure_load_balancer_profile( + managed_outbound_ip_count, + managed_outbound_ipv6_count, + outbound_ips, + outbound_ip_prefixes, + outbound_ports, + idle_timeout, + backend_pool_type, + profile, + models, +): """configure a load balancer with customer supplied values""" - if any([managed_outbound_ip_count, + if any( + [ + managed_outbound_ip_count, managed_outbound_ipv6_count, outbound_ips, - outbound_ip_prefixes]): - + outbound_ip_prefixes, + ] + ): outbound_ip_resources = _get_load_balancer_outbound_ips(outbound_ips, models) if outbound_ip_resources: if isinstance(models, SimpleNamespace): - ManagedClusterLoadBalancerProfileOutboundIPs = models.ManagedClusterLoadBalancerProfileOutboundIPs + ManagedClusterLoadBalancerProfileOutboundIPs = ( + models.ManagedClusterLoadBalancerProfileOutboundIPs + ) else: ManagedClusterLoadBalancerProfileOutboundIPs = models.get( "ManagedClusterLoadBalancerProfileOutboundIPs" @@ -62,7 +133,9 @@ def configure_load_balancer_profile(managed_outbound_ip_count, managed_outbound_ ) else: profile.outbound_i_ps = None - outbound_ip_prefix_resources = _get_load_balancer_outbound_ip_prefixes(outbound_ip_prefixes, models) + outbound_ip_prefix_resources = _get_load_balancer_outbound_ip_prefixes( + outbound_ip_prefixes, models + ) if outbound_ip_prefix_resources: if isinstance(models, SimpleNamespace): ManagedClusterLoadBalancerProfileOutboundIPPrefixes = ( @@ -72,8 +145,10 @@ def configure_load_balancer_profile(managed_outbound_ip_count, managed_outbound_ ManagedClusterLoadBalancerProfileOutboundIPPrefixes = models.get( "ManagedClusterLoadBalancerProfileOutboundIPPrefixes" ) - profile.outbound_ip_prefixes = ManagedClusterLoadBalancerProfileOutboundIPPrefixes( - public_ip_prefixes=outbound_ip_prefix_resources + profile.outbound_ip_prefixes = ( + ManagedClusterLoadBalancerProfileOutboundIPPrefixes( + public_ip_prefixes=outbound_ip_prefix_resources + ) ) else: profile.outbound_ip_prefixes = None @@ -87,7 +162,9 @@ def configure_load_balancer_profile(managed_outbound_ip_count, managed_outbound_ ManagedClusterLoadBalancerProfileManagedOutboundIPs = models.get( "ManagedClusterLoadBalancerProfileManagedOutboundIPs" ) - profile.managed_outbound_i_ps = ManagedClusterLoadBalancerProfileManagedOutboundIPs() + profile.managed_outbound_i_ps = ( + ManagedClusterLoadBalancerProfileManagedOutboundIPs() + ) if managed_outbound_ip_count: profile.managed_outbound_i_ps.count = managed_outbound_ip_count if managed_outbound_ipv6_count: @@ -104,14 +181,24 @@ def configure_load_balancer_profile(managed_outbound_ip_count, managed_outbound_ return profile -def is_load_balancer_profile_provided(managed_outbound_ip_count, managed_outbound_ipv6_count, outbound_ips, ip_prefixes, - outbound_ports, idle_timeout): - return any([managed_outbound_ip_count, - managed_outbound_ipv6_count, - outbound_ips, - ip_prefixes, - outbound_ports, - idle_timeout]) +def is_load_balancer_profile_provided( + managed_outbound_ip_count, + managed_outbound_ipv6_count, + outbound_ips, + ip_prefixes, + outbound_ports, + idle_timeout, +): + return any( + [ + managed_outbound_ip_count, + managed_outbound_ipv6_count, + outbound_ips, + ip_prefixes, + outbound_ports, + idle_timeout, + ] + ) def _get_load_balancer_outbound_ips(load_balancer_outbound_ips, models): @@ -123,9 +210,10 @@ def _get_load_balancer_outbound_ips(load_balancer_outbound_ips, models): ResourceReference = models.get("ResourceReference") if load_balancer_outbound_ips is not None: if isinstance(load_balancer_outbound_ips, str): - load_balancer_outbound_ip_resources = \ - [ResourceReference(id=x.strip()) - for x in load_balancer_outbound_ips.split(',')] + load_balancer_outbound_ip_resources = [ + ResourceReference(id=x.strip()) + for x in load_balancer_outbound_ips.split(",") + ] else: load_balancer_outbound_ip_resources = load_balancer_outbound_ips return load_balancer_outbound_ip_resources @@ -141,9 +229,12 @@ def _get_load_balancer_outbound_ip_prefixes(load_balancer_outbound_ip_prefixes, ResourceReference = models.get("ResourceReference") if load_balancer_outbound_ip_prefixes: if isinstance(load_balancer_outbound_ip_prefixes, str): - load_balancer_outbound_ip_prefix_resources = \ - [ResourceReference(id=x.strip()) - for x in load_balancer_outbound_ip_prefixes.split(',')] + load_balancer_outbound_ip_prefix_resources = [ + ResourceReference(id=x.strip()) + for x in load_balancer_outbound_ip_prefixes.split(",") + ] else: - load_balancer_outbound_ip_prefix_resources = load_balancer_outbound_ip_prefixes + load_balancer_outbound_ip_prefix_resources = ( + load_balancer_outbound_ip_prefixes + ) return load_balancer_outbound_ip_prefix_resources diff --git a/src/aks-preview/azext_aks_preview/_params.py b/src/aks-preview/azext_aks_preview/_params.py index 0073aff573c..e7860ea3700 100644 --- a/src/aks-preview/azext_aks_preview/_params.py +++ b/src/aks-preview/azext_aks_preview/_params.py @@ -3,18 +3,11 @@ # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- -# pylint: disable=line-too-long,too-many-statements - +# pylint: disable=too-many-statements,too-many-lines import os.path 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, - get_vm_size_completion_list, -) from azure.cli.command_modules.acs._consts import ( CONST_OUTBOUND_TYPE_LOAD_BALANCER, CONST_OUTBOUND_TYPE_MANAGED_NAT_GATEWAY, @@ -30,6 +23,22 @@ validate_nat_gateway_idle_timeout, validate_nat_gateway_managed_outbound_ip_count, ) +from azure.cli.core.commands.parameters import ( + edge_zone_type, + file_type, + get_enum_type, + get_resource_name_completion_list, + get_three_state_flag, + name_type, + tags_type, + zones_type, +) +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, + get_vm_size_completion_list, +) from azext_aks_preview._consts import ( CONST_ABSOLUTEMONTHLY_MAINTENANCE_SCHEDULE, CONST_AZURE_KEYVAULT_NETWORK_ACCESS_PRIVATE, @@ -55,10 +64,6 @@ CONST_NETWORK_PLUGIN_KUBENET, CONST_NETWORK_PLUGIN_MODE_OVERLAY, CONST_NETWORK_PLUGIN_NONE, - CONST_NETWORK_POLICY_AZURE, - CONST_NETWORK_POLICY_CALICO, - CONST_NETWORK_POLICY_CILIUM, - CONST_NETWORK_POLICY_NONE, CONST_NODE_IMAGE_UPGRADE_CHANNEL, CONST_NODE_OS_CHANNEL_NODE_IMAGE, CONST_NODE_OS_CHANNEL_NONE, @@ -165,17 +170,7 @@ validate_vnet_subnet_id, validate_force_upgrade_disable_and_enable_parameters, validate_azure_service_mesh_revision, - validate_artifact_streaming -) -from azure.cli.core.commands.parameters import ( - edge_zone_type, - file_type, - get_enum_type, - get_resource_name_completion_list, - get_three_state_flag, - name_type, - tags_type, - zones_type, + validate_artifact_streaming, ) from azext_aks_preview.azurecontainerstorage._consts import ( CONST_STORAGE_POOL_TYPE_AZURE_DISK, @@ -190,21 +185,36 @@ CONST_STORAGE_POOL_SKU_STANDARDSSD_ZRS, CONST_STORAGE_POOL_OPTION_NVME, CONST_STORAGE_POOL_OPTION_SSD, - CONST_STORAGE_POOL_DEFAULT_SIZE, ) from knack.arguments import CLIArgumentType # candidates for enumeration # consts for AgentPool node_priorities = [CONST_SCALE_SET_PRIORITY_REGULAR, CONST_SCALE_SET_PRIORITY_SPOT] -node_eviction_policies = [CONST_SPOT_EVICTION_POLICY_DELETE, CONST_SPOT_EVICTION_POLICY_DEALLOCATE] +node_eviction_policies = [ + CONST_SPOT_EVICTION_POLICY_DELETE, + CONST_SPOT_EVICTION_POLICY_DEALLOCATE, +] node_os_disk_types = [CONST_OS_DISK_TYPE_MANAGED, CONST_OS_DISK_TYPE_EPHEMERAL] node_mode_types = [CONST_NODEPOOL_MODE_SYSTEM, CONST_NODEPOOL_MODE_USER] -node_os_skus_create = [CONST_OS_SKU_AZURELINUX, CONST_OS_SKU_UBUNTU, CONST_OS_SKU_CBLMARINER, CONST_OS_SKU_MARINER] -node_os_skus = node_os_skus_create + [CONST_OS_SKU_WINDOWS2019, CONST_OS_SKU_WINDOWS2022] +node_os_skus_create = [ + CONST_OS_SKU_AZURELINUX, + CONST_OS_SKU_UBUNTU, + CONST_OS_SKU_CBLMARINER, + CONST_OS_SKU_MARINER, +] +node_os_skus = node_os_skus_create + [ + CONST_OS_SKU_WINDOWS2019, + CONST_OS_SKU_WINDOWS2022, +] node_os_skus_update = [CONST_OS_SKU_AZURELINUX, CONST_OS_SKU_UBUNTU] scale_down_modes = [CONST_SCALE_DOWN_MODE_DELETE, CONST_SCALE_DOWN_MODE_DEALLOCATE] -workload_runtimes = [CONST_WORKLOAD_RUNTIME_OCI_CONTAINER, CONST_WORKLOAD_RUNTIME_WASM_WASI, CONST_WORKLOAD_RUNTIME_KATA_MSHV_VM_ISOLATION, CONST_WORKLOAD_RUNTIME_KATA_CC_ISOLATION] +workload_runtimes = [ + CONST_WORKLOAD_RUNTIME_OCI_CONTAINER, + CONST_WORKLOAD_RUNTIME_WASM_WASI, + CONST_WORKLOAD_RUNTIME_KATA_MSHV_VM_ISOLATION, + CONST_WORKLOAD_RUNTIME_KATA_CC_ISOLATION, +] gpu_instance_profiles = [ CONST_GPU_INSTANCE_PROFILE_MIG1_G, CONST_GPU_INSTANCE_PROFILE_MIG2_G, @@ -215,8 +225,16 @@ # 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, CONST_MANAGED_CLUSTER_SKU_TIER_PREMIUM] -network_plugins = [CONST_NETWORK_PLUGIN_KUBENET, CONST_NETWORK_PLUGIN_AZURE, CONST_NETWORK_PLUGIN_NONE] +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] disk_driver_versions = [CONST_DISK_DRIVER_V1, CONST_DISK_DRIVER_V2] @@ -264,13 +282,16 @@ # consts for credential credential_formats = [CONST_CREDENTIAL_FORMAT_AZURE, CONST_CREDENTIAL_FORMAT_EXEC] -keyvault_network_access_types = [CONST_AZURE_KEYVAULT_NETWORK_ACCESS_PUBLIC, CONST_AZURE_KEYVAULT_NETWORK_ACCESS_PRIVATE] +keyvault_network_access_types = [ + CONST_AZURE_KEYVAULT_NETWORK_ACCESS_PUBLIC, + CONST_AZURE_KEYVAULT_NETWORK_ACCESS_PRIVATE, +] # consts for guardrails level guardrails_levels = [ CONST_GUARDRAILSLEVEL_OFF, CONST_GUARDRAILSLEVEL_WARNING, - CONST_GUARDRAILSLEVEL_ENFORCEMENT + CONST_GUARDRAILSLEVEL_ENFORCEMENT, ] # azure service mesh @@ -309,770 +330,1650 @@ 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') + 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: - c.argument('resource_name', name_type, help='Name of the managed cluster.', - completer=get_resource_name_completion_list('Microsoft.ContainerService/ManagedClusters')) - c.argument('name', name_type, help='Name of the managed cluster.', - completer=get_resource_name_completion_list('Microsoft.ContainerService/ManagedClusters')) - c.argument('kubernetes_version', options_list=[ - '--kubernetes-version', '-k'], validator=validate_k8s_version) - c.argument('node_count', options_list=['--node-count', '-c'], type=int) - c.argument('tags', tags_type) - - with self.argument_context('aks create') as c: + with self.argument_context("aks") as c: + c.argument( + "resource_name", + name_type, + help="Name of the managed cluster.", + completer=get_resource_name_completion_list( + "Microsoft.ContainerService/ManagedClusters" + ), + ) + c.argument( + "name", + name_type, + help="Name of the managed cluster.", + completer=get_resource_name_completion_list( + "Microsoft.ContainerService/ManagedClusters" + ), + ) + c.argument( + "kubernetes_version", + options_list=["--kubernetes-version", "-k"], + validator=validate_k8s_version, + ) + c.argument("node_count", options_list=["--node-count", "-c"], type=int) + c.argument("tags", tags_type) + + with self.argument_context("aks create") as c: # managed cluster paramerters - c.argument('name', validator=validate_linux_host_name) - c.argument('kubernetes_version', - completer=get_k8s_versions_completion_list) - c.argument('dns_name_prefix', options_list=['--dns-name-prefix', '-p']) - c.argument('node_osdisk_diskencryptionset_id', options_list=['--node-osdisk-diskencryptionset-id', '-d']) - c.argument('disable_local_accounts', action='store_true') - c.argument('disable_rbac', action='store_true') - c.argument('edge_zone', edge_zone_type) - c.argument('admin_username', options_list=['--admin-username', '-u'], default='azureuser') - c.argument('generate_ssh_keys', action='store_true', validator=validate_create_parameters) - c.argument('ssh_key_value', required=False, type=file_type, default=os.path.join('~', '.ssh', 'id_rsa.pub'), - completer=FilesCompleter(), validator=validate_ssh_key) - c.argument('no_ssh_key', options_list=['--no-ssh-key', '-x']) - c.argument('dns_service_ip') - c.argument('docker_bridge_address', deprecate_info=c.deprecate(target='--docker-bridge-address', hide=True)) - c.argument('pod_cidrs') - c.argument('service_cidrs') - c.argument('load_balancer_sku', arg_type=get_enum_type(load_balancer_skus), validator=validate_load_balancer_sku) - c.argument('load_balancer_managed_outbound_ip_count', type=int) - c.argument('load_balancer_outbound_ips', validator=validate_load_balancer_outbound_ips) - c.argument('load_balancer_outbound_ip_prefixes', validator=validate_load_balancer_outbound_ip_prefixes) - c.argument('load_balancer_outbound_ports', type=int, validator=validate_load_balancer_outbound_ports) - c.argument('load_balancer_idle_timeout', type=int, validator=validate_load_balancer_idle_timeout) - c.argument('load_balancer_backend_pool_type', validator=validate_load_balancer_backend_pool_type) - c.argument('nrg_lockdown_restriction_level', arg_type=get_enum_type(nrg_lockdown_restriction_levels)) - c.argument('nat_gateway_managed_outbound_ip_count', type=int, validator=validate_nat_gateway_managed_outbound_ip_count) - c.argument('nat_gateway_idle_timeout', type=int, validator=validate_nat_gateway_idle_timeout) - c.argument('outbound_type', arg_type=get_enum_type(outbound_types)) - c.argument('network_plugin', arg_type=get_enum_type(network_plugins)) - c.argument('network_plugin_mode', arg_type=get_enum_type(network_plugin_modes)) - c.argument('network_policy') - c.argument('network_dataplane', arg_type=get_enum_type(network_dataplanes)) - c.argument('kube_proxy_config') - c.argument('auto_upgrade_channel', arg_type=get_enum_type(auto_upgrade_channels)) - c.argument('node_os_upgrade_channel', arg_type=get_enum_type(node_os_upgrade_channels)) - c.argument('cluster_autoscaler_profile', nargs='+', options_list=["--cluster-autoscaler-profile", "--ca-profile"], - help="Space-separated list of key=value pairs for configuring cluster autoscaler. Pass an empty string to clear the profile.") - c.argument('uptime_sla', action='store_true', deprecate_info=c.deprecate(target='--uptime-sla', redirect='--tier', hide=True)) - c.argument('tier', arg_type=get_enum_type(sku_tiers), validator=validate_sku_tier) - c.argument('fqdn_subdomain') - c.argument('api_server_authorized_ip_ranges', validator=validate_ip_ranges) - c.argument('enable_private_cluster', action='store_true') - c.argument('private_dns_zone') - c.argument('disable_public_fqdn', action='store_true') - c.argument('service_principal') - c.argument('client_secret') - c.argument('enable_managed_identity', action='store_true') - c.argument('assign_identity', validator=validate_assign_identity) - c.argument('assign_kubelet_identity', validator=validate_assign_kubelet_identity) - c.argument('enable_aad', action='store_true') - c.argument('enable_azure_rbac', action='store_true') - c.argument('aad_client_app_id', deprecate_info=c.deprecate(target='--aad-client-app-id', hide=True)) - c.argument('aad_server_app_id', deprecate_info=c.deprecate(target='--aad-server-app-id', hide=True)) - c.argument('aad_server_app_secret', deprecate_info=c.deprecate(target='--aad-server-app-secret', hide=True)) - c.argument('aad_tenant_id') - c.argument('aad_admin_group_object_ids') - c.argument('enable_oidc_issuer', action='store_true') - c.argument('windows_admin_username') - c.argument('windows_admin_password') - c.argument('enable_ahub') - c.argument('enable_windows_gmsa', action='store_true') - c.argument('gmsa_dns_server') - c.argument('gmsa_root_domain_name') - 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)) - c.argument('disable_disk_driver', action='store_true') - c.argument('disable_file_driver', action='store_true') - c.argument('enable_blob_driver', action='store_true') - c.argument('disable_snapshot_controller', action='store_true') - c.argument('enable_azure_keyvault_kms', action='store_true') - c.argument('azure_keyvault_kms_key_id', validator=validate_azure_keyvault_kms_key_id) - c.argument('azure_keyvault_kms_key_vault_network_access', arg_type=get_enum_type(keyvault_network_access_types), default=CONST_AZURE_KEYVAULT_NETWORK_ACCESS_PUBLIC) - c.argument('azure_keyvault_kms_key_vault_resource_id', validator=validate_azure_keyvault_kms_key_vault_resource_id) - c.argument('http_proxy_config') + c.argument("name", validator=validate_linux_host_name) + c.argument("kubernetes_version", completer=get_k8s_versions_completion_list) + c.argument("dns_name_prefix", options_list=["--dns-name-prefix", "-p"]) + c.argument( + "node_osdisk_diskencryptionset_id", + options_list=["--node-osdisk-diskencryptionset-id", "-d"], + ) + c.argument("disable_local_accounts", action="store_true") + c.argument("disable_rbac", action="store_true") + c.argument("edge_zone", edge_zone_type) + c.argument( + "admin_username", + options_list=["--admin-username", "-u"], + default="azureuser", + ) + c.argument( + "generate_ssh_keys", + action="store_true", + validator=validate_create_parameters, + ) + c.argument( + "ssh_key_value", + required=False, + type=file_type, + default=os.path.join("~", ".ssh", "id_rsa.pub"), + completer=FilesCompleter(), + validator=validate_ssh_key, + ) + c.argument("no_ssh_key", options_list=["--no-ssh-key", "-x"]) + c.argument("dns_service_ip") + c.argument( + "docker_bridge_address", + deprecate_info=c.deprecate(target="--docker-bridge-address", hide=True), + ) + c.argument("pod_cidrs") + c.argument("service_cidrs") + c.argument( + "load_balancer_sku", + arg_type=get_enum_type(load_balancer_skus), + validator=validate_load_balancer_sku, + ) + c.argument("load_balancer_managed_outbound_ip_count", type=int) + c.argument( + "load_balancer_outbound_ips", validator=validate_load_balancer_outbound_ips + ) + c.argument( + "load_balancer_outbound_ip_prefixes", + validator=validate_load_balancer_outbound_ip_prefixes, + ) + c.argument( + "load_balancer_outbound_ports", + type=int, + validator=validate_load_balancer_outbound_ports, + ) + c.argument( + "load_balancer_idle_timeout", + type=int, + validator=validate_load_balancer_idle_timeout, + ) + c.argument( + "load_balancer_backend_pool_type", + validator=validate_load_balancer_backend_pool_type, + ) + c.argument( + "nrg_lockdown_restriction_level", + arg_type=get_enum_type(nrg_lockdown_restriction_levels), + ) + c.argument( + "nat_gateway_managed_outbound_ip_count", + type=int, + validator=validate_nat_gateway_managed_outbound_ip_count, + ) + c.argument( + "nat_gateway_idle_timeout", + type=int, + validator=validate_nat_gateway_idle_timeout, + ) + c.argument("outbound_type", arg_type=get_enum_type(outbound_types)) + c.argument("network_plugin", arg_type=get_enum_type(network_plugins)) + c.argument("network_plugin_mode", arg_type=get_enum_type(network_plugin_modes)) + c.argument("network_policy") + c.argument("network_dataplane", arg_type=get_enum_type(network_dataplanes)) + c.argument("kube_proxy_config") + c.argument( + "auto_upgrade_channel", arg_type=get_enum_type(auto_upgrade_channels) + ) + c.argument( + "node_os_upgrade_channel", arg_type=get_enum_type(node_os_upgrade_channels) + ) + c.argument( + "cluster_autoscaler_profile", + nargs="+", + options_list=["--cluster-autoscaler-profile", "--ca-profile"], + help=( + "Space-separated list of key=value pairs for configuring cluster autoscaler. " + "Pass an empty string to clear the profile." + ), + ) + c.argument( + "uptime_sla", + action="store_true", + deprecate_info=c.deprecate( + target="--uptime-sla", redirect="--tier", hide=True + ), + ) + c.argument( + "tier", arg_type=get_enum_type(sku_tiers), validator=validate_sku_tier + ) + c.argument("fqdn_subdomain") + c.argument("api_server_authorized_ip_ranges", validator=validate_ip_ranges) + c.argument("enable_private_cluster", action="store_true") + c.argument("private_dns_zone") + c.argument("disable_public_fqdn", action="store_true") + c.argument("service_principal") + c.argument("client_secret") + c.argument("enable_managed_identity", action="store_true") + c.argument("assign_identity", validator=validate_assign_identity) + c.argument( + "assign_kubelet_identity", validator=validate_assign_kubelet_identity + ) + c.argument("enable_aad", action="store_true") + c.argument("enable_azure_rbac", action="store_true") + c.argument( + "aad_client_app_id", + deprecate_info=c.deprecate(target="--aad-client-app-id", hide=True), + ) + c.argument( + "aad_server_app_id", + deprecate_info=c.deprecate(target="--aad-server-app-id", hide=True), + ) + c.argument( + "aad_server_app_secret", + deprecate_info=c.deprecate(target="--aad-server-app-secret", hide=True), + ) + c.argument("aad_tenant_id") + c.argument("aad_admin_group_object_ids") + c.argument("enable_oidc_issuer", action="store_true") + c.argument("windows_admin_username") + c.argument("windows_admin_password") + c.argument("enable_ahub") + c.argument("enable_windows_gmsa", action="store_true") + c.argument("gmsa_dns_server") + c.argument("gmsa_root_domain_name") + 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)) + c.argument("disable_disk_driver", action="store_true") + c.argument("disable_file_driver", action="store_true") + c.argument("enable_blob_driver", action="store_true") + c.argument("disable_snapshot_controller", action="store_true") + c.argument("enable_azure_keyvault_kms", action="store_true") + c.argument( + "azure_keyvault_kms_key_id", validator=validate_azure_keyvault_kms_key_id + ) + c.argument( + "azure_keyvault_kms_key_vault_network_access", + arg_type=get_enum_type(keyvault_network_access_types), + default=CONST_AZURE_KEYVAULT_NETWORK_ACCESS_PUBLIC, + ) + c.argument( + "azure_keyvault_kms_key_vault_resource_id", + validator=validate_azure_keyvault_kms_key_vault_resource_id, + ) + c.argument("http_proxy_config") # addons - c.argument('enable_addons', options_list=['--enable-addons', '-a'], validator=validate_addons) - c.argument('workspace_resource_id') - c.argument('enable_msi_auth_for_monitoring', arg_type=get_three_state_flag(), is_preview=True) - c.argument('enable_syslog', arg_type=get_three_state_flag(), is_preview=True) - c.argument('data_collection_settings', is_preview=True) - c.argument('aci_subnet_name') - c.argument('appgw_name', arg_group='Application Gateway') - c.argument('appgw_subnet_cidr', arg_group='Application Gateway') - c.argument('appgw_id', arg_group='Application Gateway') - c.argument('appgw_subnet_id', arg_group='Application Gateway') - c.argument('appgw_watch_namespace', arg_group='Application Gateway') - c.argument('enable_secret_rotation', action='store_true') - c.argument('rotation_poll_interval') - c.argument('enable_sgxquotehelper', action='store_true') - c.argument('enable_app_routing', action='store_true', is_preview=True) + c.argument( + "enable_addons", + options_list=["--enable-addons", "-a"], + validator=validate_addons, + ) + c.argument("workspace_resource_id") + c.argument( + "enable_msi_auth_for_monitoring", + arg_type=get_three_state_flag(), + is_preview=True, + ) + c.argument("enable_syslog", arg_type=get_three_state_flag(), is_preview=True) + c.argument("data_collection_settings", is_preview=True) + c.argument("aci_subnet_name") + c.argument("appgw_name", arg_group="Application Gateway") + c.argument("appgw_subnet_cidr", arg_group="Application Gateway") + c.argument("appgw_id", arg_group="Application Gateway") + c.argument("appgw_subnet_id", arg_group="Application Gateway") + c.argument("appgw_watch_namespace", arg_group="Application Gateway") + c.argument("enable_secret_rotation", action="store_true") + c.argument("rotation_poll_interval") + c.argument("enable_sgxquotehelper", action="store_true") + c.argument("enable_app_routing", action="store_true", is_preview=True) # nodepool paramerters - c.argument('nodepool_name', default='nodepool1', - help='Node pool name, upto 12 alphanumeric characters', validator=validate_nodepool_name) - c.argument('node_vm_size', options_list=['--node-vm-size', '-s'], completer=get_vm_size_completion_list) - c.argument('os_sku', arg_type=get_enum_type(node_os_skus_create), validator=validate_os_sku) - c.argument('snapshot_id', validator=validate_snapshot_id) - c.argument('vnet_subnet_id', validator=validate_vnet_subnet_id) - c.argument('pod_subnet_id', validator=validate_pod_subnet_id) - c.argument('enable_node_public_ip', action='store_true') - c.argument('node_public_ip_prefix_id') - c.argument('enable_cluster_autoscaler', action='store_true') - c.argument('min_count', type=int, validator=validate_nodes_count) - c.argument('max_count', type=int, validator=validate_nodes_count) - c.argument('nodepool_tags', nargs='*', validator=validate_nodepool_tags, - help='space-separated tags: key[=value] [key[=value] ...]. Use "" to clear existing tags.') - c.argument('nodepool_labels', nargs='*', validator=validate_nodepool_labels, - help='space-separated labels: key[=value] [key[=value] ...]. See https://aka.ms/node-labels for syntax of labels.') - c.argument('nodepool_taints', validator=validate_nodepool_taints) - c.argument('node_osdisk_type', arg_type=get_enum_type(node_os_disk_types)) - c.argument('node_osdisk_size', type=int) - c.argument('max_pods', type=int, options_list=['--max-pods', '-m']) - c.argument('vm_set_type', validator=validate_vm_set_type) - c.argument('enable_vmss', action='store_true', help='To be deprecated. Use vm_set_type instead.', deprecate_info=c.deprecate(redirect='--vm-set-type', hide=True)) - c.argument('zones', zones_type, options_list=['--zones', '-z'], help='Space-separated list of availability zones where agent nodes will be placed.') - c.argument('ppg') - c.argument('enable_encryption_at_host', action='store_true') - c.argument('enable_ultra_ssd', action='store_true') - c.argument('enable_fips_image', action='store_true') - c.argument('kubelet_config') - c.argument('linux_os_config') - c.argument('host_group_id', validator=validate_host_group_id) - c.argument('gpu_instance_profile', arg_type=get_enum_type(gpu_instance_profiles)) + c.argument( + "nodepool_name", + default="nodepool1", + help="Node pool name, upto 12 alphanumeric characters", + validator=validate_nodepool_name, + ) + c.argument( + "node_vm_size", + options_list=["--node-vm-size", "-s"], + completer=get_vm_size_completion_list, + ) + c.argument( + "os_sku", + arg_type=get_enum_type(node_os_skus_create), + validator=validate_os_sku, + ) + c.argument("snapshot_id", validator=validate_snapshot_id) + c.argument("vnet_subnet_id", validator=validate_vnet_subnet_id) + c.argument("pod_subnet_id", validator=validate_pod_subnet_id) + c.argument("enable_node_public_ip", action="store_true") + c.argument("node_public_ip_prefix_id") + c.argument("enable_cluster_autoscaler", action="store_true") + c.argument("min_count", type=int, validator=validate_nodes_count) + c.argument("max_count", type=int, validator=validate_nodes_count) + c.argument( + "nodepool_tags", + nargs="*", + validator=validate_nodepool_tags, + help='space-separated tags: key[=value] [key[=value] ...]. Use "" to clear existing tags.', + ) + c.argument( + "nodepool_labels", + nargs="*", + validator=validate_nodepool_labels, + help=( + "space-separated labels: key[=value] [key[=value] ...]. " + "See https://aka.ms/node-labels for syntax of labels." + ), + ) + c.argument("nodepool_taints", validator=validate_nodepool_taints) + c.argument("node_osdisk_type", arg_type=get_enum_type(node_os_disk_types)) + c.argument("node_osdisk_size", type=int) + c.argument("max_pods", type=int, options_list=["--max-pods", "-m"]) + c.argument("vm_set_type", validator=validate_vm_set_type) + c.argument( + "enable_vmss", + action="store_true", + help="To be deprecated. Use vm_set_type instead.", + deprecate_info=c.deprecate(redirect="--vm-set-type", hide=True), + ) + c.argument( + "zones", + zones_type, + options_list=["--zones", "-z"], + help="Space-separated list of availability zones where agent nodes will be placed.", + ) + c.argument("ppg") + c.argument("enable_encryption_at_host", action="store_true") + c.argument("enable_ultra_ssd", action="store_true") + c.argument("enable_fips_image", action="store_true") + c.argument("kubelet_config") + c.argument("linux_os_config") + c.argument("host_group_id", validator=validate_host_group_id) + c.argument( + "gpu_instance_profile", arg_type=get_enum_type(gpu_instance_profiles) + ) # misc - c.argument('yes', options_list=['--yes', '-y'], help='Do not prompt for confirmation.', action='store_true') - c.argument('aks_custom_headers') + c.argument( + "yes", + options_list=["--yes", "-y"], + help="Do not prompt for confirmation.", + action="store_true", + ) + c.argument("aks_custom_headers") # extensions # managed cluster - c.argument('ip_families') - c.argument('pod_cidrs') - c.argument('service_cidrs') - c.argument('load_balancer_managed_outbound_ipv6_count', type=int) - c.argument('enable_pod_security_policy', action='store_true', deprecate_info=c.deprecate(target='--enable-pod-security-policy', hide=True)) - c.argument('enable_pod_identity', action='store_true') - c.argument('enable_pod_identity_with_kubenet', action='store_true') - c.argument('enable_workload_identity', action='store_true', is_preview=True) - c.argument('enable_image_cleaner', action='store_true') - c.argument('enable_azure_service_mesh', - options_list=["--enable-azure-service-mesh", "--enable-asm"], - action='store_true', - is_preview=True) - c.argument('image_cleaner_interval_hours', type=int) - c.argument('cluster_snapshot_id', validator=validate_cluster_snapshot_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('dns_zone_resource_id', deprecate_info=c.deprecate(target='--dns-zone-resource-id', redirect='--dns-zone-resource-ids', hide=True)) - c.argument('dns_zone_resource_ids', is_preview=True) - c.argument('enable_keda', action='store_true', is_preview=True) - c.argument('enable_vpa', action='store_true', is_preview=True, help="enable vertical pod autoscaler for cluster") - c.argument('enable_node_restriction', action='store_true', is_preview=True, help="enable node restriction for cluster") - c.argument('enable_cilium_dataplane', action='store_true', is_preview=True, deprecate_info=c.deprecate(target='--enable-cilium-dataplane', redirect='--network-dataplane', hide=True)) - c.argument('enable_network_observability', action='store_true', is_preview=True, help="enable network observability for cluster") - c.argument('custom_ca_trust_certificates', options_list=["--custom-ca-trust-certificates", "--ca-certs"], is_preview=True, help="path to file containing list of new line separated CAs") + c.argument("ip_families") + c.argument("pod_cidrs") + c.argument("service_cidrs") + c.argument("load_balancer_managed_outbound_ipv6_count", type=int) + c.argument( + "enable_pod_security_policy", + action="store_true", + deprecate_info=c.deprecate( + target="--enable-pod-security-policy", hide=True + ), + ) + c.argument("enable_pod_identity", action="store_true") + c.argument("enable_pod_identity_with_kubenet", action="store_true") + c.argument("enable_workload_identity", action="store_true", is_preview=True) + c.argument("enable_image_cleaner", action="store_true") + c.argument( + "enable_azure_service_mesh", + options_list=["--enable-azure-service-mesh", "--enable-asm"], + action="store_true", + is_preview=True, + ) + c.argument("image_cleaner_interval_hours", type=int) + c.argument( + "cluster_snapshot_id", + validator=validate_cluster_snapshot_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( + "dns_zone_resource_id", + deprecate_info=c.deprecate( + target="--dns-zone-resource-id", + redirect="--dns-zone-resource-ids", + hide=True, + ), + ) + c.argument("dns_zone_resource_ids", is_preview=True) + c.argument("enable_keda", action="store_true", is_preview=True) + c.argument( + "enable_vpa", + action="store_true", + is_preview=True, + help="enable vertical pod autoscaler for cluster", + ) + c.argument( + "enable_node_restriction", + action="store_true", + is_preview=True, + help="enable node restriction for cluster", + ) + c.argument( + "enable_cilium_dataplane", + action="store_true", + is_preview=True, + deprecate_info=c.deprecate( + target="--enable-cilium-dataplane", + redirect="--network-dataplane", + hide=True, + ), + ) + c.argument( + "enable_network_observability", + action="store_true", + is_preview=True, + help="enable network observability for cluster", + ) + c.argument( + "custom_ca_trust_certificates", + options_list=["--custom-ca-trust-certificates", "--ca-certs"], + is_preview=True, + help="path to file containing list of new line separated CAs", + ) # nodepool - c.argument('crg_id', validator=validate_crg_id, is_preview=True) + c.argument("crg_id", validator=validate_crg_id, is_preview=True) # no validation for aks create because it already only supports Linux. - c.argument('message_of_the_day') - c.argument('workload_runtime', arg_type=get_enum_type(workload_runtimes), default=CONST_WORKLOAD_RUNTIME_OCI_CONTAINER) + c.argument("message_of_the_day") + c.argument( + "workload_runtime", + arg_type=get_enum_type(workload_runtimes), + default=CONST_WORKLOAD_RUNTIME_OCI_CONTAINER, + ) # no validation for aks create because it already only supports Linux. - c.argument('enable_custom_ca_trust', action='store_true') - c.argument('nodepool_allowed_host_ports', validator=validate_allowed_host_ports, is_preview=True, help="allowed host ports for agentpool") - c.argument('nodepool_asg_ids', validator=validate_application_security_groups, is_preview=True, help="application security groups for agentpool") - c.argument('node_public_ip_tags', arg_type=tags_type, validator=validate_node_public_ip_tags, - help='space-separated tags: key[=value] [key[=value] ...].') - c.argument('guardrails_level', arg_type=get_enum_type(guardrails_levels), is_preview=True) - c.argument('guardrails_version', type=str, - help='The guardrails version', is_preview=True) - c.argument('guardrails_excluded_ns', type=str, is_preview=True) + c.argument("enable_custom_ca_trust", action="store_true") + c.argument( + "nodepool_allowed_host_ports", + validator=validate_allowed_host_ports, + is_preview=True, + help="allowed host ports for agentpool", + ) + c.argument( + "nodepool_asg_ids", + validator=validate_application_security_groups, + is_preview=True, + help="application security groups for agentpool", + ) + c.argument( + "node_public_ip_tags", + arg_type=tags_type, + validator=validate_node_public_ip_tags, + help="space-separated tags: key[=value] [key[=value] ...].", + ) + c.argument( + "guardrails_level", + arg_type=get_enum_type(guardrails_levels), + is_preview=True, + ) + c.argument( + "guardrails_version", + type=str, + help="The guardrails version", + is_preview=True, + ) + c.argument("guardrails_excluded_ns", type=str, is_preview=True) # azure monitor profile - c.argument('enable_azuremonitormetrics', action='store_true', deprecate_info=c.deprecate(target='--enable-azuremonitormetrics', redirect='--enable-azure-monitor-metrics', hide=True)) - c.argument('enable_azure_monitor_metrics', action='store_true') - c.argument('azure_monitor_workspace_resource_id', validator=validate_azuremonitorworkspaceresourceid) - c.argument('ksm_metric_labels_allow_list') - c.argument('ksm_metric_annotations_allow_list') - c.argument('grafana_resource_id', validator=validate_grafanaresourceid) - c.argument('enable_windows_recording_rules', action='store_true') - c.argument('enable_cost_analysis', is_preview=True, action='store_true') + c.argument( + "enable_azuremonitormetrics", + action="store_true", + deprecate_info=c.deprecate( + target="--enable-azuremonitormetrics", + redirect="--enable-azure-monitor-metrics", + hide=True, + ), + ) + c.argument("enable_azure_monitor_metrics", action="store_true") + c.argument( + "azure_monitor_workspace_resource_id", + validator=validate_azuremonitorworkspaceresourceid, + ) + c.argument("ksm_metric_labels_allow_list") + c.argument("ksm_metric_annotations_allow_list") + c.argument("grafana_resource_id", validator=validate_grafanaresourceid) + c.argument("enable_windows_recording_rules", action="store_true") + c.argument("enable_cost_analysis", is_preview=True, action="store_true") # azure container storage - c.argument('enable_azure_container_storage', arg_type=get_enum_type(storage_pool_types), - help='enable azure container storage and define storage pool type') - c.argument('storage_pool_name', help='set storage pool name for azure container storage') - c.argument('storage_pool_size', help='set storage pool size for azure container storage') - c.argument('storage_pool_sku', arg_type=get_enum_type(storage_pool_skus), - help='set azure disk type storage pool sku for azure container storage') - c.argument('storage_pool_option', arg_type=get_enum_type(storage_pool_options), - help='set ephemeral disk storage pool option for azure container storage') - c.argument('node_provisioning_mode', is_preview=True, arg_type=get_enum_type(node_provisioning_modes), - help='Set the node provisioning mode of the cluster. Valid values are "Auto" and "Manual". For more information on "Auto" mode see aka.ms/aks/nap.') - - with self.argument_context('aks update') as c: + c.argument( + "enable_azure_container_storage", + arg_type=get_enum_type(storage_pool_types), + help="enable azure container storage and define storage pool type", + ) + c.argument( + "storage_pool_name", + help="set storage pool name for azure container storage", + ) + c.argument( + "storage_pool_size", + help="set storage pool size for azure container storage", + ) + c.argument( + "storage_pool_sku", + arg_type=get_enum_type(storage_pool_skus), + help="set azure disk type storage pool sku for azure container storage", + ) + c.argument( + "storage_pool_option", + arg_type=get_enum_type(storage_pool_options), + help="set ephemeral disk storage pool option for azure container storage", + ) + c.argument( + "node_provisioning_mode", + is_preview=True, + arg_type=get_enum_type(node_provisioning_modes), + help=( + 'Set the node provisioning mode of the cluster. Valid values are "Auto" and "Manual". ' + 'For more information on "Auto" mode see aka.ms/aks/nap.' + ) + ) + + with self.argument_context("aks update") as c: # managed cluster paramerters - c.argument('disable_local_accounts', action='store_true') - c.argument('enable_local_accounts', action='store_true') - c.argument('load_balancer_managed_outbound_ip_count', type=int) - c.argument('load_balancer_outbound_ips', validator=validate_load_balancer_outbound_ips) - c.argument('load_balancer_outbound_ip_prefixes', validator=validate_load_balancer_outbound_ip_prefixes) - c.argument('load_balancer_outbound_ports', type=int, validator=validate_load_balancer_outbound_ports) - c.argument('load_balancer_idle_timeout', type=int, validator=validate_load_balancer_idle_timeout) - c.argument('load_balancer_backend_pool_type', validator=validate_load_balancer_backend_pool_type) - c.argument('nrg_lockdown_restriction_level', arg_type=get_enum_type(nrg_lockdown_restriction_levels)) - c.argument('nat_gateway_managed_outbound_ip_count', type=int, validator=validate_nat_gateway_managed_outbound_ip_count) - c.argument('nat_gateway_idle_timeout', type=int, validator=validate_nat_gateway_idle_timeout) - c.argument('network_dataplane', arg_type=get_enum_type(network_dataplanes)) - c.argument('network_policy') - c.argument('network_plugin', arg_type=get_enum_type(network_plugins)) - c.argument('kube_proxy_config') - c.argument('auto_upgrade_channel', arg_type=get_enum_type(auto_upgrade_channels)) - c.argument('node_os_upgrade_channel', arg_type=get_enum_type(node_os_upgrade_channels)) - c.argument('disable_force_upgrade', action='store_true', validator=validate_force_upgrade_disable_and_enable_parameters) - c.argument('enable_force_upgrade', action='store_true', validator=validate_force_upgrade_disable_and_enable_parameters) - c.argument('upgrade_override_until', is_preview=True) - c.argument('cluster_autoscaler_profile', nargs='+', options_list=["--cluster-autoscaler-profile", "--ca-profile"], - help="Space-separated list of key=value pairs for configuring cluster autoscaler. Pass an empty string to clear the profile.") - c.argument('uptime_sla', action='store_true', deprecate_info=c.deprecate(target='--uptime-sla', redirect='--tier', hide=True)) - c.argument('no_uptime_sla', action='store_true', deprecate_info=c.deprecate(target='--no-uptime-sla', redirect='--tier', hide=True)) - c.argument('tier', arg_type=get_enum_type(sku_tiers), validator=validate_sku_tier) - c.argument('api_server_authorized_ip_ranges', validator=validate_ip_ranges) - c.argument('enable_public_fqdn', action='store_true') - c.argument('disable_public_fqdn', action='store_true') - c.argument('enable_managed_identity', action='store_true') - c.argument('assign_identity', validator=validate_assign_identity) - c.argument('assign_kubelet_identity', validator=validate_assign_kubelet_identity) - c.argument('enable_aad', action='store_true') - c.argument('enable_azure_rbac', action='store_true') - c.argument('disable_azure_rbac', action='store_true') - 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') - c.argument('enable_windows_gmsa', action='store_true') - c.argument('gmsa_dns_server') - c.argument('gmsa_root_domain_name') - c.argument('attach_acr', acr_arg_type, validator=validate_acr) - c.argument('detach_acr', acr_arg_type, validator=validate_acr) - c.argument('disable_defender', action='store_true', validator=validate_defender_disable_and_enable_parameters) - c.argument('enable_defender', action='store_true') - c.argument('defender_config', validator=validate_defender_config_parameter) - c.argument('enable_disk_driver', action='store_true') - c.argument('disk_driver_version', arg_type=get_enum_type(disk_driver_versions)) - c.argument('disable_disk_driver', action='store_true') - c.argument('enable_file_driver', action='store_true') - c.argument('disable_file_driver', action='store_true') - c.argument('enable_blob_driver', action='store_true') - c.argument('disable_blob_driver', action='store_true') - c.argument('enable_snapshot_controller', action='store_true') - c.argument('disable_snapshot_controller', action='store_true') - c.argument('enable_azure_keyvault_kms', action='store_true') - c.argument('disable_azure_keyvault_kms', action='store_true') - c.argument('azure_keyvault_kms_key_id', validator=validate_azure_keyvault_kms_key_id) - c.argument('azure_keyvault_kms_key_vault_network_access', arg_type=get_enum_type(keyvault_network_access_types)) - c.argument('azure_keyvault_kms_key_vault_resource_id', validator=validate_azure_keyvault_kms_key_vault_resource_id) - c.argument('http_proxy_config') + c.argument("disable_local_accounts", action="store_true") + c.argument("enable_local_accounts", action="store_true") + c.argument("load_balancer_managed_outbound_ip_count", type=int) + c.argument( + "load_balancer_outbound_ips", validator=validate_load_balancer_outbound_ips + ) + c.argument( + "load_balancer_outbound_ip_prefixes", + validator=validate_load_balancer_outbound_ip_prefixes, + ) + c.argument( + "load_balancer_outbound_ports", + type=int, + validator=validate_load_balancer_outbound_ports, + ) + c.argument( + "load_balancer_idle_timeout", + type=int, + validator=validate_load_balancer_idle_timeout, + ) + c.argument( + "load_balancer_backend_pool_type", + validator=validate_load_balancer_backend_pool_type, + ) + c.argument( + "nrg_lockdown_restriction_level", + arg_type=get_enum_type(nrg_lockdown_restriction_levels), + ) + c.argument( + "nat_gateway_managed_outbound_ip_count", + type=int, + validator=validate_nat_gateway_managed_outbound_ip_count, + ) + c.argument( + "nat_gateway_idle_timeout", + type=int, + validator=validate_nat_gateway_idle_timeout, + ) + c.argument("network_dataplane", arg_type=get_enum_type(network_dataplanes)) + c.argument("network_policy") + c.argument("network_plugin", arg_type=get_enum_type(network_plugins)) + c.argument("kube_proxy_config") + c.argument( + "auto_upgrade_channel", arg_type=get_enum_type(auto_upgrade_channels) + ) + c.argument( + "node_os_upgrade_channel", arg_type=get_enum_type(node_os_upgrade_channels) + ) + c.argument( + "disable_force_upgrade", + action="store_true", + validator=validate_force_upgrade_disable_and_enable_parameters, + ) + c.argument( + "enable_force_upgrade", + action="store_true", + validator=validate_force_upgrade_disable_and_enable_parameters, + ) + c.argument("upgrade_override_until", is_preview=True) + c.argument( + "cluster_autoscaler_profile", + nargs="+", + options_list=["--cluster-autoscaler-profile", "--ca-profile"], + help=( + "Space-separated list of key=value pairs for configuring cluster autoscaler. " + "Pass an empty string to clear the profile." + ), + ) + c.argument( + "uptime_sla", + action="store_true", + deprecate_info=c.deprecate( + target="--uptime-sla", redirect="--tier", hide=True + ), + ) + c.argument( + "no_uptime_sla", + action="store_true", + deprecate_info=c.deprecate( + target="--no-uptime-sla", redirect="--tier", hide=True + ), + ) + c.argument( + "tier", arg_type=get_enum_type(sku_tiers), validator=validate_sku_tier + ) + c.argument("api_server_authorized_ip_ranges", validator=validate_ip_ranges) + c.argument("enable_public_fqdn", action="store_true") + c.argument("disable_public_fqdn", action="store_true") + c.argument("enable_managed_identity", action="store_true") + c.argument("assign_identity", validator=validate_assign_identity) + c.argument( + "assign_kubelet_identity", validator=validate_assign_kubelet_identity + ) + c.argument("enable_aad", action="store_true") + c.argument("enable_azure_rbac", action="store_true") + c.argument("disable_azure_rbac", action="store_true") + 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") + c.argument("enable_windows_gmsa", action="store_true") + c.argument("gmsa_dns_server") + c.argument("gmsa_root_domain_name") + c.argument("attach_acr", acr_arg_type, validator=validate_acr) + c.argument("detach_acr", acr_arg_type, validator=validate_acr) + c.argument( + "disable_defender", + action="store_true", + validator=validate_defender_disable_and_enable_parameters, + ) + c.argument("enable_defender", action="store_true") + c.argument("defender_config", validator=validate_defender_config_parameter) + c.argument("enable_disk_driver", action="store_true") + c.argument("disk_driver_version", arg_type=get_enum_type(disk_driver_versions)) + c.argument("disable_disk_driver", action="store_true") + c.argument("enable_file_driver", action="store_true") + c.argument("disable_file_driver", action="store_true") + c.argument("enable_blob_driver", action="store_true") + c.argument("disable_blob_driver", action="store_true") + c.argument("enable_snapshot_controller", action="store_true") + c.argument("disable_snapshot_controller", action="store_true") + c.argument("enable_azure_keyvault_kms", action="store_true") + c.argument("disable_azure_keyvault_kms", action="store_true") + c.argument( + "azure_keyvault_kms_key_id", validator=validate_azure_keyvault_kms_key_id + ) + c.argument( + "azure_keyvault_kms_key_vault_network_access", + arg_type=get_enum_type(keyvault_network_access_types), + ) + c.argument( + "azure_keyvault_kms_key_vault_resource_id", + validator=validate_azure_keyvault_kms_key_vault_resource_id, + ) + c.argument("http_proxy_config") # addons - c.argument('enable_secret_rotation', action='store_true') - c.argument('disable_secret_rotation', action='store_true') - c.argument('rotation_poll_interval') + c.argument("enable_secret_rotation", action="store_true") + c.argument("disable_secret_rotation", action="store_true") + c.argument("rotation_poll_interval") # nodepool paramerters - c.argument('enable_cluster_autoscaler', options_list=[ - "--enable-cluster-autoscaler", "-e"], action='store_true') - c.argument('disable_cluster_autoscaler', options_list=[ - "--disable-cluster-autoscaler", "-d"], action='store_true') - c.argument('update_cluster_autoscaler', options_list=[ - "--update-cluster-autoscaler", "-u"], action='store_true') - c.argument('min_count', type=int, validator=validate_nodes_count) - c.argument('max_count', type=int, validator=validate_nodes_count) - c.argument('nodepool_labels', nargs='*', validator=validate_nodepool_labels, - help='space-separated labels: key[=value] [key[=value] ...]. See https://aka.ms/node-labels for syntax of labels.') - c.argument('nodepool_taints', validator=validate_nodepool_taints) + c.argument( + "enable_cluster_autoscaler", + options_list=["--enable-cluster-autoscaler", "-e"], + action="store_true", + ) + c.argument( + "disable_cluster_autoscaler", + options_list=["--disable-cluster-autoscaler", "-d"], + action="store_true", + ) + c.argument( + "update_cluster_autoscaler", + options_list=["--update-cluster-autoscaler", "-u"], + action="store_true", + ) + c.argument("min_count", type=int, validator=validate_nodes_count) + c.argument("max_count", type=int, validator=validate_nodes_count) + c.argument( + "nodepool_labels", + nargs="*", + validator=validate_nodepool_labels, + help=( + "space-separated labels: key[=value] [key[=value] ...]. " + "See https://aka.ms/node-labels for syntax of labels." + ) + ) + c.argument("nodepool_taints", validator=validate_nodepool_taints) # misc - c.argument('yes', options_list=['--yes', '-y'], help='Do not prompt for confirmation.', action='store_true') - c.argument('aks_custom_headers') + c.argument( + "yes", + options_list=["--yes", "-y"], + help="Do not prompt for confirmation.", + action="store_true", + ) + c.argument("aks_custom_headers") # extensions # managed cluster - c.argument('ssh_key_value', type=file_type, completer=FilesCompleter(), validator=validate_ssh_key_for_update) - c.argument('load_balancer_managed_outbound_ipv6_count', type=int) - c.argument('outbound_type', arg_type=get_enum_type(outbound_types)) - c.argument('enable_pod_security_policy', action='store_true', deprecate_info=c.deprecate(target='--enable-pod-security-policy', hide=True)) - c.argument('disable_pod_security_policy', action='store_true', is_preview=True) - c.argument('enable_pod_identity', action='store_true') - c.argument('enable_pod_identity_with_kubenet', action='store_true') - c.argument('disable_pod_identity', action='store_true') - c.argument('enable_workload_identity', action='store_true', is_preview=True) - c.argument('disable_workload_identity', action='store_true', is_preview=True) - c.argument('enable_image_cleaner', action='store_true') - c.argument('disable_image_cleaner', action='store_true', validator=validate_image_cleaner_enable_disable_mutually_exclusive) - c.argument('image_cleaner_interval_hours', type=int) - c.argument('disable_image_integrity', action='store_true', 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) - c.argument('enable_node_restriction', action='store_true', is_preview=True, help="enable node restriction for cluster") - c.argument('disable_node_restriction', action='store_true', is_preview=True, help="disable node restriction for cluster") - c.argument('enable_private_cluster', action='store_true', is_preview=True, help='enable private cluster for apiserver vnet integration') - c.argument('disable_private_cluster', action='store_true', is_preview=True, help='disable private cluster for apiserver vnet integration') - c.argument('private_dns_zone', is_preview=True) - c.argument('enable_azuremonitormetrics', action='store_true', deprecate_info=c.deprecate(target='--enable-azuremonitormetrics', redirect='--enable-azure-monitor-metrics', hide=True)) - c.argument('enable_azure_monitor_metrics', action='store_true') - c.argument('azure_monitor_workspace_resource_id', validator=validate_azuremonitorworkspaceresourceid) - c.argument('ksm_metric_labels_allow_list') - c.argument('ksm_metric_annotations_allow_list') - c.argument('grafana_resource_id', validator=validate_grafanaresourceid) - c.argument('enable_windows_recording_rules', action='store_true') - c.argument('disable_azuremonitormetrics', action='store_true', deprecate_info=c.deprecate(target='--disable-azuremonitormetrics', redirect='--disable-azure-monitor-metrics', hide=True)) - c.argument('disable_azure_monitor_metrics', action='store_true') - c.argument('enable_vpa', action='store_true', is_preview=True, help="enable vertical pod autoscaler for cluster") - c.argument('disable_vpa', action='store_true', is_preview=True, help="disable vertical pod autoscaler for cluster") - c.argument('cluster_snapshot_id', validator=validate_cluster_snapshot_id, is_preview=True) - c.argument('custom_ca_trust_certificates', options_list=["--custom-ca-trust-certificates", "--ca-certs"], validator=validate_custom_ca_trust_certificates, is_preview=True, help="path to file containing list of new line separated CAs") - c.argument('guardrails_level', arg_type=get_enum_type(guardrails_levels), is_preview=True) - c.argument('guardrails_version', help='The guardrails version', is_preview=True) - c.argument('guardrails_excluded_ns', is_preview=True) - c.argument('enable_network_observability', action='store_true', is_preview=True, help="enable network observability for cluster") - c.argument('disable_network_observability', action='store_true', is_preview=True, help="disable network observability for cluster") - c.argument('enable_cost_analysis', is_preview=True, action='store_true') - c.argument('disable_cost_analysis', is_preview=True, action='store_true') + c.argument( + "ssh_key_value", + type=file_type, + completer=FilesCompleter(), + validator=validate_ssh_key_for_update, + ) + c.argument("load_balancer_managed_outbound_ipv6_count", type=int) + c.argument("outbound_type", arg_type=get_enum_type(outbound_types)) + c.argument( + "enable_pod_security_policy", + action="store_true", + deprecate_info=c.deprecate( + target="--enable-pod-security-policy", hide=True + ), + ) + c.argument("disable_pod_security_policy", action="store_true", is_preview=True) + c.argument("enable_pod_identity", action="store_true") + c.argument("enable_pod_identity_with_kubenet", action="store_true") + c.argument("disable_pod_identity", action="store_true") + c.argument("enable_workload_identity", action="store_true", is_preview=True) + c.argument("disable_workload_identity", action="store_true", is_preview=True) + c.argument("enable_image_cleaner", action="store_true") + c.argument( + "disable_image_cleaner", + action="store_true", + validator=validate_image_cleaner_enable_disable_mutually_exclusive, + ) + c.argument("image_cleaner_interval_hours", type=int) + c.argument("disable_image_integrity", action="store_true", 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) + c.argument( + "enable_node_restriction", + action="store_true", + is_preview=True, + help="enable node restriction for cluster", + ) + c.argument( + "disable_node_restriction", + action="store_true", + is_preview=True, + help="disable node restriction for cluster", + ) + c.argument( + "enable_private_cluster", + action="store_true", + is_preview=True, + help="enable private cluster for apiserver vnet integration", + ) + c.argument( + "disable_private_cluster", + action="store_true", + is_preview=True, + help="disable private cluster for apiserver vnet integration", + ) + c.argument("private_dns_zone", is_preview=True) + c.argument( + "enable_azuremonitormetrics", + action="store_true", + deprecate_info=c.deprecate( + target="--enable-azuremonitormetrics", + redirect="--enable-azure-monitor-metrics", + hide=True, + ), + ) + c.argument("enable_azure_monitor_metrics", action="store_true") + c.argument( + "azure_monitor_workspace_resource_id", + validator=validate_azuremonitorworkspaceresourceid, + ) + c.argument("ksm_metric_labels_allow_list") + c.argument("ksm_metric_annotations_allow_list") + c.argument("grafana_resource_id", validator=validate_grafanaresourceid) + c.argument("enable_windows_recording_rules", action="store_true") + c.argument( + "disable_azuremonitormetrics", + action="store_true", + deprecate_info=c.deprecate( + target="--disable-azuremonitormetrics", + redirect="--disable-azure-monitor-metrics", + hide=True, + ), + ) + c.argument("disable_azure_monitor_metrics", action="store_true") + c.argument( + "enable_vpa", + action="store_true", + is_preview=True, + help="enable vertical pod autoscaler for cluster", + ) + c.argument( + "disable_vpa", + action="store_true", + is_preview=True, + help="disable vertical pod autoscaler for cluster", + ) + c.argument( + "cluster_snapshot_id", + validator=validate_cluster_snapshot_id, + is_preview=True, + ) + c.argument( + "custom_ca_trust_certificates", + options_list=["--custom-ca-trust-certificates", "--ca-certs"], + validator=validate_custom_ca_trust_certificates, + is_preview=True, + help="path to file containing list of new line separated CAs", + ) + c.argument( + "guardrails_level", + arg_type=get_enum_type(guardrails_levels), + is_preview=True, + ) + c.argument("guardrails_version", help="The guardrails version", is_preview=True) + c.argument("guardrails_excluded_ns", is_preview=True) + c.argument( + "enable_network_observability", + action="store_true", + is_preview=True, + help="enable network observability for cluster", + ) + c.argument( + "disable_network_observability", + action="store_true", + is_preview=True, + help="disable network observability for cluster", + ) + c.argument("enable_cost_analysis", is_preview=True, action="store_true") + c.argument("disable_cost_analysis", is_preview=True, action="store_true") # azure container storage - c.argument('enable_azure_container_storage', arg_type=get_enum_type(storage_pool_types), - help='enable azure container storage and define storage pool type') - c.argument('disable_azure_container_storage', action='store_true', - help='Flag to disable azure container storage') - c.argument('storage_pool_name', help='set storage pool name for azure container storage') - c.argument('storage_pool_size', help='set storage pool size for azure container storage') - c.argument('storage_pool_sku', arg_type=get_enum_type(storage_pool_skus), - help='set azure disk type storage pool sku for azure container storage') - c.argument('storage_pool_option', arg_type=get_enum_type(storage_pool_options), - help='set ephemeral disk storage pool option for azure container storage') - c.argument('azure_container_storage_nodepools', - help='define the comma separated nodepool list to install azure container storage') - c.argument('node_provisioning_mode', is_preview=True, arg_type=get_enum_type(node_provisioning_modes), - help='Set the node provisioning mode of the cluster. Valid values are "Auto" and "Manual". For more information on "Auto" mode see aka.ms/aks/nap.') - - with self.argument_context('aks upgrade') as c: - c.argument('kubernetes_version', completer=get_k8s_upgrades_completion_list) - c.argument('cluster_snapshot_id', validator=validate_cluster_snapshot_id, is_preview=True) - c.argument('yes', options_list=['--yes', '-y'], help='Do not prompt for confirmation.', action='store_true') - - with self.argument_context('aks scale') as c: - c.argument('nodepool_name', help='Node pool name, upto 12 alphanumeric characters', validator=validate_nodepool_name) - - with self.argument_context('aks nodepool') as c: - c.argument('cluster_name', help='The cluster name.') - c.argument('nodepool_name', options_list=['--nodepool-name', '--name', '-n'], validator=validate_nodepool_name, help='The node pool name.') - - with self.argument_context('aks nodepool wait') as c: - c.argument('resource_name', options_list=['--cluster-name'], help='The cluster name.') + c.argument( + "enable_azure_container_storage", + arg_type=get_enum_type(storage_pool_types), + help="enable azure container storage and define storage pool type", + ) + c.argument( + "disable_azure_container_storage", + action="store_true", + help="Flag to disable azure container storage", + ) + c.argument( + "storage_pool_name", + help="set storage pool name for azure container storage", + ) + c.argument( + "storage_pool_size", + help="set storage pool size for azure container storage", + ) + c.argument( + "storage_pool_sku", + arg_type=get_enum_type(storage_pool_skus), + help="set azure disk type storage pool sku for azure container storage", + ) + c.argument( + "storage_pool_option", + arg_type=get_enum_type(storage_pool_options), + help="set ephemeral disk storage pool option for azure container storage", + ) + c.argument( + "azure_container_storage_nodepools", + help="define the comma separated nodepool list to install azure container storage", + ) + c.argument( + "node_provisioning_mode", + is_preview=True, + arg_type=get_enum_type(node_provisioning_modes), + help=( + 'Set the node provisioning mode of the cluster. Valid values are "Auto" and "Manual". ' + 'For more information on "Auto" mode see aka.ms/aks/nap.' + ) + ) + + with self.argument_context("aks upgrade") as c: + c.argument("kubernetes_version", completer=get_k8s_upgrades_completion_list) + c.argument( + "cluster_snapshot_id", + validator=validate_cluster_snapshot_id, + is_preview=True, + ) + c.argument( + "yes", + options_list=["--yes", "-y"], + help="Do not prompt for confirmation.", + action="store_true", + ) + + with self.argument_context("aks scale") as c: + c.argument( + "nodepool_name", + help="Node pool name, upto 12 alphanumeric characters", + validator=validate_nodepool_name, + ) + + with self.argument_context("aks nodepool") as c: + c.argument("cluster_name", help="The cluster name.") + c.argument( + "nodepool_name", + options_list=["--nodepool-name", "--name", "-n"], + validator=validate_nodepool_name, + help="The node pool name.", + ) + + with self.argument_context("aks nodepool wait") as c: + c.argument( + "resource_name", options_list=["--cluster-name"], help="The cluster name." + ) # the option name '--agent-pool-name' is depracated, left for compatibility only - c.argument('agent_pool_name', options_list=['--nodepool-name', '--name', '-n', c.deprecate(target='--agent-pool-name', redirect='--nodepool-name', hide=True)], validator=validate_agent_pool_name, help='The node pool name.') - - with self.argument_context('aks nodepool add') as c: - c.argument('node_vm_size', options_list=['--node-vm-size', '-s'], completer=get_vm_size_completion_list) - c.argument('os_type') - c.argument('os_sku', arg_type=get_enum_type(node_os_skus), validator=validate_os_sku) - c.argument('snapshot_id', validator=validate_snapshot_id) - c.argument('vnet_subnet_id', validator=validate_vnet_subnet_id) - c.argument('pod_subnet_id', validator=validate_pod_subnet_id) - c.argument('enable_node_public_ip', action='store_true') - c.argument('node_public_ip_prefix_id') - c.argument('enable_cluster_autoscaler', options_list=["--enable-cluster-autoscaler", "-e"], action='store_true') - c.argument('min_count', type=int, validator=validate_nodes_count) - c.argument('max_count', type=int, validator=validate_nodes_count) - c.argument('priority', arg_type=get_enum_type(node_priorities), validator=validate_priority) - c.argument('eviction_policy', arg_type=get_enum_type(node_eviction_policies), validator=validate_eviction_policy) - c.argument('spot_max_price', type=float, validator=validate_spot_max_price) - c.argument('labels', nargs='*', validator=validate_nodepool_labels) - c.argument('tags', tags_type) - c.argument('node_taints', validator=validate_nodepool_taints) - c.argument('node_osdisk_type', arg_type=get_enum_type(node_os_disk_types)) - c.argument('node_osdisk_size', type=int) - c.argument('max_surge', validator=validate_max_surge) - c.argument('drain_timeout', type=int) - c.argument('node_soak_duration', type=int) - c.argument('mode', arg_type=get_enum_type(node_mode_types)) - c.argument('scale_down_mode', arg_type=get_enum_type(scale_down_modes)) - c.argument('max_pods', type=int, options_list=['--max-pods', '-m']) - c.argument('zones', zones_type, options_list=['--zones', '-z'], help='Space-separated list of availability zones where agent nodes will be placed.') - c.argument('ppg') - c.argument('vm_set_type', validator=validate_vm_set_type) - c.argument('enable_encryption_at_host', action='store_true') - c.argument('enable_ultra_ssd', action='store_true') - c.argument('enable_fips_image', action='store_true') - c.argument('kubelet_config') - c.argument('linux_os_config') - c.argument('host_group_id', validator=validate_host_group_id) - c.argument('gpu_instance_profile', arg_type=get_enum_type(gpu_instance_profiles)) + c.argument( + "agent_pool_name", + options_list=[ + "--nodepool-name", + "--name", + "-n", + c.deprecate( + target="--agent-pool-name", redirect="--nodepool-name", hide=True + ), + ], + validator=validate_agent_pool_name, + help="The node pool name.", + ) + + with self.argument_context("aks nodepool add") as c: + c.argument( + "node_vm_size", + options_list=["--node-vm-size", "-s"], + completer=get_vm_size_completion_list, + ) + c.argument("os_type") + c.argument( + "os_sku", arg_type=get_enum_type(node_os_skus), validator=validate_os_sku + ) + c.argument("snapshot_id", validator=validate_snapshot_id) + c.argument("vnet_subnet_id", validator=validate_vnet_subnet_id) + c.argument("pod_subnet_id", validator=validate_pod_subnet_id) + c.argument("enable_node_public_ip", action="store_true") + c.argument("node_public_ip_prefix_id") + c.argument( + "enable_cluster_autoscaler", + options_list=["--enable-cluster-autoscaler", "-e"], + action="store_true", + ) + c.argument("min_count", type=int, validator=validate_nodes_count) + c.argument("max_count", type=int, validator=validate_nodes_count) + c.argument( + "priority", + arg_type=get_enum_type(node_priorities), + validator=validate_priority, + ) + c.argument( + "eviction_policy", + arg_type=get_enum_type(node_eviction_policies), + validator=validate_eviction_policy, + ) + c.argument("spot_max_price", type=float, validator=validate_spot_max_price) + c.argument("labels", nargs="*", validator=validate_nodepool_labels) + c.argument("tags", tags_type) + c.argument("node_taints", validator=validate_nodepool_taints) + c.argument("node_osdisk_type", arg_type=get_enum_type(node_os_disk_types)) + c.argument("node_osdisk_size", type=int) + c.argument("max_surge", validator=validate_max_surge) + c.argument("drain_timeout", type=int) + c.argument("node_soak_duration", type=int) + c.argument("mode", arg_type=get_enum_type(node_mode_types)) + c.argument("scale_down_mode", arg_type=get_enum_type(scale_down_modes)) + c.argument("max_pods", type=int, options_list=["--max-pods", "-m"]) + c.argument( + "zones", + zones_type, + options_list=["--zones", "-z"], + help="Space-separated list of availability zones where agent nodes will be placed.", + ) + c.argument("ppg") + c.argument("vm_set_type", validator=validate_vm_set_type) + c.argument("enable_encryption_at_host", action="store_true") + c.argument("enable_ultra_ssd", action="store_true") + c.argument("enable_fips_image", action="store_true") + c.argument("kubelet_config") + c.argument("linux_os_config") + c.argument("host_group_id", validator=validate_host_group_id) + c.argument( + "gpu_instance_profile", arg_type=get_enum_type(gpu_instance_profiles) + ) # misc - c.argument('aks_custom_headers') + c.argument("aks_custom_headers") # extensions - c.argument('crg_id', validator=validate_crg_id, is_preview=True) - c.argument('message_of_the_day', validator=validate_message_of_the_day) - c.argument('workload_runtime', arg_type=get_enum_type(workload_runtimes), default=CONST_WORKLOAD_RUNTIME_OCI_CONTAINER) - c.argument('enable_custom_ca_trust', action='store_true', validator=validate_enable_custom_ca_trust) - c.argument('disable_windows_outbound_nat', action='store_true', validator=validate_disable_windows_outbound_nat) - c.argument('allowed_host_ports', validator=validate_allowed_host_ports, is_preview=True) - c.argument('asg_ids', validator=validate_application_security_groups, is_preview=True) - c.argument('enable_artifact_streaming', action='store_true', validator=validate_artifact_streaming, is_preview=True) - c.argument('node_public_ip_tags', arg_type=tags_type, validator=validate_node_public_ip_tags, - help='space-separated tags: key[=value] [key[=value] ...].') - - with self.argument_context('aks nodepool update') as c: - c.argument('enable_cluster_autoscaler', options_list=[ - "--enable-cluster-autoscaler", "-e"], action='store_true') - c.argument('disable_cluster_autoscaler', options_list=[ - "--disable-cluster-autoscaler", "-d"], action='store_true') - c.argument('update_cluster_autoscaler', options_list=[ - "--update-cluster-autoscaler", "-u"], action='store_true') - c.argument('min_count', type=int, validator=validate_nodes_count) - c.argument('max_count', type=int, validator=validate_nodes_count) - c.argument('labels', nargs='*', validator=validate_nodepool_labels) - c.argument('tags', tags_type) - c.argument('node_taints', validator=validate_nodepool_taints) - c.argument('max_surge', validator=validate_max_surge) - c.argument('drain_timeout', type=int) - c.argument('node_soak_duration', type=int) - c.argument('mode', arg_type=get_enum_type(node_mode_types)) - c.argument('scale_down_mode', arg_type=get_enum_type(scale_down_modes)) + c.argument("crg_id", validator=validate_crg_id, is_preview=True) + c.argument("message_of_the_day", validator=validate_message_of_the_day) + c.argument( + "workload_runtime", + arg_type=get_enum_type(workload_runtimes), + default=CONST_WORKLOAD_RUNTIME_OCI_CONTAINER, + ) + c.argument( + "enable_custom_ca_trust", + action="store_true", + validator=validate_enable_custom_ca_trust, + ) + c.argument( + "disable_windows_outbound_nat", + action="store_true", + validator=validate_disable_windows_outbound_nat, + ) + c.argument( + "allowed_host_ports", validator=validate_allowed_host_ports, is_preview=True + ) + c.argument( + "asg_ids", validator=validate_application_security_groups, is_preview=True + ) + c.argument( + "enable_artifact_streaming", + action="store_true", + validator=validate_artifact_streaming, + is_preview=True, + ) + c.argument( + "node_public_ip_tags", + arg_type=tags_type, + validator=validate_node_public_ip_tags, + help="space-separated tags: key[=value] [key[=value] ...].", + ) + + with self.argument_context("aks nodepool update") as c: + c.argument( + "enable_cluster_autoscaler", + options_list=["--enable-cluster-autoscaler", "-e"], + action="store_true", + ) + c.argument( + "disable_cluster_autoscaler", + options_list=["--disable-cluster-autoscaler", "-d"], + action="store_true", + ) + c.argument( + "update_cluster_autoscaler", + options_list=["--update-cluster-autoscaler", "-u"], + action="store_true", + ) + c.argument("min_count", type=int, validator=validate_nodes_count) + c.argument("max_count", type=int, validator=validate_nodes_count) + c.argument("labels", nargs="*", validator=validate_nodepool_labels) + c.argument("tags", tags_type) + c.argument("node_taints", validator=validate_nodepool_taints) + c.argument("max_surge", validator=validate_max_surge) + c.argument("drain_timeout", type=int) + c.argument("node_soak_duration", type=int) + c.argument("mode", arg_type=get_enum_type(node_mode_types)) + c.argument("scale_down_mode", arg_type=get_enum_type(scale_down_modes)) # extensions - c.argument('enable_custom_ca_trust', action='store_true', validator=validate_enable_custom_ca_trust) - c.argument('disable_custom_ca_trust', options_list=['--disable-custom-ca-trust', '--dcat'], action='store_true') - c.argument('allowed_host_ports', validator=validate_allowed_host_ports, is_preview=True) - c.argument('asg_ids', validator=validate_application_security_groups, is_preview=True) - c.argument('enable_artifact_streaming', action='store_true', validator=validate_artifact_streaming, is_preview=True) - c.argument('os_sku', arg_type=get_enum_type(node_os_skus_update), validator=validate_os_sku) - - with self.argument_context('aks nodepool upgrade') as c: - c.argument('max_surge', validator=validate_max_surge) - c.argument('drain_timeout', type=int) - c.argument('node_soak_duration', type=int) - c.argument('snapshot_id', validator=validate_snapshot_id) - c.argument('yes', options_list=['--yes', '-y'], help='Do not prompt for confirmation.', action='store_true') - c.argument('aks_custom_headers') - - with self.argument_context('aks nodepool delete') as c: - c.argument('ignore_pod_disruption_budget', options_list=[ - "--ignore-pod-disruption-budget", "-i"], action=get_three_state_flag(), is_preview=True, - help='delete an AKS nodepool by ignoring PodDisruptionBudget setting') - - with self.argument_context('aks machine') as c: - c.argument('cluster_name', help='The cluster name.') - c.argument('nodepool_name', validator=validate_nodepool_name, help='The node pool name.') - - with self.argument_context('aks machine show') as c: - c.argument('machine_name', help='to display specific information for all machines.') - - with self.argument_context('aks maintenanceconfiguration') as c: - c.argument('cluster_name', help='The cluster name.') - - for scope in ['aks maintenanceconfiguration add', 'aks maintenanceconfiguration update']: + c.argument( + "enable_custom_ca_trust", + action="store_true", + validator=validate_enable_custom_ca_trust, + ) + c.argument( + "disable_custom_ca_trust", + options_list=["--disable-custom-ca-trust", "--dcat"], + action="store_true", + ) + c.argument( + "allowed_host_ports", validator=validate_allowed_host_ports, is_preview=True + ) + c.argument( + "asg_ids", validator=validate_application_security_groups, is_preview=True + ) + c.argument( + "enable_artifact_streaming", + action="store_true", + validator=validate_artifact_streaming, + is_preview=True, + ) + c.argument( + "os_sku", + arg_type=get_enum_type(node_os_skus_update), + validator=validate_os_sku, + ) + + with self.argument_context("aks nodepool upgrade") as c: + c.argument("max_surge", validator=validate_max_surge) + c.argument("drain_timeout", type=int) + c.argument("node_soak_duration", type=int) + c.argument("snapshot_id", validator=validate_snapshot_id) + c.argument( + "yes", + options_list=["--yes", "-y"], + help="Do not prompt for confirmation.", + action="store_true", + ) + c.argument("aks_custom_headers") + + with self.argument_context("aks nodepool delete") as c: + c.argument( + "ignore_pod_disruption_budget", + options_list=["--ignore-pod-disruption-budget", "-i"], + action=get_three_state_flag(), + is_preview=True, + help="delete an AKS nodepool by ignoring PodDisruptionBudget setting", + ) + + with self.argument_context("aks machine") as c: + c.argument("cluster_name", help="The cluster name.") + c.argument( + "nodepool_name", + validator=validate_nodepool_name, + help="The node pool name.", + ) + + with self.argument_context("aks machine show") as c: + c.argument( + "machine_name", help="to display specific information for all machines." + ) + + with self.argument_context("aks maintenanceconfiguration") as c: + c.argument("cluster_name", help="The cluster name.") + + for scope in [ + "aks maintenanceconfiguration add", + "aks maintenanceconfiguration update", + ]: with self.argument_context(scope) as c: - c.argument('config_name', options_list=[ - '--name', '-n'], help='The config name.') - c.argument('config_file', help='The config json file.') - c.argument('weekday', help='Weekday on which maintenance can happen. e.g. Monday') - c.argument('start_hour', type=int, help='Maintenance start hour of 1 hour window on the weekday. e.g. 1 means 1:00am - 2:00am') - c.argument('schedule_type', arg_type=get_enum_type(schedule_types), - help='Schedule type for non-default maintenance configuration.') - c.argument('interval_days', type=int, help='The number of days between each set of occurrences for Daily schedule.') - c.argument('interval_weeks', type=int, help='The number of weeks between each set of occurrences for Weekly schedule.') - c.argument('interval_months', type=int, help='The number of months between each set of occurrences for AbsoluteMonthly or RelativeMonthly schedule.') - c.argument('day_of_week', help='Specify on which day of the week the maintenance occurs for Weekly or RelativeMonthly schedule.') - c.argument('day_of_month', help='Specify on which date of the month the maintenance occurs for AbsoluteMonthly schedule.') - c.argument('week_index', arg_type=get_enum_type(week_indexes), - help='Specify on which instance of the weekday specified in --day-of-week the maintenance occurs for RelativeMonthly schedule.') - c.argument('duration_hours', options_list=['--duration'], type=int, - help='The length of maintenance window. The value ranges from 4 to 24 hours.') - c.argument('utc_offset', validator=validate_utc_offset, - help='The UTC offset in format +/-HH:mm. e.g. -08:00 or +05:30.') - c.argument('start_date', validator=validate_start_date, - help='The date the maintenance window activates. e.g. 2023-01-01.') - c.argument('start_time', validator=validate_start_time, - help='The start time of the maintenance window. e.g. 09:30.') - - for scope in ['aks maintenanceconfiguration show', 'aks maintenanceconfiguration delete']: + c.argument( + "config_name", options_list=["--name", "-n"], help="The config name." + ) + c.argument("config_file", help="The config json file.") + c.argument( + "weekday", help="Weekday on which maintenance can happen. e.g. Monday" + ) + c.argument( + "start_hour", + type=int, + help="Maintenance start hour of 1 hour window on the weekday. e.g. 1 means 1:00am - 2:00am", + ) + c.argument( + "schedule_type", + arg_type=get_enum_type(schedule_types), + help="Schedule type for non-default maintenance configuration.", + ) + c.argument( + "interval_days", + type=int, + help="The number of days between each set of occurrences for Daily schedule.", + ) + c.argument( + "interval_weeks", + type=int, + help="The number of weeks between each set of occurrences for Weekly schedule.", + ) + c.argument( + "interval_months", + type=int, + help=( + "The number of months between each set of occurrences for AbsoluteMonthly or " + "RelativeMonthly schedule." + ) + ) + c.argument( + "day_of_week", + help="Specify on which day of the week the maintenance occurs for Weekly or RelativeMonthly schedule.", + ) + c.argument( + "day_of_month", + help="Specify on which date of the month the maintenance occurs for AbsoluteMonthly schedule.", + ) + c.argument( + "week_index", + arg_type=get_enum_type(week_indexes), + help=( + "Specify on which instance of the weekday specified in --day-of-week " + "the maintenance occurs for RelativeMonthly schedule." + ) + ) + c.argument( + "duration_hours", + options_list=["--duration"], + type=int, + help="The length of maintenance window. The value ranges from 4 to 24 hours.", + ) + c.argument( + "utc_offset", + validator=validate_utc_offset, + help="The UTC offset in format +/-HH:mm. e.g. -08:00 or +05:30.", + ) + c.argument( + "start_date", + validator=validate_start_date, + help="The date the maintenance window activates. e.g. 2023-01-01.", + ) + c.argument( + "start_time", + validator=validate_start_time, + help="The start time of the maintenance window. e.g. 09:30.", + ) + + for scope in [ + "aks maintenanceconfiguration show", + "aks maintenanceconfiguration delete", + ]: with self.argument_context(scope) as c: - c.argument('config_name', options_list=[ - '--name', '-n'], help='The config name.') - - with self.argument_context('aks addon show') as c: - c.argument('addon', options_list=[ - '--addon', '-a'], validator=validate_addon) - - with self.argument_context('aks addon enable') as c: - c.argument('addon', options_list=[ - '--addon', '-a'], validator=validate_addon) - c.argument('subnet_name', options_list=['--subnet-name', '-s']) - c.argument('enable_sgxquotehelper', action='store_true') - c.argument('osm_mesh_name', options_list=['--osm-mesh-name']) - c.argument('appgw_name', options_list=[ - '--appgw-name'], arg_group='Application Gateway') - c.argument('appgw_subnet_prefix', options_list=[ - '--appgw-subnet-prefix'], arg_group='Application Gateway', deprecate_info=c.deprecate(redirect='--appgw-subnet-cidr', hide=True)) - c.argument('appgw_subnet_cidr', options_list=[ - '--appgw-subnet-cidr'], arg_group='Application Gateway') - c.argument('appgw_id', options_list=[ - '--appgw-id'], arg_group='Application Gateway') - c.argument('appgw_subnet_id', options_list=[ - '--appgw-subnet-id'], arg_group='Application Gateway') - c.argument('appgw_watch_namespace', options_list=[ - '--appgw-watch-namespace'], arg_group='Application Gateway') - c.argument('enable_secret_rotation', action='store_true') - c.argument('rotation_poll_interval') - c.argument('workspace_resource_id') - c.argument('enable_msi_auth_for_monitoring', - arg_type=get_three_state_flag(), is_preview=True) - c.argument('enable_syslog', arg_type=get_three_state_flag(), is_preview=True) - c.argument('data_collection_settings', is_preview=True) - c.argument('dns_zone_resource_id', deprecate_info=c.deprecate(target='--dns-zone-resource-id', redirect='--dns-zone-resource-ids', hide=True)) - c.argument('dns_zone_resource_ids', is_preview=True) - - with self.argument_context('aks addon disable') as c: - c.argument('addon', options_list=[ - '--addon', '-a'], validator=validate_addon) - - with self.argument_context('aks addon update') as c: - c.argument('addon', options_list=[ - '--addon', '-a'], validator=validate_addon) - c.argument('subnet_name', options_list=['--subnet-name', '-s']) - c.argument('enable_sgxquotehelper', action='store_true') - c.argument('osm_mesh_name', options_list=['--osm-mesh-name']) - c.argument('appgw_name', options_list=[ - '--appgw-name'], arg_group='Application Gateway') - c.argument('appgw_subnet_prefix', options_list=[ - '--appgw-subnet-prefix'], arg_group='Application Gateway', deprecate_info=c.deprecate(redirect='--appgw-subnet-cidr', hide=True)) - c.argument('appgw_subnet_cidr', options_list=[ - '--appgw-subnet-cidr'], arg_group='Application Gateway') - c.argument('appgw_id', options_list=[ - '--appgw-id'], arg_group='Application Gateway') - c.argument('appgw_subnet_id', options_list=[ - '--appgw-subnet-id'], arg_group='Application Gateway') - c.argument('appgw_watch_namespace', options_list=[ - '--appgw-watch-namespace'], arg_group='Application Gateway') - c.argument('enable_secret_rotation', action='store_true') - c.argument('rotation_poll_interval') - c.argument('workspace_resource_id') - c.argument('enable_msi_auth_for_monitoring', - arg_type=get_three_state_flag(), is_preview=True) - c.argument('enable_syslog', arg_type=get_three_state_flag(), is_preview=True) - c.argument('data_collection_settings', is_preview=True) - c.argument('dns_zone_resource_id', deprecate_info=c.deprecate(target='--dns-zone-resource-id', redirect='--dns-zone-resource-ids', hide=True)) - c.argument('dns_zone_resource_ids', is_preview=True) - - with self.argument_context('aks disable-addons') as c: - c.argument('addons', options_list=['--addons', '-a'], validator=validate_addons) - - with self.argument_context('aks enable-addons') as c: - c.argument('addons', options_list=['--addons', '-a'], validator=validate_addons) - c.argument('subnet_name', options_list=['--subnet-name', '-s']) - c.argument('enable_sgxquotehelper', action='store_true') - c.argument('osm_mesh_name') - c.argument('appgw_name', arg_group='Application Gateway') - c.argument('appgw_subnet_prefix', arg_group='Application Gateway', deprecate_info=c.deprecate(redirect='--appgw-subnet-cidr', hide=True)) - c.argument('appgw_subnet_cidr', arg_group='Application Gateway') - c.argument('appgw_id', arg_group='Application Gateway') - c.argument('appgw_subnet_id', arg_group='Application Gateway') - c.argument('appgw_watch_namespace', arg_group='Application Gateway') - c.argument('enable_secret_rotation', action='store_true') - c.argument('rotation_poll_interval') - c.argument('workspace_resource_id') - c.argument('enable_msi_auth_for_monitoring', arg_type=get_three_state_flag(), is_preview=True) - c.argument('enable_syslog', arg_type=get_three_state_flag(), is_preview=True) - c.argument('data_collection_settings', is_preview=True) - c.argument('dns_zone_resource_id', deprecate_info=c.deprecate(target='--dns-zone-resource-id', redirect='--dns-zone-resource-ids', hide=True)) - c.argument('dns_zone_resource_ids', is_preview=True) - - with self.argument_context('aks get-credentials') as c: - c.argument('admin', options_list=['--admin', '-a'], default=False) - c.argument('context_name', options_list=['--context'], - help='If specified, overwrite the default context name.') - c.argument('user', options_list=[ - '--user', '-u'], default='clusterUser', validator=validate_user) - c.argument('path', options_list=['--file', '-f'], type=file_type, completer=FilesCompleter(), - default=os.path.join(os.path.expanduser('~'), '.kube', 'config')) - c.argument('public_fqdn', default=False, action='store_true') - c.argument('credential_format', options_list=['--format'], arg_type=get_enum_type(credential_formats)) - - with self.argument_context('aks pod-identity') as c: - c.argument('cluster_name', help='The cluster name.') - c.argument('aks_custom_headers', help='Send custom headers. When specified, format should be Key1=Value1,Key2=Value2.') - - with self.argument_context('aks pod-identity add') as c: - c.argument('identity_name', options_list=['--name', '-n'], default=None, required=False, - help='The pod identity name. Generate if not specified.', - validator=validate_pod_identity_resource_name('identity_name', required=False)) - c.argument('identity_namespace', options_list=[ - '--namespace'], help='The pod identity namespace.') - c.argument('identity_resource_id', options_list=[ - '--identity-resource-id'], help='Resource id of the identity to use.') - c.argument('binding_selector', options_list=[ - '--binding-selector'], help='Optional binding selector to use.') - - with self.argument_context('aks pod-identity delete') as c: - c.argument('identity_name', options_list=['--name', '-n'], default=None, required=True, - help='The pod identity name.', - validator=validate_pod_identity_resource_name('identity_name', required=True)) - c.argument('identity_namespace', options_list=[ - '--namespace'], help='The pod identity namespace.') - - with self.argument_context('aks pod-identity exception add') as c: - c.argument('exc_name', options_list=['--name', '-n'], default=None, required=False, - help='The pod identity exception name. Generate if not specified.', - validator=validate_pod_identity_resource_name('exc_name', required=False)) - c.argument('exc_namespace', options_list=['--namespace'], required=True, - help='The pod identity exception namespace.', - validator=validate_pod_identity_resource_namespace) - c.argument('pod_labels', nargs='*', required=True, - help='space-separated labels: key=value [key=value ...].', - validator=validate_pod_identity_pod_labels) - - with self.argument_context('aks pod-identity exception delete') as c: - c.argument('exc_name', options_list=['--name', '-n'], required=True, - help='The pod identity exception name to remove.', - validator=validate_pod_identity_resource_name('exc_name', required=True)) - c.argument('exc_namespace', options_list=['--namespace'], required=True, - help='The pod identity exception namespace to remove.', - validator=validate_pod_identity_resource_namespace) - - with self.argument_context('aks pod-identity exception update') as c: - c.argument('exc_name', options_list=['--name', '-n'], required=True, - help='The pod identity exception name to remove.', - validator=validate_pod_identity_resource_name('exc_name', required=True)) - c.argument('exc_namespace', options_list=['--namespace'], required=True, - help='The pod identity exception namespace to remove.', - validator=validate_pod_identity_resource_namespace) - c.argument('pod_labels', nargs='*', required=True, - help='pod labels in key=value [key=value ...].', - validator=validate_pod_identity_pod_labels) - - for scope in ['aks nodepool snapshot create']: + c.argument( + "config_name", options_list=["--name", "-n"], help="The config name." + ) + + with self.argument_context("aks addon show") as c: + c.argument("addon", options_list=["--addon", "-a"], validator=validate_addon) + + with self.argument_context("aks addon enable") as c: + c.argument("addon", options_list=["--addon", "-a"], validator=validate_addon) + c.argument("subnet_name", options_list=["--subnet-name", "-s"]) + c.argument("enable_sgxquotehelper", action="store_true") + c.argument("osm_mesh_name", options_list=["--osm-mesh-name"]) + c.argument( + "appgw_name", options_list=["--appgw-name"], arg_group="Application Gateway" + ) + c.argument( + "appgw_subnet_prefix", + options_list=["--appgw-subnet-prefix"], + arg_group="Application Gateway", + deprecate_info=c.deprecate(redirect="--appgw-subnet-cidr", hide=True), + ) + c.argument( + "appgw_subnet_cidr", + options_list=["--appgw-subnet-cidr"], + arg_group="Application Gateway", + ) + c.argument( + "appgw_id", options_list=["--appgw-id"], arg_group="Application Gateway" + ) + c.argument( + "appgw_subnet_id", + options_list=["--appgw-subnet-id"], + arg_group="Application Gateway", + ) + c.argument( + "appgw_watch_namespace", + options_list=["--appgw-watch-namespace"], + arg_group="Application Gateway", + ) + c.argument("enable_secret_rotation", action="store_true") + c.argument("rotation_poll_interval") + c.argument("workspace_resource_id") + c.argument( + "enable_msi_auth_for_monitoring", + arg_type=get_three_state_flag(), + is_preview=True, + ) + c.argument("enable_syslog", arg_type=get_three_state_flag(), is_preview=True) + c.argument("data_collection_settings", is_preview=True) + c.argument( + "dns_zone_resource_id", + deprecate_info=c.deprecate( + target="--dns-zone-resource-id", + redirect="--dns-zone-resource-ids", + hide=True, + ), + ) + c.argument("dns_zone_resource_ids", is_preview=True) + + with self.argument_context("aks addon disable") as c: + c.argument("addon", options_list=["--addon", "-a"], validator=validate_addon) + + with self.argument_context("aks addon update") as c: + c.argument("addon", options_list=["--addon", "-a"], validator=validate_addon) + c.argument("subnet_name", options_list=["--subnet-name", "-s"]) + c.argument("enable_sgxquotehelper", action="store_true") + c.argument("osm_mesh_name", options_list=["--osm-mesh-name"]) + c.argument( + "appgw_name", options_list=["--appgw-name"], arg_group="Application Gateway" + ) + c.argument( + "appgw_subnet_prefix", + options_list=["--appgw-subnet-prefix"], + arg_group="Application Gateway", + deprecate_info=c.deprecate(redirect="--appgw-subnet-cidr", hide=True), + ) + c.argument( + "appgw_subnet_cidr", + options_list=["--appgw-subnet-cidr"], + arg_group="Application Gateway", + ) + c.argument( + "appgw_id", options_list=["--appgw-id"], arg_group="Application Gateway" + ) + c.argument( + "appgw_subnet_id", + options_list=["--appgw-subnet-id"], + arg_group="Application Gateway", + ) + c.argument( + "appgw_watch_namespace", + options_list=["--appgw-watch-namespace"], + arg_group="Application Gateway", + ) + c.argument("enable_secret_rotation", action="store_true") + c.argument("rotation_poll_interval") + c.argument("workspace_resource_id") + c.argument( + "enable_msi_auth_for_monitoring", + arg_type=get_three_state_flag(), + is_preview=True, + ) + c.argument("enable_syslog", arg_type=get_three_state_flag(), is_preview=True) + c.argument("data_collection_settings", is_preview=True) + c.argument( + "dns_zone_resource_id", + deprecate_info=c.deprecate( + target="--dns-zone-resource-id", + redirect="--dns-zone-resource-ids", + hide=True, + ), + ) + c.argument("dns_zone_resource_ids", is_preview=True) + + with self.argument_context("aks disable-addons") as c: + c.argument("addons", options_list=["--addons", "-a"], validator=validate_addons) + + with self.argument_context("aks enable-addons") as c: + c.argument("addons", options_list=["--addons", "-a"], validator=validate_addons) + c.argument("subnet_name", options_list=["--subnet-name", "-s"]) + c.argument("enable_sgxquotehelper", action="store_true") + c.argument("osm_mesh_name") + c.argument("appgw_name", arg_group="Application Gateway") + c.argument( + "appgw_subnet_prefix", + arg_group="Application Gateway", + deprecate_info=c.deprecate(redirect="--appgw-subnet-cidr", hide=True), + ) + c.argument("appgw_subnet_cidr", arg_group="Application Gateway") + c.argument("appgw_id", arg_group="Application Gateway") + c.argument("appgw_subnet_id", arg_group="Application Gateway") + c.argument("appgw_watch_namespace", arg_group="Application Gateway") + c.argument("enable_secret_rotation", action="store_true") + c.argument("rotation_poll_interval") + c.argument("workspace_resource_id") + c.argument( + "enable_msi_auth_for_monitoring", + arg_type=get_three_state_flag(), + is_preview=True, + ) + c.argument("enable_syslog", arg_type=get_three_state_flag(), is_preview=True) + c.argument("data_collection_settings", is_preview=True) + c.argument( + "dns_zone_resource_id", + deprecate_info=c.deprecate( + target="--dns-zone-resource-id", + redirect="--dns-zone-resource-ids", + hide=True, + ), + ) + c.argument("dns_zone_resource_ids", is_preview=True) + + with self.argument_context("aks get-credentials") as c: + c.argument("admin", options_list=["--admin", "-a"], default=False) + c.argument( + "context_name", + options_list=["--context"], + help="If specified, overwrite the default context name.", + ) + c.argument( + "user", + options_list=["--user", "-u"], + default="clusterUser", + validator=validate_user, + ) + c.argument( + "path", + options_list=["--file", "-f"], + type=file_type, + completer=FilesCompleter(), + default=os.path.join(os.path.expanduser("~"), ".kube", "config"), + ) + c.argument("public_fqdn", default=False, action="store_true") + c.argument( + "credential_format", + options_list=["--format"], + arg_type=get_enum_type(credential_formats), + ) + + with self.argument_context("aks pod-identity") as c: + c.argument("cluster_name", help="The cluster name.") + c.argument( + "aks_custom_headers", + help="Send custom headers. When specified, format should be Key1=Value1,Key2=Value2.", + ) + + with self.argument_context("aks pod-identity add") as c: + c.argument( + "identity_name", + options_list=["--name", "-n"], + default=None, + required=False, + help="The pod identity name. Generate if not specified.", + validator=validate_pod_identity_resource_name( + "identity_name", required=False + ), + ) + c.argument( + "identity_namespace", + options_list=["--namespace"], + help="The pod identity namespace.", + ) + c.argument( + "identity_resource_id", + options_list=["--identity-resource-id"], + help="Resource id of the identity to use.", + ) + c.argument( + "binding_selector", + options_list=["--binding-selector"], + help="Optional binding selector to use.", + ) + + with self.argument_context("aks pod-identity delete") as c: + c.argument( + "identity_name", + options_list=["--name", "-n"], + default=None, + required=True, + help="The pod identity name.", + validator=validate_pod_identity_resource_name( + "identity_name", required=True + ), + ) + c.argument( + "identity_namespace", + options_list=["--namespace"], + help="The pod identity namespace.", + ) + + with self.argument_context("aks pod-identity exception add") as c: + c.argument( + "exc_name", + options_list=["--name", "-n"], + default=None, + required=False, + help="The pod identity exception name. Generate if not specified.", + validator=validate_pod_identity_resource_name("exc_name", required=False), + ) + c.argument( + "exc_namespace", + options_list=["--namespace"], + required=True, + help="The pod identity exception namespace.", + validator=validate_pod_identity_resource_namespace, + ) + c.argument( + "pod_labels", + nargs="*", + required=True, + help="space-separated labels: key=value [key=value ...].", + validator=validate_pod_identity_pod_labels, + ) + + with self.argument_context("aks pod-identity exception delete") as c: + c.argument( + "exc_name", + options_list=["--name", "-n"], + required=True, + help="The pod identity exception name to remove.", + validator=validate_pod_identity_resource_name("exc_name", required=True), + ) + c.argument( + "exc_namespace", + options_list=["--namespace"], + required=True, + help="The pod identity exception namespace to remove.", + validator=validate_pod_identity_resource_namespace, + ) + + with self.argument_context("aks pod-identity exception update") as c: + c.argument( + "exc_name", + options_list=["--name", "-n"], + required=True, + help="The pod identity exception name to remove.", + validator=validate_pod_identity_resource_name("exc_name", required=True), + ) + c.argument( + "exc_namespace", + options_list=["--namespace"], + required=True, + help="The pod identity exception namespace to remove.", + validator=validate_pod_identity_resource_namespace, + ) + c.argument( + "pod_labels", + nargs="*", + required=True, + help="pod labels in key=value [key=value ...].", + validator=validate_pod_identity_pod_labels, + ) + + for scope in ["aks nodepool snapshot create"]: with self.argument_context(scope) as c: - c.argument('snapshot_name', options_list=[ - '--name', '-n'], required=True, help='The nodepool snapshot name.', validator=validate_snapshot_name) - c.argument('tags', tags_type) - c.argument('nodepool_id', required=True, - help='The nodepool id.', validator=validate_nodepool_id) - c.argument('aks_custom_headers') - - with self.argument_context('aks nodepool snapshot update') as c: - c.argument('snapshot_name', options_list=['--name', '-n'], help='The nodepool snapshot name.', validator=validate_snapshot_name) - c.argument('tags', tags_type, help='The tags to set to the snapshot.') - - for scope in ['aks nodepool snapshot show', 'aks nodepool snapshot delete']: + c.argument( + "snapshot_name", + options_list=["--name", "-n"], + required=True, + help="The nodepool snapshot name.", + validator=validate_snapshot_name, + ) + c.argument("tags", tags_type) + c.argument( + "nodepool_id", + required=True, + help="The nodepool id.", + validator=validate_nodepool_id, + ) + c.argument("aks_custom_headers") + + with self.argument_context("aks nodepool snapshot update") as c: + c.argument( + "snapshot_name", + options_list=["--name", "-n"], + help="The nodepool snapshot name.", + validator=validate_snapshot_name, + ) + c.argument("tags", tags_type, help="The tags to set to the snapshot.") + + for scope in ["aks nodepool snapshot show", "aks nodepool snapshot delete"]: with self.argument_context(scope) as c: - c.argument('snapshot_name', options_list=[ - '--name', '-n'], required=True, help='The nodepool snapshot name.', validator=validate_snapshot_name) - c.argument('yes', options_list=[ - '--yes', '-y'], help='Do not prompt for confirmation.', action='store_true') - - for scope in ['aks snapshot create']: + c.argument( + "snapshot_name", + options_list=["--name", "-n"], + required=True, + help="The nodepool snapshot name.", + validator=validate_snapshot_name, + ) + c.argument( + "yes", + options_list=["--yes", "-y"], + help="Do not prompt for confirmation.", + action="store_true", + ) + + for scope in ["aks snapshot create"]: with self.argument_context(scope) as c: - c.argument('snapshot_name', options_list=[ - '--name', '-n'], required=True, help='The cluster snapshot name.', validator=validate_snapshot_name) - c.argument('tags', tags_type) - c.argument('cluster_id', required=True, - validator=validate_cluster_id, help='The cluster id.') - c.argument('aks_custom_headers') - - for scope in ['aks snapshot show', 'aks snapshot delete']: + c.argument( + "snapshot_name", + options_list=["--name", "-n"], + required=True, + help="The cluster snapshot name.", + validator=validate_snapshot_name, + ) + c.argument("tags", tags_type) + c.argument( + "cluster_id", + required=True, + validator=validate_cluster_id, + help="The cluster id.", + ) + c.argument("aks_custom_headers") + + for scope in ["aks snapshot show", "aks snapshot delete"]: with self.argument_context(scope) as c: - c.argument('snapshot_name', options_list=[ - '--name', '-n'], required=True, help='The cluster snapshot name.', validator=validate_snapshot_name) - c.argument('yes', options_list=[ - '--yes', '-y'], help='Do not prompt for confirmation.', action='store_true') - - with self.argument_context('aks trustedaccess rolebinding') as c: - c.argument('cluster_name', help='The cluster name.') - - for scope in ['aks trustedaccess rolebinding show', 'aks trustedaccess rolebinding create', - 'aks trustedaccess rolebinding update', 'aks trustedaccess rolebinding delete']: + c.argument( + "snapshot_name", + options_list=["--name", "-n"], + required=True, + help="The cluster snapshot name.", + validator=validate_snapshot_name, + ) + c.argument( + "yes", + options_list=["--yes", "-y"], + help="Do not prompt for confirmation.", + action="store_true", + ) + + with self.argument_context("aks trustedaccess rolebinding") as c: + c.argument("cluster_name", help="The cluster name.") + + for scope in [ + "aks trustedaccess rolebinding show", + "aks trustedaccess rolebinding create", + "aks trustedaccess rolebinding update", + "aks trustedaccess rolebinding delete", + ]: with self.argument_context(scope) as c: - c.argument('role_binding_name', options_list=[ - '--name', '-n'], required=True, help='The role binding name.') - - with self.argument_context('aks trustedaccess rolebinding create') as c: - c.argument('roles', help='comma-separated roles: Microsoft.Demo/samples/reader,Microsoft.Demo/samples/writer,...') - c.argument('source_resource_id', options_list=['--source-resource-id', '-r', c.deprecate(target='-s', redirect='--source-resource-id', hide=True)], help='The source resource id of the binding') - - with self.argument_context('aks trustedaccess rolebinding update') as c: - c.argument('roles', help='comma-separated roles: Microsoft.Demo/samples/reader,Microsoft.Demo/samples/writer,...') - - with self.argument_context('aks mesh enable-ingress-gateway') as c: - c.argument('ingress_gateway_type', - arg_type=get_enum_type(ingress_gateway_types)) - - with self.argument_context('aks mesh disable-ingress-gateway') as c: - c.argument('ingress_gateway_type', - arg_type=get_enum_type(ingress_gateway_types)) - - with self.argument_context('aks mesh enable-egress-gateway') as c: - c.argument('egx_gtw_nodeselector', nargs='*', validator=validate_egress_gtw_nodeselector, required=False, default=None, - options_list=["--egress-gateway-nodeselector", "--egx-gtw-ns"]) - - with self.argument_context('aks mesh enable') as c: - c.argument('revision', validator=validate_azure_service_mesh_revision) - c.argument('key_vault_id') - c.argument('ca_cert_object_name') - c.argument('ca_key_object_name') - c.argument('root_cert_object_name') - c.argument('cert_chain_object_name') - - with self.argument_context('aks mesh get-revisions') as c: - c.argument('location', required=True, help='Location in which to discover available Azure Service Mesh revisions.') - - with self.argument_context('aks mesh upgrade start') as c: - c.argument('revision', validator=validate_azure_service_mesh_revision, required=True) - - with self.argument_context('aks approuting enable') as c: - c.argument('enable_kv', action='store_true') - c.argument('keyvault_id', options_list=[ - '--attach-kv']) - - with self.argument_context('aks approuting update') as c: - c.argument('keyvault_id', options_list=[ - '--attach-kv']) - c.argument('enable_kv', action='store_true') - - with self.argument_context('aks approuting zone add') as c: - c.argument('dns_zone_resource_ids', options_list=[ - '--ids'], required=True) - c.argument('attach_zones') - - with self.argument_context('aks approuting zone delete') as c: - c.argument('dns_zone_resource_ids', options_list=[ - '--ids'], required=True) - - with self.argument_context('aks approuting zone update') as c: - c.argument('dns_zone_resource_ids', options_list=[ - '--ids'], required=True) - c.argument('attach_zones') + c.argument( + "role_binding_name", + options_list=["--name", "-n"], + required=True, + help="The role binding name.", + ) + + with self.argument_context("aks trustedaccess rolebinding create") as c: + c.argument( + "roles", + help="comma-separated roles: Microsoft.Demo/samples/reader,Microsoft.Demo/samples/writer,...", + ) + c.argument( + "source_resource_id", + options_list=[ + "--source-resource-id", + "-r", + c.deprecate(target="-s", redirect="--source-resource-id", hide=True), + ], + help="The source resource id of the binding", + ) + + with self.argument_context("aks trustedaccess rolebinding update") as c: + c.argument( + "roles", + help="comma-separated roles: Microsoft.Demo/samples/reader,Microsoft.Demo/samples/writer,...", + ) + + with self.argument_context("aks mesh enable-ingress-gateway") as c: + c.argument( + "ingress_gateway_type", arg_type=get_enum_type(ingress_gateway_types) + ) + + with self.argument_context("aks mesh disable-ingress-gateway") as c: + c.argument( + "ingress_gateway_type", arg_type=get_enum_type(ingress_gateway_types) + ) + + with self.argument_context("aks mesh enable-egress-gateway") as c: + c.argument( + "egx_gtw_nodeselector", + nargs="*", + validator=validate_egress_gtw_nodeselector, + required=False, + default=None, + options_list=["--egress-gateway-nodeselector", "--egx-gtw-ns"], + ) + + with self.argument_context("aks mesh enable") as c: + c.argument("revision", validator=validate_azure_service_mesh_revision) + c.argument("key_vault_id") + c.argument("ca_cert_object_name") + c.argument("ca_key_object_name") + c.argument("root_cert_object_name") + c.argument("cert_chain_object_name") + + with self.argument_context("aks mesh get-revisions") as c: + c.argument( + "location", + required=True, + help="Location in which to discover available Azure Service Mesh revisions.", + ) + + with self.argument_context("aks mesh upgrade start") as c: + c.argument( + "revision", validator=validate_azure_service_mesh_revision, required=True + ) + + with self.argument_context("aks approuting enable") as c: + c.argument("enable_kv", action="store_true") + c.argument("keyvault_id", options_list=["--attach-kv"]) + + with self.argument_context("aks approuting update") as c: + c.argument("keyvault_id", options_list=["--attach-kv"]) + c.argument("enable_kv", action="store_true") + + with self.argument_context("aks approuting zone add") as c: + c.argument("dns_zone_resource_ids", options_list=["--ids"], required=True) + c.argument("attach_zones") + + with self.argument_context("aks approuting zone delete") as c: + c.argument("dns_zone_resource_ids", options_list=["--ids"], required=True) + + with self.argument_context("aks approuting zone update") as c: + c.argument("dns_zone_resource_ids", options_list=["--ids"], required=True) + c.argument("attach_zones") def _get_default_install_location(exe_name): system = platform.system() - if system == 'Windows': - home_dir = os.environ.get('USERPROFILE') + if system == "Windows": + home_dir = os.environ.get("USERPROFILE") if not home_dir: return None install_location = os.path.join( - home_dir, r'.azure-{0}\{0}.exe'.format(exe_name)) - elif system in ('Linux', 'Darwin'): - install_location = '/usr/local/bin/{}'.format(exe_name) + home_dir, f".azure-{exe_name}\\{exe_name}.exe" + ) + elif system in ("Linux", "Darwin"): + install_location = f"/usr/local/bin/{exe_name}" else: install_location = None return install_location diff --git a/src/aks-preview/azext_aks_preview/_podidentity.py b/src/aks-preview/azext_aks_preview/_podidentity.py index ec39ad3f7e0..da9ea60e1c6 100644 --- a/src/aks-preview/azext_aks_preview/_podidentity.py +++ b/src/aks-preview/azext_aks_preview/_podidentity.py @@ -62,7 +62,7 @@ def _fill_defaults_for_pod_identity_exceptions(pod_identity_exceptions): # which will be converted to `None` in response. This behavior will break the extension # when using 2021-10-01 version. As a workaround, we always back fill the empty dict value # before sending to the server side. - exc.pod_labels = dict() + exc.pod_labels = {} def _fill_defaults_for_pod_identity_profile(pod_identity_profile): @@ -115,8 +115,7 @@ def _ensure_managed_identity_operator_permission(cmd, instance, scope): elif instance.identity.type.lower() == 'systemassigned': cluster_identity_object_id = instance.identity.principal_id else: - raise CLIError('unsupported identity type: {}'.format( - instance.identity.type)) + raise CLIError(f"unsupported identity type: {instance.identity.type}") if cluster_identity_object_id is None: raise CLIError('unable to resolve cluster identity') @@ -126,7 +125,7 @@ def _ensure_managed_identity_operator_permission(cmd, instance, scope): scope = scope.lower() # list all assignments of the target identity (scope) that assigned to the cluster identity - filter_query = "atScope() and assignedTo('{}')".format(cluster_identity_object_id) + filter_query = f"atScope() and assignedTo('{cluster_identity_object_id}')" for i in assignments_client.list_for_scope(scope=scope, filter=filter_query): if not i.role_definition_id.lower().endswith(CONST_MANAGED_IDENTITY_OPERATOR_ROLE_ID): continue @@ -140,7 +139,7 @@ def _ensure_managed_identity_operator_permission(cmd, instance, scope): continue # already assigned - logger.debug('Managed Identity Opereator role has been assigned to {}'.format(i.scope)) + logger.debug('Managed Identity Opereator role has been assigned to %s', i.scope) return if not add_role_assignment(cmd, CONST_MANAGED_IDENTITY_OPERATOR_ROLE, cluster_identity_object_id, diff --git a/src/aks-preview/azext_aks_preview/_roleassignments.py b/src/aks-preview/azext_aks_preview/_roleassignments.py index 4edad68824a..b9aa28382a7 100644 --- a/src/aks-preview/azext_aks_preview/_roleassignments.py +++ b/src/aks-preview/azext_aks_preview/_roleassignments.py @@ -27,8 +27,7 @@ def add_role_assignment(cmd, role, service_principal_msi_id, is_service_principa from azure.cli.core import __version__ as core_version if core_version <= "2.45.0": return _add_role_assignment_old(cmd, role, service_principal_msi_id, is_service_principal, delay, scope) - else: - return _add_role_assignment_new(cmd, role, service_principal_msi_id, is_service_principal, delay, scope) + return _add_role_assignment_new(cmd, role, service_principal_msi_id, is_service_principal, delay, scope) # TODO(fuming): remove and replaced by import from azure.cli.command_modules.acs once dependency bumped to 2.47.0 diff --git a/src/aks-preview/azext_aks_preview/_validators.py b/src/aks-preview/azext_aks_preview/_validators.py index 060ce4c564c..c8bb1f8d1e4 100644 --- a/src/aks-preview/azext_aks_preview/_validators.py +++ b/src/aks-preview/azext_aks_preview/_validators.py @@ -11,8 +11,15 @@ from ipaddress import ip_network from math import isclose, isnan -import azure.cli.core.keys as keys -from azure.mgmt.containerservice.models import KubernetesSupportPlan +from azure.cli.core import keys +from azure.cli.core.azclierror import ( + ArgumentUsageError, + InvalidArgumentValueError, + MutuallyExclusiveArgumentError, + RequiredArgumentMissingError, +) +from azure.cli.core.commands.validators import validate_tag +from azure.cli.core.util import CLIError from azext_aks_preview._consts import ( ADDONS, CONST_LOAD_BALANCER_BACKEND_POOL_TYPE_NODE_IP, @@ -25,14 +32,6 @@ CONST_OS_SKU_MARINER, ) from azext_aks_preview._helpers import _fuzzy_match -from azure.cli.core.azclierror import ( - ArgumentUsageError, - InvalidArgumentValueError, - MutuallyExclusiveArgumentError, - RequiredArgumentMissingError, -) -from azure.cli.core.commands.validators import validate_tag -from azure.cli.core.util import CLIError from knack.log import get_logger logger = get_logger(__name__) @@ -46,7 +45,7 @@ def validate_ssh_key(namespace): content = string_or_file if os.path.exists(string_or_file): logger.info('Use existing SSH public key file: %s', string_or_file) - with open(string_or_file, 'r') as f: + with open(string_or_file, 'r', encoding="utf-8") as f: content = f.read() elif not keys.is_valid_ssh_rsa_public_key(content): if namespace.generate_ssh_keys: @@ -77,7 +76,7 @@ def validate_ssh_key_for_update(namespace): content = string_or_file if os.path.exists(string_or_file): logger.info('Use existing SSH public key file: %s', string_or_file) - with open(string_or_file, 'r') as f: + with open(string_or_file, 'r', encoding="utf-8") as f: content = f.read() elif not keys.is_valid_ssh_rsa_public_key(content): raise InvalidArgumentValueError('An RSA key file or key value must be supplied to SSH Key Value') @@ -159,8 +158,10 @@ def validate_ip_ranges(namespace): raise CLIError( "--api-server-authorized-ip-ranges cannot be IPv6 addresses") except ValueError: + # pylint: disable=raise-missing-from raise CLIError( - "--api-server-authorized-ip-ranges should be a list of IPv4 addresses or CIDRs") + "--api-server-authorized-ip-ranges should be a list of IPv4 addresses or CIDRs" + ) def _validate_nodepool_name(nodepool_name): @@ -208,7 +209,11 @@ 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, CONST_MANAGED_CLUSTER_SKU_TIER_PREMIUM): + 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") @@ -236,7 +241,7 @@ def validate_taint(taint): return found = regex.findall(taint) if not found: - raise ArgumentUsageError('Invalid node taint: %s' % taint) + raise ArgumentUsageError(f'Invalid node taint: {taint}') def validate_priority(namespace): @@ -244,8 +249,7 @@ def validate_priority(namespace): if namespace.priority is not None: if namespace.priority == '': return - if namespace.priority != "Spot" and \ - namespace.priority != "Regular": + if namespace.priority not in ("Spot", "Regular"): raise CLIError("--priority can only be Spot or Regular") @@ -254,10 +258,8 @@ def validate_eviction_policy(namespace): if namespace.eviction_policy is not None: if namespace.eviction_policy == '': return - if namespace.eviction_policy != "Delete" and \ - namespace.eviction_policy != "Deallocate": - raise CLIError( - "--eviction-policy can only be Delete or Deallocate") + if namespace.eviction_policy not in ("Delete", "Deallocate"): + raise CLIError("--eviction-policy can only be Delete or Deallocate") def validate_spot_max_price(namespace): @@ -319,10 +321,14 @@ def _validate_subnet_id(subnet_id, name): def validate_load_balancer_backend_pool_type(namespace): """validate load balancer backend pool type""" if namespace.load_balancer_backend_pool_type is not None: - if namespace.load_balancer_backend_pool_type not in [CONST_LOAD_BALANCER_BACKEND_POOL_TYPE_NODE_IP, - CONST_LOAD_BALANCER_BACKEND_POOL_TYPE_NODE_IPCONFIGURATION]: + if namespace.load_balancer_backend_pool_type not in [ + CONST_LOAD_BALANCER_BACKEND_POOL_TYPE_NODE_IP, + CONST_LOAD_BALANCER_BACKEND_POOL_TYPE_NODE_IPCONFIGURATION, + ]: raise InvalidArgumentValueError( - f"Invalid Load Balancer Backend Pool Type {namespace.load_balancer_backend_pool_type}, supported values are nodeIP and nodeIPConfiguration") + f"Invalid Load Balancer Backend Pool Type {namespace.load_balancer_backend_pool_type}, " + "supported values are nodeIP and nodeIPConfiguration" + ) def validate_nodepool_tags(ns): @@ -404,7 +410,8 @@ def validate_label(label): kv = label.split('=') if len(kv) != 2: raise CLIError( - "Invalid label: %s. Label definition must be of format name=value." % label) + f"Invalid label: {label}. Label definition must be of format name=value." + ) name_parts = kv[0].split('/') if len(name_parts) == 1: name = name_parts[0] @@ -412,34 +419,45 @@ def validate_label(label): prefix = name_parts[0] if not prefix or len(prefix) > 253: raise CLIError( - "Invalid label: %s. Label prefix can't be empty or more than 253 chars." % label) + f"Invalid label: {label}. Label prefix can't be empty or more than 253 chars." + ) if not prefix_regex.match(prefix): - raise CLIError("Invalid label: %s. Prefix part a DNS-1123 label must consist of lower case alphanumeric " - "characters or '-', and must start and end with an alphanumeric character" % label) + raise CLIError( + f"Invalid label: {label}. Prefix part a DNS-1123 label must consist of lower case alphanumeric " + "characters or '-', and must start and end with an alphanumeric character" + ) name = name_parts[1] else: - raise CLIError("Invalid label: %s. A qualified name must consist of alphanumeric characters, '-', '_' " - "or '.', and must start and end with an alphanumeric character (e.g. 'MyName', or " - "'my.name', or '123-abc') with an optional DNS subdomain prefix and '/' " - "(e.g. 'example.com/MyName')" % label) + raise CLIError( + f"Invalid label: {label}. A qualified name must consist of alphanumeric characters, '-', '_' " + "or '.', and must start and end with an alphanumeric character (e.g. 'MyName', or " + "'my.name', or '123-abc') with an optional DNS subdomain prefix and '/' " + "(e.g. 'example.com/MyName')" + ) # validate label name if not name or len(name) > 63: raise CLIError( - "Invalid label: %s. Label name can't be empty or more than 63 chars." % label) + f"Invalid label: {label}. Label name can't be empty or more than 63 chars." + ) if not name_regex.match(name): - raise CLIError("Invalid label: %s. A qualified name must consist of alphanumeric characters, '-', '_' " - "or '.', and must start and end with an alphanumeric character (e.g. 'MyName', or " - "'my.name', or '123-abc') with an optional DNS subdomain prefix and '/' (e.g. " - "'example.com/MyName')" % label) + raise CLIError( + f"Invalid label: {label}. A qualified name must consist of alphanumeric characters, '-', '_' " + "or '.', and must start and end with an alphanumeric character (e.g. 'MyName', or " + "'my.name', or '123-abc') with an optional DNS subdomain prefix and '/' (e.g. " + "'example.com/MyName')" + ) # validate label value if len(kv[1]) > 63: raise CLIError( - "Invalid label: %s. Label must be more than 63 chars." % label) + f"Invalid label: {label}. Label must be more than 63 chars." + ) if not value_regex.match(kv[1]): - raise CLIError("Invalid label: %s. A valid label must be an empty string or consist of alphanumeric " - "characters, '-', '_' or '.', and must start and end with an alphanumeric character" % label) + raise CLIError( + f"Invalid label: {label}. A valid label must be an empty string or consist of alphanumeric " + "characters, '-', '_' or '.', and must start and end with an alphanumeric character" + ) return {kv[0]: kv[1]} @@ -456,6 +474,7 @@ def validate_max_surge(namespace): if int(int_or_percent) < 0: raise CLIError("--max-surge must be positive") except ValueError: + # pylint: disable=raise-missing-from raise CLIError("--max-surge should be an int or percentage") @@ -621,8 +640,10 @@ def validate_crg_id(namespace): def validate_azure_keyvault_kms_key_id(namespace): key_id = namespace.azure_keyvault_kms_key_id if key_id: - err_msg = '--azure-keyvault-kms-key-id is not a valid Key Vault key ID. ' \ - 'See https://docs.microsoft.com/en-us/azure/key-vault/general/about-keys-secrets-certificates#vault-name-and-object-name' + err_msg = ( + "--azure-keyvault-kms-key-id is not a valid Key Vault key ID. " + "See https://docs.microsoft.com/en-us/azure/key-vault/general/about-keys-secrets-certificates#vault-name-and-object-name" # pylint: disable=line-too-long + ) https_prefix = "https://" if not key_id.startswith(https_prefix): @@ -678,7 +699,9 @@ def validate_defender_disable_and_enable_parameters(namespace): def validate_force_upgrade_disable_and_enable_parameters(namespace): if namespace.disable_force_upgrade and namespace.enable_force_upgrade: - raise MutuallyExclusiveArgumentError('Providing both --disable-force-upgrade and --enable-force-upgrade flags is invalid') + raise MutuallyExclusiveArgumentError( + 'Providing both --disable-force-upgrade and --enable-force-upgrade flags is invalid' + ) def sanitize_resource_id(resource_id): @@ -695,8 +718,18 @@ def validate_azuremonitorworkspaceresourceid(namespace): if resource_id is None: return resource_id = sanitize_resource_id(resource_id) - if (bool(re.match(r'/subscriptions/.*/resourcegroups/.*/providers/microsoft.monitor/accounts/.*', resource_id))) is False: - raise ArgumentUsageError("--azure-monitor-workspace-resource-id not in the correct format. It should match `/subscriptions//resourceGroups//providers/microsoft.monitor/accounts/`") + if ( + bool( + re.match( + r"/subscriptions/.*/resourcegroups/.*/providers/microsoft.monitor/accounts/.*", + resource_id, + ) + ) + ) is False: + raise ArgumentUsageError( + "--azure-monitor-workspace-resource-id not in the correct format. It should match " + "`/subscriptions//resourceGroups//providers/microsoft.monitor/accounts/`" # pylint: disable=line-too-long + ) def validate_grafanaresourceid(namespace): @@ -704,8 +737,18 @@ def validate_grafanaresourceid(namespace): if resource_id is None: return resource_id = sanitize_resource_id(resource_id) - if (bool(re.match(r'/subscriptions/.*/resourcegroups/.*/providers/microsoft.dashboard/grafana/.*', resource_id))) is False: - raise ArgumentUsageError("--grafana-resource-id not in the correct format. It should match `/subscriptions//resourceGroups//providers/microsoft.dashboard/grafana/`") + if ( + bool( + re.match( + r"/subscriptions/.*/resourcegroups/.*/providers/microsoft.dashboard/grafana/.*", + resource_id, + ) + ) + ) is False: + raise ArgumentUsageError( + "--grafana-resource-id not in the correct format. It should match " + "`/subscriptions//resourceGroups//providers/microsoft.dashboard/grafana/`" # pylint: disable=line-too-long + ) def validate_allowed_host_ports(namespace): @@ -722,7 +765,8 @@ def validate_allowed_host_ports(namespace): if found: continue raise InvalidArgumentValueError( - "--allowed-host-ports must be a comma-separated list of port ranges in the format of /" + "--allowed-host-ports must be a comma-separated list of port ranges " + "in the format of /" ) @@ -747,7 +791,9 @@ def validate_utc_offset(namespace): utc_offset_regex = re.compile(r'^[+-]\d{2}:\d{2}$') found = utc_offset_regex.findall(namespace.utc_offset) if not found: - raise InvalidArgumentValueError('--utc-offset must be in format: "+/-HH:mm". For example, "+05:30" and "-12:00".') + raise InvalidArgumentValueError( + '--utc-offset must be in format: "+/-HH:mm". For example, "+05:30" and "-12:00".' + ) def validate_start_date(namespace): diff --git a/src/aks-preview/azext_aks_preview/addonconfiguration.py b/src/aks-preview/azext_aks_preview/addonconfiguration.py index d55f53a653d..1538649a91c 100644 --- a/src/aks-preview/azext_aks_preview/addonconfiguration.py +++ b/src/aks-preview/azext_aks_preview/addonconfiguration.py @@ -3,7 +3,6 @@ # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- -import json from knack.log import get_logger from knack.util import CLIError from azure.cli.core.azclierror import ArgumentUsageError @@ -42,29 +41,32 @@ logger = get_logger(__name__) -def enable_addons(cmd, - client, - resource_group_name, - name, - addons, - check_enabled=True, - workspace_resource_id=None, - subnet_name=None, - appgw_name=None, - appgw_subnet_prefix=None, - appgw_subnet_cidr=None, - appgw_id=None, - appgw_subnet_id=None, - appgw_watch_namespace=None, - enable_sgxquotehelper=False, - enable_secret_rotation=False, - rotation_poll_interval=None, - no_wait=False, - dns_zone_resource_id=None, - dns_zone_resource_ids=None, - enable_msi_auth_for_monitoring=True, - enable_syslog=False, - data_collection_settings=None): +# pylint: disable=too-many-locals +def enable_addons( + cmd, + client, + resource_group_name, + name, + addons, + check_enabled=True, + workspace_resource_id=None, + subnet_name=None, + appgw_name=None, + appgw_subnet_prefix=None, + appgw_subnet_cidr=None, + appgw_id=None, + appgw_subnet_id=None, + appgw_watch_namespace=None, + enable_sgxquotehelper=False, + enable_secret_rotation=False, + rotation_poll_interval=None, + no_wait=False, + dns_zone_resource_id=None, + dns_zone_resource_ids=None, + enable_msi_auth_for_monitoring=True, + enable_syslog=False, + data_collection_settings=None +): instance = client.get(resource_group_name, name) # this is overwritten by _update_addons(), so the value needs to be recorded here msi_auth = False @@ -74,18 +76,33 @@ def enable_addons(cmd, enable_msi_auth_for_monitoring = False subscription_id = get_subscription_id(cmd.cli_ctx) - instance = update_addons(cmd, instance, subscription_id, resource_group_name, name, addons, enable=True, - check_enabled=check_enabled, - workspace_resource_id=workspace_resource_id, - enable_msi_auth_for_monitoring=enable_msi_auth_for_monitoring, subnet_name=subnet_name, - appgw_name=appgw_name, appgw_subnet_prefix=appgw_subnet_prefix, - appgw_subnet_cidr=appgw_subnet_cidr, appgw_id=appgw_id, appgw_subnet_id=appgw_subnet_id, - appgw_watch_namespace=appgw_watch_namespace, - enable_sgxquotehelper=enable_sgxquotehelper, - enable_secret_rotation=enable_secret_rotation, rotation_poll_interval=rotation_poll_interval, no_wait=no_wait, - dns_zone_resource_id=dns_zone_resource_id, dns_zone_resource_ids=dns_zone_resource_ids, - enable_syslog=enable_syslog, - data_collection_settings=data_collection_settings) + instance = update_addons( + cmd, + instance, + subscription_id, + resource_group_name, + name, + addons, + enable=True, + check_enabled=check_enabled, + workspace_resource_id=workspace_resource_id, + enable_msi_auth_for_monitoring=enable_msi_auth_for_monitoring, + subnet_name=subnet_name, + appgw_name=appgw_name, + appgw_subnet_prefix=appgw_subnet_prefix, + appgw_subnet_cidr=appgw_subnet_cidr, + appgw_id=appgw_id, + appgw_subnet_id=appgw_subnet_id, + appgw_watch_namespace=appgw_watch_namespace, + enable_sgxquotehelper=enable_sgxquotehelper, + enable_secret_rotation=enable_secret_rotation, + rotation_poll_interval=rotation_poll_interval, + no_wait=no_wait, + dns_zone_resource_id=dns_zone_resource_id, + dns_zone_resource_ids=dns_zone_resource_ids, + enable_syslog=enable_syslog, + data_collection_settings=data_collection_settings, + ) if CONST_MONITORING_ADDON_NAME in instance.addon_profiles and instance.addon_profiles[ CONST_MONITORING_ADDON_NAME].enabled: @@ -95,21 +112,20 @@ def enable_addons(cmd, if not msi_auth: raise ArgumentUsageError( "--enable-msi-auth-for-monitoring can not be used on clusters with service principal auth.") - else: - # create a Data Collection Rule (DCR) and associate it with the cluster - ensure_container_insights_for_monitoring( - cmd, - instance.addon_profiles[CONST_MONITORING_ADDON_NAME], - subscription_id, - resource_group_name, - name, - instance.location, - aad_route=True, - create_dcr=True, - create_dcra=True, - enable_syslog=enable_syslog, - data_collection_settings=data_collection_settings - ) + # create a Data Collection Rule (DCR) and associate it with the cluster + ensure_container_insights_for_monitoring( + cmd, + instance.addon_profiles[CONST_MONITORING_ADDON_NAME], + subscription_id, + resource_group_name, + name, + instance.location, + aad_route=True, + create_dcr=True, + create_dcra=True, + enable_syslog=enable_syslog, + data_collection_settings=data_collection_settings + ) else: # monitoring addon will use legacy path if enable_syslog: @@ -163,31 +179,34 @@ def enable_addons(cmd, return result -def update_addons(cmd, # pylint: disable=too-many-branches,too-many-statements - instance, - subscription_id, - resource_group_name, - name, - addons, - enable, - check_enabled=True, - workspace_resource_id=None, - enable_msi_auth_for_monitoring=True, - subnet_name=None, - appgw_name=None, - appgw_subnet_prefix=None, - appgw_subnet_cidr=None, - appgw_id=None, - appgw_subnet_id=None, - appgw_watch_namespace=None, - enable_sgxquotehelper=False, - enable_secret_rotation=False, - rotation_poll_interval=None, - dns_zone_resource_id=None, - dns_zone_resource_ids=None, - no_wait=False, # pylint: disable=unused-argument - enable_syslog=False, - data_collection_settings=None): +# pylint: disable=too-many-locals, too-many-branches, too-many-statements +def update_addons( + cmd, + instance, + subscription_id, + resource_group_name, + name, + addons, + enable, + check_enabled=True, + workspace_resource_id=None, + enable_msi_auth_for_monitoring=True, + subnet_name=None, + appgw_name=None, + appgw_subnet_prefix=None, + appgw_subnet_cidr=None, + appgw_id=None, + appgw_subnet_id=None, + appgw_watch_namespace=None, + enable_sgxquotehelper=False, + enable_secret_rotation=False, + rotation_poll_interval=None, + dns_zone_resource_id=None, + dns_zone_resource_ids=None, + no_wait=False, # pylint: disable=unused-argument + enable_syslog=False, # pylint: disable=unused-argument + data_collection_settings=None, # pylint: disable=unused-argument +): # parse the comma-separated addons argument addon_args = addons.split(',') @@ -242,7 +261,7 @@ def update_addons(cmd, # pylint: disable=too-many-branches,too-many-statements continue if addon_arg not in ADDONS: - raise CLIError("Invalid addon name: {}.".format(addon_arg)) + raise CLIError(f"Invalid addon name: {addon_arg}.") addon = ADDONS[addon_arg] if addon == CONST_VIRTUAL_NODE_ADDON_NAME: # only linux is supported for now, in the future this will be a user flag @@ -274,13 +293,22 @@ def update_addons(cmd, # pylint: disable=too-many-branches,too-many-statements cloud_name = cmd.cli_ctx.cloud.name if enable_msi_auth_for_monitoring and (cloud_name.lower() == 'ussec' or cloud_name.lower() == 'usnat'): - if instance.identity is not None and instance.identity.type is not None and instance.identity.type == "userassigned": - logger.warning("--enable_msi_auth_for_monitoring is not supported in %s cloud and continuing monitoring enablement without this flag.", cloud_name) + if ( + instance.identity is not None and + instance.identity.type is not None and + instance.identity.type == "userassigned" + ): + logger.warning( + "--enable_msi_auth_for_monitoring is not supported in %s cloud and continuing " + "monitoring enablement without this flag.", cloud_name + ) enable_msi_auth_for_monitoring = False addon_profile.config = { logAnalyticsConstName: workspace_resource_id} - addon_profile.config[CONST_MONITORING_USING_AAD_MSI_AUTH] = "true" if enable_msi_auth_for_monitoring else "false" + addon_profile.config[CONST_MONITORING_USING_AAD_MSI_AUTH] = ( + "true" if enable_msi_auth_for_monitoring else "false" + ) elif addon == (CONST_VIRTUAL_NODE_ADDON_NAME + os_type): if addon_profile.enabled and check_enabled: raise CLIError('The virtual-node addon is already enabled for this managed cluster.\n' @@ -333,10 +361,11 @@ def update_addons(cmd, # pylint: disable=too-many-branches,too-many-statements elif addon == CONST_AZURE_KEYVAULT_SECRETS_PROVIDER_ADDON_NAME: if addon_profile.enabled and check_enabled: raise CLIError( - 'The azure-keyvault-secrets-provider addon is already enabled for this managed cluster.\n' - 'To change azure-keyvault-secrets-provider configuration, run ' - f'"az aks disable-addons -a azure-keyvault-secrets-provider -n {name} -g {resource_group_name}" ' - 'before enabling it again.') + "The azure-keyvault-secrets-provider addon is already enabled for this managed cluster.\n" + "To change azure-keyvault-secrets-provider configuration, run " + '"az aks disable-addons -a azure-keyvault-secrets-provider ' + f'-n {name} -g {resource_group_name}" before enabling it again.' + ) addon_profile = ManagedClusterAddonProfile( enabled=True, config={CONST_SECRET_ROTATION_ENABLED: "false", CONST_ROTATION_POLL_INTERVAL: "2m"}) if enable_secret_rotation: @@ -352,7 +381,8 @@ def update_addons(cmd, # pylint: disable=too-many-branches,too-many-statements enabled=False) else: raise CLIError( - "The addon {} is not installed.".format(addon)) + f"The addon {addon} is not installed." + ) addon_profiles[addon].config = None addon_profiles[addon].enabled = enable diff --git a/src/aks-preview/azext_aks_preview/agentpool_decorator.py b/src/aks-preview/azext_aks_preview/agentpool_decorator.py index fb5b1c029c1..d50f08f93ba 100644 --- a/src/aks-preview/azext_aks_preview/agentpool_decorator.py +++ b/src/aks-preview/azext_aks_preview/agentpool_decorator.py @@ -32,9 +32,7 @@ CONST_VIRTUAL_MACHINE_SCALE_SETS, CONST_AVAILABILITY_SET, CONST_VIRTUAL_MACHINES, - CONST_OS_SKU_UBUNTU, ) -from azext_aks_preview._params import node_os_skus_update from azext_aks_preview._helpers import get_nodepool_snapshot_by_snapshot_id logger = get_logger(__name__) @@ -98,7 +96,9 @@ def get_vm_set_type(self) -> str: elif vm_set_type.lower() == CONST_VIRTUAL_MACHINES.lower(): vm_set_type = CONST_VIRTUAL_MACHINES else: - raise InvalidArgumentValueError("--vm-set-type can only be VirtualMachineScaleSets, AvailabilitySet or VirtualMachines(Preview)") + raise InvalidArgumentValueError( + "--vm-set-type can only be VirtualMachineScaleSets, AvailabilitySet or VirtualMachines(Preview)" + ) # this parameter does not need validation return vm_set_type @@ -132,9 +132,7 @@ def get_message_of_the_day(self) -> Union[str, None]: if message_of_the_day_file_path: if not os.path.isfile(message_of_the_day_file_path): raise InvalidArgumentValueError( - "{} is not valid file, or not accessable.".format( - message_of_the_day_file_path - ) + f"{message_of_the_day_file_path} is not valid file, or not accessable." ) message_of_the_day = read_file_content( message_of_the_day_file_path) @@ -507,7 +505,7 @@ def set_up_agentpool_windows_profile(self, agentpool: AgentPool) -> AgentPool: # Construct AgentPoolWindowsProfile if one of the fields has been set if disable_windows_outbound_nat: - agentpool.windows_profile = self.models.AgentPoolWindowsProfile( + agentpool.windows_profile = self.models.AgentPoolWindowsProfile( # pylint: disable=no-member disable_outbound_nat=disable_windows_outbound_nat ) @@ -518,7 +516,7 @@ def set_up_agentpool_network_profile(self, agentpool: AgentPool) -> AgentPool: asg_ids = self.context.get_asg_ids() allowed_host_ports = self.context.get_allowed_host_ports() - agentpool.network_profile = self.models.AgentPoolNetworkProfile() + agentpool.network_profile = self.models.AgentPoolNetworkProfile() # pylint: disable=no-member if allowed_host_ports is not None: agentpool.network_profile.allowed_host_ports = allowed_host_ports agentpool.network_profile.application_security_groups = asg_ids @@ -544,7 +542,9 @@ def set_up_artifact_streaming(self, agentpool: AgentPool) -> AgentPool: if self.context.get_enable_artifact_streaming(): if agentpool.artifact_streaming_profile is None: - agentpool.artifact_streaming_profile = self.models.AgentPoolArtifactStreamingProfile() + agentpool.artifact_streaming_profile = ( + self.models.AgentPoolArtifactStreamingProfile() # pylint: disable=no-member + ) agentpool.artifact_streaming_profile.enabled = True return agentpool @@ -584,7 +584,7 @@ def set_up_upgrade_settings(self, agentpool: AgentPool) -> AgentPool: """ self._ensure_agentpool(agentpool) - upgrade_settings = self.models.AgentPoolUpgradeSettings() + upgrade_settings = self.models.AgentPoolUpgradeSettings() # pylint: disable=no-member max_surge = self.context.get_max_surge() if max_surge: upgrade_settings.max_surge = max_surge @@ -654,7 +654,7 @@ def update_network_profile(self, agentpool: AgentPool) -> AgentPool: asg_ids = self.context.get_asg_ids() allowed_host_ports = self.context.get_allowed_host_ports() if not agentpool.network_profile and (asg_ids or allowed_host_ports): - agentpool.network_profile = self.models.AgentPoolNetworkProfile() + agentpool.network_profile = self.models.AgentPoolNetworkProfile() # pylint: disable=no-member if asg_ids is not None: agentpool.network_profile.application_security_groups = asg_ids if allowed_host_ports is not None: @@ -669,7 +669,7 @@ def update_artifact_streaming(self, agentpool: AgentPool) -> AgentPool: if self.context.get_enable_artifact_streaming(): if agentpool.artifact_streaming_profile is None: - agentpool.artifact_streaming_profile = self.models.AgentPoolArtifactStreamingProfile() + agentpool.artifact_streaming_profile = self.models.AgentPoolArtifactStreamingProfile() # pylint: disable=no-member agentpool.artifact_streaming_profile.enabled = True return agentpool @@ -714,7 +714,7 @@ def update_upgrade_settings(self, agentpool: AgentPool) -> AgentPool: upgrade_settings = agentpool.upgrade_settings if upgrade_settings is None: - upgrade_settings = self.models.AgentPoolUpgradeSettings() + upgrade_settings = self.models.AgentPoolUpgradeSettings() # pylint: disable=no-member max_surge = self.context.get_max_surge() if max_surge: diff --git a/src/aks-preview/azext_aks_preview/aks_diagnostics.py b/src/aks-preview/azext_aks_preview/aks_diagnostics.py index 6328e42c02b..95b81e70fd7 100644 --- a/src/aks-preview/azext_aks_preview/aks_diagnostics.py +++ b/src/aks-preview/azext_aks_preview/aks_diagnostics.py @@ -3,37 +3,37 @@ # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- -import colorama import datetime import json import os import subprocess import tempfile import time - -from azure.cli.core.commands.client_factory import get_mgmt_service_client, get_subscription_id -from azure.cli.command_modules.acs.custom import k8s_install_kubelogin -from azure.cli.command_modules.acs._params import _get_default_install_location from enum import Flag, auto -from knack.log import get_logger -from knack.prompting import prompt_y_n -from knack.util import CLIError -from msrestazure.azure_exceptions import CloudError -from packaging import version -from tabulate import tabulate +import colorama from azext_aks_preview._client_factory import cf_agent_pools, get_storage_client - from azext_aks_preview._consts import ( CONST_CONTAINER_NAME_MAX_LENGTH, - CONST_PERISCOPE_REPO_ORG, CONST_PERISCOPE_CONTAINER_REGISTRY, - CONST_PERISCOPE_RELEASE_TAG, CONST_PERISCOPE_IMAGE_VERSION, CONST_PERISCOPE_NAMESPACE, + CONST_PERISCOPE_RELEASE_TAG, + CONST_PERISCOPE_REPO_ORG, ) - -from azext_aks_preview._helpers import which, print_or_merge_credentials +from azext_aks_preview._helpers import print_or_merge_credentials, which +from azure.cli.command_modules.acs._params import _get_default_install_location +from azure.cli.command_modules.acs.custom import k8s_install_kubelogin +from azure.cli.core.commands.client_factory import ( + get_mgmt_service_client, + get_subscription_id, +) +from knack.log import get_logger +from knack.prompting import prompt_y_n +from knack.util import CLIError +from msrestazure.azure_exceptions import CloudError +from packaging import version +from tabulate import tabulate logger = get_logger(__name__) @@ -87,9 +87,9 @@ def aks_kollect_cmd(cmd, # pylint: disable=too-many-statements,too-many-local try: parsed_storage_account = parse_resource_id(storage_account_id) except CloudError as ex: - raise CLIError(ex.message) + raise CLIError(ex.message) # pylint: disable=raise-missing-from else: - raise CLIError("Invalid storage account id %s" % storage_account_id) + raise CLIError(f"Invalid storage account id {storage_account_id}") storage_account_name = parsed_storage_account['name'] @@ -133,11 +133,11 @@ def aks_kollect_cmd(cmd, # pylint: disable=too-many-statements,too-many-local return print() - print("Getting credentials for cluster %s " % name) + print(f"Getting credentials for cluster {name}") temp_kubeconfig_path = _get_temp_kubeconfig_path(cmd, client, resource_group_name, name, mc.aad_profile is not None) print() - print("Starts collecting diag info for cluster %s " % name) + print(f"Starts collecting diag info for cluster {name}") # Base the container name on the fqdn (or private fqdn) of the managed cluster container_name = _generate_container_name(mc.fqdn, mc.private_fqdn) @@ -193,7 +193,7 @@ def aks_kollect_cmd(cmd, # pylint: disable=too-many-statements,too-many-local subprocess.check_output(["kubectl", "--kubeconfig", temp_kubeconfig_path, "apply", "-k", kustomize_folder, "-n", CONST_PERISCOPE_NAMESPACE], stderr=subprocess.STDOUT) except subprocess.CalledProcessError as err: - raise CLIError(err.output) + raise CLIError(err.output) # pylint: disable=raise-missing-from finally: os.remove(kustomize_file_path) os.rmdir(kustomize_folder) @@ -322,9 +322,10 @@ def _get_storage_account_from_diag_settings(cli_ctx, resource_group_name, name): diag_settings_client = get_mgmt_service_client( cli_ctx, MonitorManagementClient).diagnostic_settings subscription_id = get_subscription_id(cli_ctx) - aks_resource_id = '/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.ContainerService' \ - '/managedClusters/{2}'.format(subscription_id, - resource_group_name, name) + aks_resource_id = ( + f"/subscriptions/{subscription_id}/resourceGroups/{resource_group_name}/providers/" + f"Microsoft.ContainerService/managedClusters/{name}" + ) diag_settings = diag_settings_client.list(aks_resource_id) for _, diag_setting in enumerate(diag_settings): if diag_setting: @@ -374,7 +375,7 @@ def _is_windows_hpc_supported(agent_pools): # The full (major.minor.patch) version *may* be stored in currentOrchestratorVersion. # If not, it'll be in orchestratorVersion. windows_k8s_versions = [p.current_orchestrator_version or p.orchestrator_version for p in agent_pools if p.os_type.casefold() == "Windows".casefold()] - return all([version.parse(v) >= version.parse("1.23.0") for v in windows_k8s_versions]) + return all((version.parse(v) >= version.parse("1.23.0") for v in windows_k8s_versions)) def _display_diagnostics_report(temp_kubeconfig_path): # pylint: disable=too-many-statements @@ -420,17 +421,15 @@ def _display_diagnostics_report(temp_kubeconfig_path): # pylint: disable=too-m if apd_lines and 'No resources found' in apd_lines[0]: apd_lines.pop(0) - print("Got {} diagnostic results for {} ready nodes{}\r".format(len(apd_lines), - len(ready_nodes), - '.' * retry), end='') + print(f"Got {len(apd_lines)} diagnostic results for {len(ready_nodes)} ready nodes{'.' * retry}\r", end='') if len(apd_lines) < len(ready_nodes): time.sleep(3) else: apds_created = True print() else: - for node_name in ready_nodes: - if ready_nodes[node_name]: + for node_name, node_ready in ready_nodes.items(): + if node_ready: continue apdName = "aks-periscope-diagnostic-" + node_name try: @@ -450,8 +449,10 @@ def _display_diagnostics_report(temp_kubeconfig_path): # pylint: disable=too-m node_name, network_status) if not network_config or not network_status: - print("The diagnostics information for node {} is not ready yet. " - "Will try again in 10 seconds.".format(node_name)) + print( + f"The diagnostics information for node {node_name} is not ready yet. " + "Will try again in 10 seconds." + ) time.sleep(10) break @@ -462,7 +463,7 @@ def _display_diagnostics_report(temp_kubeconfig_path): # pylint: disable=too-m network_status_object) ready_nodes[node_name] = True except subprocess.CalledProcessError as err: - raise CLIError(err.output) + raise CLIError(err.output) # pylint: disable=raise-missing-from print() if network_config_array: diff --git a/src/aks-preview/azext_aks_preview/aks_draft/commands.py b/src/aks-preview/azext_aks_preview/aks_draft/commands.py index 7df5c322201..18d53461716 100644 --- a/src/aks-preview/azext_aks_preview/aks_draft/commands.py +++ b/src/aks-preview/azext_aks_preview/aks_draft/commands.py @@ -4,19 +4,16 @@ # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- -import json -from posixpath import dirname -from typing import Dict, List, Optional, Tuple -import subprocess -import requests +import logging import os import platform +import subprocess from pathlib import Path +from typing import Dict, List, Optional, Tuple + +import requests +from azext_aks_preview._consts import CONST_DRAFT_CLI_VERSION from knack.prompting import prompt_y_n -import logging -from azext_aks_preview._consts import ( - CONST_DRAFT_CLI_VERSION -) # `az aks draft create` function @@ -147,10 +144,10 @@ def _run(binary_path: str, command: str, arguments: List[str]) -> bool: if binary_path is None: raise ValueError('The given Binary path was null or empty') - logging.info(f'Running `az aks draft {command}`') + logging.info("Running `az aks draft %s`", command) cmd = [binary_path, command] + arguments - process = subprocess.Popen(cmd) - exit_code = process.wait() + with subprocess.Popen(cmd) as process: + exit_code = process.wait() return exit_code == 0 @@ -189,25 +186,23 @@ def _binary_pre_check(download_path: str) -> Optional[str]: if response: return _download_binary() return draft_binary_path - else: # prompt the user to download binary - # If users says no, we error out and tell them that this requires the binary - msg = 'The required binary was not found. Would you like us to download the required binary for you?' - - if not prompt_y_n(msg, default='n'): - raise ValueError('`az aks draft` requires the missing dependency') - - return _download_binary() + # prompt the user to download binary + # If users says no, we error out and tell them that this requires the binary + msg = 'The required binary was not found. Would you like us to download the required binary for you?' + if not prompt_y_n(msg, default='n'): + raise ValueError('`az aks draft` requires the missing dependency') + return _download_binary() # Returns True if the local binary is the latest version, False otherwise def _is_latest_version(binary_path: str) -> bool: latest_version = CONST_DRAFT_CLI_VERSION - process = subprocess.Popen([binary_path, 'version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stdout, stderr = process.communicate() + with subprocess.Popen([binary_path, 'version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) as process: + stdout, stderr = process.communicate() if stderr.decode(): return False # return string of result is "version: v0.0.x" - current_version = stdout.decode().split('\n')[0].strip().split()[-1] + current_version = stdout.decode().split('\n', maxsplit=1)[0].strip().split()[-1] return latest_version == current_version @@ -220,7 +215,9 @@ def _get_filename() -> Optional[str]: if architecture == 'x86_64': architecture = 'amd64' if architecture not in ['arm64', 'amd64']: - logging.error('Cannot find a suitable download for the current system architecture. Draft only supports AMD64 and ARM64.') + logging.error( + "Cannot find a suitable download for the current system architecture. Draft only supports AMD64 and ARM64." + ) return None file_suffix = ".exe" if operating_system == "windows" else "" @@ -243,7 +240,7 @@ def _get_existing_path() -> Optional[str]: for path in paths: binary_file_path = path + '/' + filename if os.path.exists(binary_file_path): - logging.info('Existing binary found at: ' + binary_file_path) + logging.info("Existing binary found at: %s", binary_file_path) return binary_file_path return None @@ -277,15 +274,15 @@ def _download_binary(download_path: str = '~/.aksdraft') -> Optional[str]: # Directory if os.path.exists(download_path) is False: Path(download_path).mkdir(parents=True, exist_ok=True) - logging.info(f'Directory {download_path} was created inside of your HOME directory') + logging.info("Directory %s was created inside of your HOME directory", download_path) full_path = f'{download_path}/{filename}' # Writing the file to the local file system with open(full_path, 'wb') as output_file: output_file.write(response.content) - logging.info(f'Download of Draft binary was successful with a status code: {response.status_code}') + logging.info("Download of Draft binary was successful with a status code: %s", response.status_code) os.chmod(full_path, 0o755) return full_path - logging.error(f'Download of Draft binary was unsuccessful with a status code: {response.status_code}') + logging.error("Download of Draft binary was unsuccessful with a status code: %s", response.status_code) return None diff --git a/src/aks-preview/azext_aks_preview/commands.py b/src/aks-preview/azext_aks_preview/commands.py index 125e2914eb7..213c18539aa 100644 --- a/src/aks-preview/azext_aks_preview/commands.py +++ b/src/aks-preview/azext_aks_preview/commands.py @@ -13,7 +13,7 @@ cf_nodepool_snapshots, cf_trustedaccess_role, cf_trustedaccess_role_binding, - cf_machines + cf_machines, ) from azext_aks_preview._format import ( aks_addon_list_available_table_format, @@ -50,7 +50,7 @@ def transform_mc_objects_with_custom_cas(result): def _patch_custom_cas_in_security_profile(security_profile): # modify custom_ca_trust_certificates in-place # security_profile shouldn't be None - custom_cas = getattr(security_profile, 'custom_ca_trust_certificates', None) + custom_cas = getattr(security_profile, "custom_ca_trust_certificates", None) if custom_cas: decoded_custom_cas = [] for custom_ca in custom_cas: @@ -71,275 +71,347 @@ def _patch_custom_cas_in_security_profile(security_profile): result = [result] for r in result: - if getattr(r, 'security_profile', None): + if getattr(r, "security_profile", None): # security_profile shouldn't be None _patch_custom_cas_in_security_profile(r.security_profile) return result[0] if singular else result +# pylint: disable=too-many-statements def load_command_table(self, _): - managed_clusters_sdk = CliCommandType( - operations_tmpl='azext_aks_preview.vendored_sdks.azure_mgmt_preview_aks.' - 'operations._managed_clusters_operations#ManagedClustersOperations.{}', - operation_group='managed_clusters', - client_factory=cf_managed_clusters + operations_tmpl="azext_aks_preview.vendored_sdks.azure_mgmt_preview_aks." + "operations._managed_clusters_operations#ManagedClustersOperations.{}", + operation_group="managed_clusters", + client_factory=cf_managed_clusters, ) agent_pools_sdk = CliCommandType( - operations_tmpl='azext_aks_preview.vendored_sdks.azure_mgmt_preview_aks.' - 'operations._agent_pools_operations#AgentPoolsOperations.{}', - client_factory=cf_managed_clusters + operations_tmpl="azext_aks_preview.vendored_sdks.azure_mgmt_preview_aks." + "operations._agent_pools_operations#AgentPoolsOperations.{}", + client_factory=cf_managed_clusters, ) machines_sdk = CliCommandType( - operations_tmpl='azext_aks_preview.vendored_sdks.azure_mgmt_preview_aks.' - 'operations._machine_operations#MachinesOperations.{}', - client_factory=cf_managed_clusters + operations_tmpl="azext_aks_preview.vendored_sdks.azure_mgmt_preview_aks." + "operations._machine_operations#MachinesOperations.{}", + client_factory=cf_managed_clusters, ) maintenance_configuration_sdk = CliCommandType( - operations_tmpl='azext_aks_preview.vendored_sdks.azure_mgmt_preview_aks.' - 'operations._maintenance_configurations_operations#MaintenanceConfigurationsOperations.{}', - client_factory=cf_maintenance_configurations + operations_tmpl="azext_aks_preview.vendored_sdks.azure_mgmt_preview_aks." + "operations._maintenance_configurations_operations#MaintenanceConfigurationsOperations.{}", + client_factory=cf_maintenance_configurations, ) nodepool_snapshot_sdk = CliCommandType( - operations_tmpl='azext_aks_preview.vendored_sdks.azure_mgmt_preview_aks.' - 'operations._snapshots_operations#SnapshotsOperations.{}', - client_factory=cf_nodepool_snapshots + operations_tmpl="azext_aks_preview.vendored_sdks.azure_mgmt_preview_aks." + "operations._snapshots_operations#SnapshotsOperations.{}", + client_factory=cf_nodepool_snapshots, ) mc_snapshot_sdk = CliCommandType( - operations_tmpl='azext_aks_preview.vendored_sdks.azure_mgmt_preview_aks.' - 'operations._managed_clusters_snapshots_operations#ManagedClusterSnapshotsOperations.{}', - client_factory=cf_mc_snapshots + operations_tmpl="azext_aks_preview.vendored_sdks.azure_mgmt_preview_aks." + "operations._managed_clusters_snapshots_operations#ManagedClusterSnapshotsOperations.{}", + client_factory=cf_mc_snapshots, ) trustedaccess_role_sdk = CliCommandType( - operations_tmpl='azext_aks_preview.vendored_sdks.azure_mgmt_preview_aks.' - 'operations._trusted_access_roles_operations#TrustedAccessRolesOperations.{}', - client_factory=cf_trustedaccess_role + operations_tmpl="azext_aks_preview.vendored_sdks.azure_mgmt_preview_aks." + "operations._trusted_access_roles_operations#TrustedAccessRolesOperations.{}", + client_factory=cf_trustedaccess_role, ) trustedaccess_role_binding_sdk = CliCommandType( - operations_tmpl='azext_aks_preview.vendored_sdks.azure_mgmt_preview_aks.' - 'operations._trusted_access_role_bindings_operations#TrustedAccessRoleBindingsOperations.{}', - client_factory=cf_trustedaccess_role_binding + operations_tmpl="azext_aks_preview.vendored_sdks.azure_mgmt_preview_aks." + "operations._trusted_access_role_bindings_operations#TrustedAccessRoleBindingsOperations.{}", + client_factory=cf_trustedaccess_role_binding, ) # AKS managed cluster commands - with self.command_group('aks', managed_clusters_sdk, client_factory=cf_managed_clusters, - transform=transform_mc_objects_with_custom_cas) as g: - g.custom_command('browse', 'aks_browse') - g.custom_command('create', 'aks_create', supports_no_wait=True) - g.custom_command('update', 'aks_update', supports_no_wait=True) - g.command('get-upgrades', 'get_upgrade_profile', table_transformer=aks_upgrades_table_format) - g.custom_command('upgrade', 'aks_upgrade', supports_no_wait=True) - g.custom_command('scale', 'aks_scale', supports_no_wait=True) - g.command('delete', 'begin_delete', supports_no_wait=True, confirmation=True) - g.custom_show_command('show', 'aks_show', table_transformer=aks_show_table_format) - g.custom_command('list', 'aks_list', table_transformer=aks_list_table_format) - g.custom_command('enable-addons', 'aks_enable_addons', supports_no_wait=True) - g.custom_command('disable-addons', 'aks_disable_addons', supports_no_wait=True) - g.custom_command('get-credentials', 'aks_get_credentials') - g.custom_command('rotate-certs', 'aks_rotate_certs', supports_no_wait=True, - confirmation='Kubernetes will be unavailable during certificate rotation process.\n' + - 'Are you sure you want to perform this operation?') - g.custom_command('stop', 'aks_stop', supports_no_wait=True) - g.command('start', 'begin_start', supports_no_wait=True) - g.wait_command('wait') - g.custom_command('get-versions', 'aks_get_versions', table_transformer=aks_versions_table_format) + with self.command_group( + "aks", + managed_clusters_sdk, + client_factory=cf_managed_clusters, + transform=transform_mc_objects_with_custom_cas, + ) as g: + g.custom_command("browse", "aks_browse") + g.custom_command("create", "aks_create", supports_no_wait=True) + g.custom_command("update", "aks_update", supports_no_wait=True) + g.command( + "get-upgrades", + "get_upgrade_profile", + table_transformer=aks_upgrades_table_format, + ) + g.custom_command("upgrade", "aks_upgrade", supports_no_wait=True) + g.custom_command("scale", "aks_scale", supports_no_wait=True) + g.command("delete", "begin_delete", supports_no_wait=True, confirmation=True) + g.custom_show_command( + "show", "aks_show", table_transformer=aks_show_table_format + ) + g.custom_command("list", "aks_list", table_transformer=aks_list_table_format) + g.custom_command("enable-addons", "aks_enable_addons", supports_no_wait=True) + g.custom_command("disable-addons", "aks_disable_addons", supports_no_wait=True) + g.custom_command("get-credentials", "aks_get_credentials") + g.custom_command( + "rotate-certs", + "aks_rotate_certs", + supports_no_wait=True, + confirmation="Kubernetes will be unavailable during certificate rotation process.\n" + + "Are you sure you want to perform this operation?", + ) + g.custom_command("stop", "aks_stop", supports_no_wait=True) + g.command("start", "begin_start", supports_no_wait=True) + g.wait_command("wait") + g.custom_command( + "get-versions", + "aks_get_versions", + table_transformer=aks_versions_table_format, + ) # aks-preview only - g.custom_command('kollect', 'aks_kollect') - g.custom_command('kanalyze', 'aks_kanalyze') - g.custom_command('get-os-options', 'aks_get_os_options') - g.custom_command('operation-abort', 'aks_operation_abort', supports_no_wait=True) + g.custom_command("kollect", "aks_kollect") + g.custom_command("kanalyze", "aks_kanalyze") + g.custom_command("get-os-options", "aks_get_os_options") + g.custom_command( + "operation-abort", "aks_operation_abort", supports_no_wait=True + ) # AKS maintenance configuration commands - with self.command_group('aks maintenanceconfiguration', maintenance_configuration_sdk, client_factory=cf_maintenance_configurations) as g: - g.custom_command('list', 'aks_maintenanceconfiguration_list') - g.custom_show_command('show', 'aks_maintenanceconfiguration_show') - g.custom_command('add', 'aks_maintenanceconfiguration_add') - g.custom_command('update', 'aks_maintenanceconfiguration_update') - g.custom_command('delete', 'aks_maintenanceconfiguration_delete') + with self.command_group( + "aks maintenanceconfiguration", + maintenance_configuration_sdk, + client_factory=cf_maintenance_configurations, + ) as g: + g.custom_command("list", "aks_maintenanceconfiguration_list") + g.custom_show_command("show", "aks_maintenanceconfiguration_show") + g.custom_command("add", "aks_maintenanceconfiguration_add") + g.custom_command("update", "aks_maintenanceconfiguration_update") + g.custom_command("delete", "aks_maintenanceconfiguration_delete") # AKS addon commands - with self.command_group('aks addon', managed_clusters_sdk, client_factory=cf_managed_clusters) as g: - g.custom_command('list-available', 'aks_addon_list_available', - table_transformer=aks_addon_list_available_table_format) - g.custom_command('list', 'aks_addon_list', - table_transformer=aks_addon_list_table_format) - g.custom_show_command('show', 'aks_addon_show', - table_transformer=aks_addon_show_table_format) - g.custom_command('enable', 'aks_addon_enable', supports_no_wait=True) - g.custom_command('disable', 'aks_addon_disable', supports_no_wait=True) - g.custom_command('update', 'aks_addon_update', supports_no_wait=True) + with self.command_group( + "aks addon", managed_clusters_sdk, client_factory=cf_managed_clusters + ) as g: + g.custom_command( + "list-available", + "aks_addon_list_available", + table_transformer=aks_addon_list_available_table_format, + ) + g.custom_command( + "list", "aks_addon_list", table_transformer=aks_addon_list_table_format + ) + g.custom_show_command( + "show", "aks_addon_show", table_transformer=aks_addon_show_table_format + ) + g.custom_command("enable", "aks_addon_enable", supports_no_wait=True) + g.custom_command("disable", "aks_addon_disable", supports_no_wait=True) + g.custom_command("update", "aks_addon_update", supports_no_wait=True) # AKS agent pool commands - with self.command_group('aks nodepool', agent_pools_sdk, client_factory=cf_agent_pools) as g: - g.custom_command('list', 'aks_agentpool_list', - table_transformer=aks_agentpool_list_table_format) - g.custom_show_command('show', 'aks_agentpool_show', - table_transformer=aks_agentpool_show_table_format) - g.custom_command('add', 'aks_agentpool_add', supports_no_wait=True) - g.custom_command('scale', 'aks_agentpool_scale', supports_no_wait=True) - g.custom_command('upgrade', 'aks_agentpool_upgrade', - supports_no_wait=True) - g.custom_command('update', 'aks_agentpool_update', - supports_no_wait=True) - g.custom_command('delete', 'aks_agentpool_delete', - supports_no_wait=True) - g.custom_command('get-upgrades', 'aks_agentpool_get_upgrade_profile') - g.custom_command('stop', 'aks_agentpool_stop', supports_no_wait=True) - g.custom_command('start', 'aks_agentpool_start', supports_no_wait=True) - g.custom_command('operation-abort', 'aks_agentpool_operation_abort', supports_no_wait=True) - - with self.command_group('aks machine', machines_sdk, client_factory=cf_machines) as g: - g.custom_command('list', 'aks_machine_list', - table_transformer=aks_machine_list_table_format) - g.custom_show_command('show', 'aks_machine_show', - table_transformer=aks_machine_show_table_format) + with self.command_group( + "aks nodepool", agent_pools_sdk, client_factory=cf_agent_pools + ) as g: + g.custom_command( + "list", + "aks_agentpool_list", + table_transformer=aks_agentpool_list_table_format, + ) + g.custom_show_command( + "show", + "aks_agentpool_show", + table_transformer=aks_agentpool_show_table_format, + ) + g.custom_command("add", "aks_agentpool_add", supports_no_wait=True) + g.custom_command("scale", "aks_agentpool_scale", supports_no_wait=True) + g.custom_command("upgrade", "aks_agentpool_upgrade", supports_no_wait=True) + g.custom_command("update", "aks_agentpool_update", supports_no_wait=True) + g.custom_command("delete", "aks_agentpool_delete", supports_no_wait=True) + g.custom_command("get-upgrades", "aks_agentpool_get_upgrade_profile") + g.custom_command("stop", "aks_agentpool_stop", supports_no_wait=True) + g.custom_command("start", "aks_agentpool_start", supports_no_wait=True) + g.custom_command( + "operation-abort", "aks_agentpool_operation_abort", supports_no_wait=True + ) + + with self.command_group( + "aks machine", machines_sdk, client_factory=cf_machines + ) as g: + g.custom_command( + "list", "aks_machine_list", table_transformer=aks_machine_list_table_format + ) + g.custom_show_command( + "show", "aks_machine_show", table_transformer=aks_machine_show_table_format + ) # AKS draft commands - with self.command_group('aks draft', managed_clusters_sdk, client_factory=cf_managed_clusters) as g: - g.custom_command('create', 'aks_draft_create') - g.custom_command('setup-gh', 'aks_draft_setup_gh') - g.custom_command('generate-workflow', 'aks_draft_generate_workflow') - g.custom_command('up', 'aks_draft_up') - g.custom_command('update', 'aks_draft_update') + with self.command_group( + "aks draft", managed_clusters_sdk, client_factory=cf_managed_clusters + ) as g: + g.custom_command("create", "aks_draft_create") + g.custom_command("setup-gh", "aks_draft_setup_gh") + g.custom_command("generate-workflow", "aks_draft_generate_workflow") + g.custom_command("up", "aks_draft_up") + g.custom_command("update", "aks_draft_update") # AKS pod identity commands - with self.command_group('aks pod-identity', managed_clusters_sdk, client_factory=cf_managed_clusters) as g: - g.custom_command('add', 'aks_pod_identity_add') - g.custom_command('delete', 'aks_pod_identity_delete') - g.custom_command('list', 'aks_pod_identity_list', - table_transformer=aks_pod_identities_table_format) + with self.command_group( + "aks pod-identity", managed_clusters_sdk, client_factory=cf_managed_clusters + ) as g: + g.custom_command("add", "aks_pod_identity_add") + g.custom_command("delete", "aks_pod_identity_delete") + g.custom_command( + "list", + "aks_pod_identity_list", + table_transformer=aks_pod_identities_table_format, + ) # AKS pod identity exception commands - with self.command_group('aks pod-identity exception', managed_clusters_sdk, client_factory=cf_managed_clusters) as g: - g.custom_command('add', 'aks_pod_identity_exception_add') - g.custom_command('delete', 'aks_pod_identity_exception_delete') - g.custom_command('update', 'aks_pod_identity_exception_update') - g.custom_command('list', 'aks_pod_identity_exception_list', - table_transformer=aks_pod_identity_exceptions_table_format) + with self.command_group( + "aks pod-identity exception", + managed_clusters_sdk, + client_factory=cf_managed_clusters, + ) as g: + g.custom_command("add", "aks_pod_identity_exception_add") + g.custom_command("delete", "aks_pod_identity_exception_delete") + g.custom_command("update", "aks_pod_identity_exception_update") + g.custom_command( + "list", + "aks_pod_identity_exception_list", + table_transformer=aks_pod_identity_exceptions_table_format, + ) # AKS egress commands - with self.command_group('aks egress-endpoints', managed_clusters_sdk, client_factory=cf_managed_clusters) as g: - g.custom_command('list', 'aks_egress_endpoints_list') + with self.command_group( + "aks egress-endpoints", managed_clusters_sdk, client_factory=cf_managed_clusters + ) as g: + g.custom_command("list", "aks_egress_endpoints_list") # AKS nodepool snapshot commands - with self.command_group('aks nodepool snapshot', nodepool_snapshot_sdk, client_factory=cf_nodepool_snapshots) as g: - g.custom_command('list', 'aks_nodepool_snapshot_list', - table_transformer=aks_list_nodepool_snapshot_table_format) - g.custom_show_command('show', 'aks_nodepool_snapshot_show', - table_transformer=aks_show_nodepool_snapshot_table_format) - g.custom_command('create', 'aks_nodepool_snapshot_create', - supports_no_wait=True) - g.custom_command('update', 'aks_nodepool_snapshot_update') - g.custom_command('delete', 'aks_nodepool_snapshot_delete', - supports_no_wait=True) + with self.command_group( + "aks nodepool snapshot", + nodepool_snapshot_sdk, + client_factory=cf_nodepool_snapshots, + ) as g: + g.custom_command( + "list", + "aks_nodepool_snapshot_list", + table_transformer=aks_list_nodepool_snapshot_table_format, + ) + g.custom_show_command( + "show", + "aks_nodepool_snapshot_show", + table_transformer=aks_show_nodepool_snapshot_table_format, + ) + g.custom_command( + "create", "aks_nodepool_snapshot_create", supports_no_wait=True + ) + g.custom_command("update", "aks_nodepool_snapshot_update") + g.custom_command( + "delete", "aks_nodepool_snapshot_delete", supports_no_wait=True + ) # AKS mc snapshot commands - with self.command_group('aks snapshot', mc_snapshot_sdk, client_factory=cf_mc_snapshots) as g: - g.custom_command('list', 'aks_snapshot_list', - table_transformer=aks_list_snapshot_table_format) - g.custom_show_command('show', 'aks_snapshot_show', - table_transformer=aks_show_snapshot_table_format) - g.custom_command('create', 'aks_snapshot_create', - supports_no_wait=True) - g.custom_command('delete', 'aks_snapshot_delete', - supports_no_wait=True) + with self.command_group( + "aks snapshot", mc_snapshot_sdk, client_factory=cf_mc_snapshots + ) as g: + g.custom_command( + "list", + "aks_snapshot_list", + table_transformer=aks_list_snapshot_table_format, + ) + g.custom_show_command( + "show", + "aks_snapshot_show", + table_transformer=aks_show_snapshot_table_format, + ) + g.custom_command("create", "aks_snapshot_create", supports_no_wait=True) + g.custom_command("delete", "aks_snapshot_delete", supports_no_wait=True) # AKS trusted access role commands - with self.command_group('aks trustedaccess role', trustedaccess_role_sdk, client_factory=cf_trustedaccess_role) as g: - g.custom_command('list', 'aks_trustedaccess_role_list') + with self.command_group( + "aks trustedaccess role", + trustedaccess_role_sdk, + client_factory=cf_trustedaccess_role, + ) as g: + g.custom_command("list", "aks_trustedaccess_role_list") # AKS trusted access rolebinding commands - with self.command_group('aks trustedaccess rolebinding', trustedaccess_role_binding_sdk, client_factory=cf_trustedaccess_role_binding) as g: - g.custom_command('list', 'aks_trustedaccess_role_binding_list') - g.custom_show_command('show', 'aks_trustedaccess_role_binding_get') - g.custom_command('create', 'aks_trustedaccess_role_binding_create') - g.custom_command('update', 'aks_trustedaccess_role_binding_update') - g.custom_command('delete', 'aks_trustedaccess_role_binding_delete', confirmation=True) + with self.command_group( + "aks trustedaccess rolebinding", + trustedaccess_role_binding_sdk, + client_factory=cf_trustedaccess_role_binding, + ) as g: + g.custom_command("list", "aks_trustedaccess_role_binding_list") + g.custom_show_command("show", "aks_trustedaccess_role_binding_get") + g.custom_command("create", "aks_trustedaccess_role_binding_create") + g.custom_command("update", "aks_trustedaccess_role_binding_update") + g.custom_command( + "delete", "aks_trustedaccess_role_binding_delete", confirmation=True + ) # AKS mesh commands - with self.command_group('aks mesh', managed_clusters_sdk, client_factory=cf_managed_clusters) as g: + with self.command_group( + "aks mesh", managed_clusters_sdk, client_factory=cf_managed_clusters + ) as g: + g.custom_command("enable", "aks_mesh_enable", supports_no_wait=True) g.custom_command( - 'enable', - 'aks_mesh_enable', - supports_no_wait=True) + "disable", "aks_mesh_disable", supports_no_wait=True, confirmation=True + ) g.custom_command( - 'disable', - 'aks_mesh_disable', + "enable-ingress-gateway", + "aks_mesh_enable_ingress_gateway", supports_no_wait=True, - confirmation=True) - g.custom_command( - 'enable-ingress-gateway', - 'aks_mesh_enable_ingress_gateway', - supports_no_wait=True) + ) g.custom_command( - 'enable-egress-gateway', - 'aks_mesh_enable_egress_gateway', - supports_no_wait=True) + "enable-egress-gateway", + "aks_mesh_enable_egress_gateway", + supports_no_wait=True, + ) g.custom_command( - 'disable-ingress-gateway', - 'aks_mesh_disable_ingress_gateway', + "disable-ingress-gateway", + "aks_mesh_disable_ingress_gateway", supports_no_wait=True, - confirmation=True) + confirmation=True, + ) g.custom_command( - 'disable-egress-gateway', - 'aks_mesh_disable_egress_gateway', + "disable-egress-gateway", + "aks_mesh_disable_egress_gateway", supports_no_wait=True, - confirmation=True) + confirmation=True, + ) g.custom_command( - 'get-revisions', - 'aks_mesh_get_revisions', - table_transformer=aks_mesh_revisions_table_format) + "get-revisions", + "aks_mesh_get_revisions", + table_transformer=aks_mesh_revisions_table_format, + ) g.custom_command( - 'get-upgrades', - 'aks_mesh_get_upgrades', - table_transformer=aks_mesh_upgrades_table_format) + "get-upgrades", + "aks_mesh_get_upgrades", + table_transformer=aks_mesh_upgrades_table_format, + ) # AKS mesh upgrade commands - with self.command_group('aks mesh upgrade', managed_clusters_sdk, client_factory=cf_managed_clusters) as g: - g.custom_command( - 'start', - 'aks_mesh_upgrade_start', - supports_no_wait=True) - g.custom_command( - 'complete', - 'aks_mesh_upgrade_complete', - supports_no_wait=True) - g.custom_command( - 'rollback', - 'aks_mesh_upgrade_rollback', - supports_no_wait=True) + with self.command_group( + "aks mesh upgrade", managed_clusters_sdk, client_factory=cf_managed_clusters + ) as g: + g.custom_command("start", "aks_mesh_upgrade_start", supports_no_wait=True) + g.custom_command("complete", "aks_mesh_upgrade_complete", supports_no_wait=True) + g.custom_command("rollback", "aks_mesh_upgrade_rollback", supports_no_wait=True) # AKS approuting commands - with self.command_group('aks approuting', managed_clusters_sdk, client_factory=cf_managed_clusters) as g: - g.custom_command( - 'enable', - 'aks_approuting_enable') - g.custom_command( - 'disable', - 'aks_approuting_disable', confirmation=True) - g.custom_command( - 'update', - 'aks_approuting_update') + with self.command_group( + "aks approuting", managed_clusters_sdk, client_factory=cf_managed_clusters + ) as g: + g.custom_command("enable", "aks_approuting_enable") + g.custom_command("disable", "aks_approuting_disable", confirmation=True) + g.custom_command("update", "aks_approuting_update") # AKS approuting dns-zone commands - with self.command_group('aks approuting zone', managed_clusters_sdk, client_factory=cf_managed_clusters) as g: - g.custom_command( - 'add', - 'aks_approuting_zone_add') - g.custom_command( - 'delete', - 'aks_approuting_zone_delete', confirmation=True) - g.custom_command( - 'update', - 'aks_approuting_zone_update') - g.custom_command( - 'list', - 'aks_approuting_zone_list') + with self.command_group( + "aks approuting zone", managed_clusters_sdk, client_factory=cf_managed_clusters + ) as g: + g.custom_command("add", "aks_approuting_zone_add") + g.custom_command("delete", "aks_approuting_zone_delete", confirmation=True) + g.custom_command("update", "aks_approuting_zone_update") + g.custom_command("list", "aks_approuting_zone_list") diff --git a/src/aks-preview/azext_aks_preview/custom.py b/src/aks-preview/azext_aks_preview/custom.py index 638b743f056..9ee5b8915c5 100644 --- a/src/aks-preview/azext_aks_preview/custom.py +++ b/src/aks-preview/azext_aks_preview/custom.py @@ -1,9 +1,9 @@ # -------------------------------------------------------------------------------------------- -# -------------------------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- +# pylint: disable=too-many-lines import datetime import json import os @@ -22,7 +22,6 @@ cf_agent_pools, get_graph_rbac_management_client, get_msi_client, - cf_machines ) from azext_aks_preview._consts import ( ADDONS, @@ -49,7 +48,6 @@ CONST_SPOT_EVICTION_POLICY_DELETE, CONST_VIRTUAL_NODE_ADDON_NAME, CONST_VIRTUAL_NODE_SUBNET_NAME, - CONST_AZURE_KEYVAULT_SECRETS_PROVIDER_ADDON_NAME, CONST_AZURE_SERVICE_MESH_UPGRADE_COMMAND_START, CONST_AZURE_SERVICE_MESH_UPGRADE_COMMAND_COMPLETE, CONST_AZURE_SERVICE_MESH_UPGRADE_COMMAND_ROLLBACK, @@ -130,10 +128,10 @@ def wait_then_open(url): """ for _ in range(1, 10): try: - urlopen(url, context=_ssl_context()) + with urlopen(url, context=_ssl_context()): + break except URLError: time.sleep(1) - break webbrowser.open_new_tab(url) @@ -141,7 +139,7 @@ def wait_then_open_async(url): """ Spawns a thread that waits for a bit then opens a URL. """ - t = threading.Thread(target=wait_then_open, args=({url})) + t = threading.Thread(target=wait_then_open, args=url) t.daemon = True t.start() @@ -216,8 +214,10 @@ def create_application(client, display_name, homepage, identifier_uris, except GraphErrorException as ex: if 'insufficient privileges' in str(ex).lower(): link = 'https://docs.microsoft.com/azure/azure-resource-manager/resource-group-create-service-principal-portal' # pylint: disable=line-too-long - raise CLIError("Directory permission is needed for the current user to register the application. " - "For how to configure, please refer '{}'. Original error: {}".format(link, ex)) + raise CLIError( + "Directory permission is needed for the current user to register the application. " + f"For how to configure, please refer '{link}'." + ) from ex raise @@ -260,10 +260,10 @@ def create_service_principal(cli_ctx, identifier, resolve_app=True, rbac_client= try: uuid.UUID(identifier) result = list(rbac_client.applications.list( - filter="appId eq '{}'".format(identifier))) + filter=f"appId eq '{identifier}'")) except ValueError: result = list(rbac_client.applications.list( - filter="identifierUris/any(s:s eq '{}')".format(identifier))) + filter=f"identifierUris/any(s:s eq '{identifier}')")) if not result: # assume we get an object id result = [rbac_client.applications.get(identifier)] @@ -292,11 +292,10 @@ def _get_user_assigned_identity(cli_ctx, resource_id): resource_name=identity_name) except CloudError as ex: if 'was not found' in ex.message: - raise CLIError("Identity {} not found.".format(resource_id)) - raise CLIError(ex.message) + raise CLIError(f"Identity {resource_id} not found.") from ex + raise ex return identity - raise CLIError( - "Cannot parse identity name from provided resource id {}.".format(resource_id)) + raise CLIError(f"Cannot parse identity name from provided resource id {resource_id}.") def aks_browse( @@ -323,7 +322,7 @@ def aks_browse( def aks_maintenanceconfiguration_list( - cmd, + cmd, # pylint: disable=unused-argument client, resource_group_name, cluster_name @@ -332,7 +331,7 @@ def aks_maintenanceconfiguration_list( def aks_maintenanceconfiguration_show( - cmd, + cmd, # pylint: disable=unused-argument client, resource_group_name, cluster_name, @@ -344,7 +343,7 @@ def aks_maintenanceconfiguration_show( def aks_maintenanceconfiguration_delete( - cmd, + cmd, # pylint: disable=unused-argument client, resource_group_name, cluster_name, @@ -355,6 +354,7 @@ def aks_maintenanceconfiguration_delete( return client.delete(resource_group_name, cluster_name, config_name) +# pylint: disable=unused-argument def aks_maintenanceconfiguration_add( cmd, client, @@ -379,8 +379,10 @@ def aks_maintenanceconfiguration_add( configs = client.list_by_managed_cluster(resource_group_name, cluster_name) for config in configs: if config.name == config_name: - raise CLIError("Maintenance configuration '{}' already exists, please try a different name, " - "use 'aks maintenanceconfiguration list' to get current list of maitenance configurations".format(config_name)) + raise CLIError( + f"Maintenance configuration '{config_name}' already exists, please try a different name, " + "use 'aks maintenanceconfiguration list' to get current list of maitenance configurations" + ) # DO NOT MOVE: get all the original parameters and save them as a dictionary raw_parameters = locals() return aks_maintenanceconfiguration_update_internal(cmd, client, raw_parameters) @@ -414,14 +416,16 @@ def aks_maintenanceconfiguration_update( found = True break if not found: - raise CLIError("Maintenance configuration '{}' doesn't exist." - "use 'aks maintenanceconfiguration list' to get current list of maitenance configurations".format(config_name)) + raise CLIError( + f"Maintenance configuration '{config_name}' doesn't exist." + "use 'aks maintenanceconfiguration list' to get current list of maitenance configurations" + ) # DO NOT MOVE: get all the original parameters and save them as a dictionary raw_parameters = locals() return aks_maintenanceconfiguration_update_internal(cmd, client, raw_parameters) -# pylint: disable=too-many-locals +# pylint: disable=too-many-locals, unused-argument def aks_create( cmd, client, @@ -505,7 +509,7 @@ def aks_create( azure_keyvault_kms_key_vault_resource_id=None, http_proxy_config=None, # addons - enable_addons=None, + enable_addons=None, # pylint: disable=redefined-outer-name workspace_resource_id=None, enable_msi_auth_for_monitoring=True, enable_syslog=False, @@ -646,7 +650,7 @@ def aks_create( return aks_create_decorator.create_mc(mc) -# pylint: disable=too-many-locals +# pylint: disable=too-many-locals, unused-argument def aks_update( cmd, client, @@ -822,13 +826,16 @@ def aks_show(cmd, client, resource_group_name, name, aks_custom_headers=None): return _remove_nulls([mc])[0] +# pylint: disable=unused-argument def aks_stop(cmd, client, resource_group_name, name, no_wait=False): instance = client.get(resource_group_name, name) # print warning when stopping a private cluster if check_is_private_link_cluster(instance): - logger.warning('Your private cluster apiserver IP might get changed when it\'s stopped and started.\n' - 'Any user provisioned private endpoints linked to this private cluster will need to be deleted and created again. ' - 'Any user managed DNS record also needs to be updated with the new IP.') + logger.warning( + "Your private cluster apiserver IP might get changed when it's stopped and started.\n" + "Any user provisioned private endpoints linked to this private cluster will need to be deleted and " + "created again. Any user managed DNS record also needs to be updated with the new IP." + ) return sdk_no_wait(no_wait, client.begin_stop, resource_group_name, name) @@ -922,8 +929,8 @@ def aks_get_credentials( encoding='UTF-8') print_or_merge_credentials( path, kubeconfig, overwrite_existing, context_name) - except (IndexError, ValueError): - raise CLIError("Fail to find kubeconfig file.") + except (IndexError, ValueError) as exc: + raise CLIError("Fail to find kubeconfig file.") from exc def aks_scale(cmd, # pylint: disable=unused-argument @@ -939,8 +946,10 @@ def aks_scale(cmd, # pylint: disable=unused-argument _fill_defaults_for_pod_identity_profile(instance.pod_identity_profile) if len(instance.agent_pool_profiles) > 1 and nodepool_name == "": - raise CLIError('There are more than one node pool in the cluster. ' - 'Please specify nodepool name or use az aks nodepool command to scale node pool') + raise CLIError( + "There are more than one node pool in the cluster. " + "Please specify nodepool name or use az aks nodepool command to scale node pool" + ) for agent_profile in instance.agent_pool_profiles: if agent_profile.name == nodepool_name or (nodepool_name == "" and len(instance.agent_pool_profiles) == 1): @@ -948,14 +957,22 @@ def aks_scale(cmd, # pylint: disable=unused-argument raise CLIError( "Cannot scale cluster autoscaler enabled node pool.") - agent_profile.count = int(node_count) # pylint: disable=no-member + agent_profile.count = int(node_count) # null out the SP profile because otherwise validation complains instance.service_principal_profile = None - return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, name, instance, headers=headers) - raise CLIError('The nodepool "{}" was not found.'.format(nodepool_name)) + return sdk_no_wait( + no_wait, + client.begin_create_or_update, + resource_group_name, + name, + instance, + headers=headers, + ) + raise CLIError(f'The nodepool "{nodepool_name}" was not found.') -def aks_upgrade(cmd, # pylint: disable=unused-argument, too-many-return-statements +# pylint: disable=too-many-return-statements, too-many-branches +def aks_upgrade(cmd, client, resource_group_name, name, @@ -1028,21 +1045,27 @@ def aks_upgrade(cmd, # pylint: disable=unused-argument, too-many-return-state # for legacy clusters, we always upgrade node pools with CCP. if instance.max_agent_pools < 8 or vmas_cluster: if control_plane_only: - msg = ("Legacy clusters do not support control plane only upgrade. All node pools will be " - "upgraded to {} as well. Continue?").format(instance.kubernetes_version) + msg = ( + "Legacy clusters do not support control plane only upgrade. All node pools will be " + f"upgraded to {instance.kubernetes_version} as well. Continue?" + ) if not yes and not prompt_y_n(msg, default="n"): return None upgrade_all = True else: if not control_plane_only: - msg = ("Since control-plane-only argument is not specified, this will upgrade the control plane " - "AND all nodepools to version {}. Continue?").format(instance.kubernetes_version) + msg = ( + "Since control-plane-only argument is not specified, this will upgrade the control plane " + f"AND all nodepools to version {instance.kubernetes_version}. Continue?" + ) if not yes and not prompt_y_n(msg, default="n"): return None upgrade_all = True else: - msg = ("Since control-plane-only argument is specified, this will upgrade only the control plane to {}. " - "Node pool will not change. Continue?").format(instance.kubernetes_version) + msg = ( + "Since control-plane-only argument is specified, this will upgrade only the control plane to " + f"{instance.kubernetes_version}. Node pool will not change. Continue?" + ) if not yes and not prompt_y_n(msg, default="n"): return None @@ -1059,12 +1082,21 @@ def aks_upgrade(cmd, # pylint: disable=unused-argument, too-many-return-state return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, name, instance, headers=headers) -def _upgrade_single_nodepool_image_version(no_wait, client, resource_group_name, cluster_name, nodepool_name, snapshot_id=None): +def _upgrade_single_nodepool_image_version( + no_wait, client, resource_group_name, cluster_name, nodepool_name, snapshot_id=None +): headers = {} if snapshot_id: headers["AKSSnapshotId"] = snapshot_id - return sdk_no_wait(no_wait, client.begin_upgrade_node_image_version, resource_group_name, cluster_name, nodepool_name, headers=headers) + return sdk_no_wait( + no_wait, + client.begin_upgrade_node_image_version, + resource_group_name, + cluster_name, + nodepool_name, + headers=headers, + ) def aks_agentpool_show(cmd, # pylint: disable=unused-argument @@ -1234,7 +1266,15 @@ def aks_agentpool_scale(cmd, # pylint: disable=unused-argument raise CLIError( "The new node count is the same as the current node count.") instance.count = new_node_count # pylint: disable=no-member - return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, cluster_name, nodepool_name, instance, headers=headers) + return sdk_no_wait( + no_wait, + client.begin_create_or_update, + resource_group_name, + cluster_name, + nodepool_name, + instance, + headers=headers, + ) def aks_agentpool_upgrade(cmd, @@ -1266,9 +1306,10 @@ def aks_agentpool_upgrade(cmd, # Note: we exclude this option because node image upgrade can't accept nodepool put fields like max surge if (max_surge or drain_timeout or node_soak_duration) and node_image_only: raise MutuallyExclusiveArgumentError( - 'Conflicting flags. Unable to specify max-surge/drain-timeout/node-soak-duration with node-image-only.' - 'If you want to use max-surge/drain-timeout/node-soak-duration with a node image upgrade, please first ' - 'update max-surge/drain-timeout/node-soak-duration using "az aks nodepool update --max-surge/--drain-timeout/--node-soak-duration".' + "Conflicting flags. Unable to specify max-surge/drain-timeout/node-soak-duration with node-image-only." + "If you want to use max-surge/drain-timeout/node-soak-duration with a node image upgrade, please first " + "update max-surge/drain-timeout/node-soak-duration using " + '"az aks nodepool update --max-surge/--drain-timeout/--node-soak-duration".' ) if node_image_only: @@ -1301,9 +1342,16 @@ def aks_agentpool_upgrade(cmd, if kubernetes_version != '' or instance.orchestrator_version == kubernetes_version: msg = "The new kubernetes version is the same as the current kubernetes version." if instance.provisioning_state == "Succeeded": - msg = "The cluster is already on version {} and is not in a failed state. No operations will occur when upgrading to the same version if the cluster is not in a failed state.".format(instance.orchestrator_version) + msg = ( + f"The cluster is already on version {instance.orchestrator_version} and is not in a failed state. " + "No operations will occur when upgrading to the same version if the cluster " + "is not in a failed state." + ) elif instance.provisioning_state == "Failed": - msg = "Cluster currently in failed state. Proceeding with upgrade to existing version {} to attempt resolution of failed cluster state.".format(instance.orchestrator_version) + msg = ( + "Cluster currently in failed state. Proceeding with upgrade to existing version " + f"{instance.orchestrator_version} to attempt resolution of failed cluster state." + ) if not yes and not prompt_y_n(msg): return None @@ -1370,13 +1418,22 @@ def aks_agentpool_stop(cmd, # pylint: disable=unused-argument if not agentpool_exists: raise InvalidArgumentValueError( - "Node pool {} doesnt exist, use 'aks nodepool list' to get current node pool list".format(nodepool_name)) + f"Node pool {nodepool_name} doesnt exist, use 'aks nodepool list' to get current node pool list" + ) instance = client.get(resource_group_name, cluster_name, nodepool_name) power_state = PowerState(code="Stopped") instance.power_state = power_state headers = get_aks_custom_headers(aks_custom_headers) - return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, cluster_name, nodepool_name, instance, headers=headers) + return sdk_no_wait( + no_wait, + client.begin_create_or_update, + resource_group_name, + cluster_name, + nodepool_name, + instance, + headers=headers, + ) def aks_agentpool_start(cmd, # pylint: disable=unused-argument @@ -1400,12 +1457,21 @@ def aks_agentpool_start(cmd, # pylint: disable=unused-argument break if not agentpool_exists: raise InvalidArgumentValueError( - "Node pool {} doesnt exist, use 'aks nodepool list' to get current node pool list".format(nodepool_name)) + f"Node pool {nodepool_name} doesnt exist, use 'aks nodepool list' to get current node pool list" + ) instance = client.get(resource_group_name, cluster_name, nodepool_name) power_state = PowerState(code="Running") instance.power_state = power_state headers = get_aks_custom_headers(aks_custom_headers) - return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, cluster_name, nodepool_name, instance, headers=headers) + return sdk_no_wait( + no_wait, + client.begin_create_or_update, + resource_group_name, + cluster_name, + nodepool_name, + instance, + headers=headers, + ) def aks_agentpool_delete(cmd, # pylint: disable=unused-argument @@ -1423,10 +1489,19 @@ def aks_agentpool_delete(cmd, # pylint: disable=unused-argument break if not agentpool_exists: - raise CLIError("Node pool {} doesnt exist, " - "use 'aks nodepool list' to get current node pool list".format(nodepool_name)) + raise CLIError( + f"Node pool {nodepool_name} doesnt exist, " + "use 'aks nodepool list' to get current node pool list" + ) - return sdk_no_wait(no_wait, client.begin_delete, resource_group_name, cluster_name, nodepool_name, ignore_pod_disruption_budget=ignore_pod_disruption_budget) + return sdk_no_wait( + no_wait, + client.begin_delete, + resource_group_name, + cluster_name, + nodepool_name, + ignore_pod_disruption_budget=ignore_pod_disruption_budget, + ) def aks_agentpool_operation_abort(cmd, # pylint: disable=unused-argument @@ -1450,12 +1525,19 @@ def aks_agentpool_operation_abort(cmd, # pylint: disable=unused-argument break if not agentpool_exists: raise InvalidArgumentValueError( - "Node pool {} doesnt exist, use 'aks nodepool list' to get current node pool list".format(nodepool_name)) + f"Node pool {nodepool_name} doesnt exist, use 'aks nodepool list' to get current node pool list") instance = client.get(resource_group_name, cluster_name, nodepool_name) power_state = PowerState(code="Running") instance.power_state = power_state headers = get_aks_custom_headers(aks_custom_headers) - return sdk_no_wait(no_wait, client.begin_abort_latest_operation, resource_group_name, cluster_name, nodepool_name, headers=headers) + return sdk_no_wait( + no_wait, + client.begin_abort_latest_operation, + resource_group_name, + cluster_name, + nodepool_name, + headers=headers, + ) def aks_operation_abort(cmd, # pylint: disable=unused-argument @@ -1473,7 +1555,9 @@ def aks_operation_abort(cmd, # pylint: disable=unused-argument instance = client.get(resource_group_name, name) power_state = PowerState(code="Running") if instance is None: - raise InvalidArgumentValueError("Cluster {} doesnt exist, use 'aks list' to get current cluster list".format(name)) + raise InvalidArgumentValueError( + f"Cluster {name} doesnt exist, use 'aks list' to get current cluster list" + ) instance.power_state = power_state headers = get_aks_custom_headers(aks_custom_headers) return sdk_no_wait(no_wait, client.begin_abort_latest_operation, resource_group_name, name, headers=headers) @@ -1503,28 +1587,24 @@ def aks_addon_list(cmd, client, resource_group_name, name): current_addons = [] os_type = 'Linux' - for name, addon_key in ADDONS.items(): + for addon_name, addon_key in ADDONS.items(): # web_application_routing is a special case, the configuration is stored in a separate profile - if name == "web_application_routing": - enabled = ( - True - if mc.ingress_profile and + if addon_name == "web_application_routing": + enabled = bool( + mc.ingress_profile and mc.ingress_profile.web_app_routing and mc.ingress_profile.web_app_routing.enabled - else False ) else: - if name == "virtual-node": + if addon_name == "virtual-node": addon_key += os_type - enabled = ( - True - if mc.addon_profiles and + enabled = bool( + mc.addon_profiles and addon_key in mc.addon_profiles and mc.addon_profiles[addon_key].enabled - else False ) current_addons.append({ - "name": name, + "name": addon_name, "api_key": addon_key, "enabled": enabled }) @@ -1539,7 +1619,11 @@ def aks_addon_show(cmd, client, resource_group_name, name, addon): # web_application_routing is a special case, the configuration is stored in a separate profile if addon == "web_application_routing": - if not mc.ingress_profile and not mc.ingress_profile.web_app_routing and not mc.ingress_profile.web_app_routing.enabled: + if ( + not mc.ingress_profile and + not mc.ingress_profile.web_app_routing and + not mc.ingress_profile.web_app_routing.enabled + ): raise InvalidArgumentValueError(f'Addon "{addon}" is not enabled in this cluster.') return { "name": addon, @@ -1558,32 +1642,84 @@ def aks_addon_show(cmd, client, resource_group_name, name, addon): } -def aks_addon_enable(cmd, client, resource_group_name, name, addon, workspace_resource_id=None, - subnet_name=None, appgw_name=None, appgw_subnet_prefix=None, appgw_subnet_cidr=None, appgw_id=None, - appgw_subnet_id=None, - appgw_watch_namespace=None, enable_sgxquotehelper=False, enable_secret_rotation=False, rotation_poll_interval=None, - no_wait=False, enable_msi_auth_for_monitoring=True, - dns_zone_resource_id=None, dns_zone_resource_ids=None, enable_syslog=False, data_collection_settings=None): - return enable_addons(cmd, client, resource_group_name, name, addon, workspace_resource_id=workspace_resource_id, - subnet_name=subnet_name, appgw_name=appgw_name, appgw_subnet_prefix=appgw_subnet_prefix, - appgw_subnet_cidr=appgw_subnet_cidr, appgw_id=appgw_id, appgw_subnet_id=appgw_subnet_id, - appgw_watch_namespace=appgw_watch_namespace, enable_sgxquotehelper=enable_sgxquotehelper, - enable_secret_rotation=enable_secret_rotation, rotation_poll_interval=rotation_poll_interval, no_wait=no_wait, - enable_msi_auth_for_monitoring=enable_msi_auth_for_monitoring, - dns_zone_resource_id=dns_zone_resource_id, dns_zone_resource_ids=dns_zone_resource_ids, enable_syslog=enable_syslog, - data_collection_settings=data_collection_settings) +def aks_addon_enable( + cmd, + client, + resource_group_name, + name, + addon, + workspace_resource_id=None, + subnet_name=None, + appgw_name=None, + appgw_subnet_prefix=None, + appgw_subnet_cidr=None, + appgw_id=None, + appgw_subnet_id=None, + appgw_watch_namespace=None, + enable_sgxquotehelper=False, + enable_secret_rotation=False, + rotation_poll_interval=None, + no_wait=False, + enable_msi_auth_for_monitoring=True, + dns_zone_resource_id=None, + dns_zone_resource_ids=None, + enable_syslog=False, + data_collection_settings=None, +): + return enable_addons( + cmd, + client, + resource_group_name, + name, + addon, + workspace_resource_id=workspace_resource_id, + subnet_name=subnet_name, + appgw_name=appgw_name, + appgw_subnet_prefix=appgw_subnet_prefix, + appgw_subnet_cidr=appgw_subnet_cidr, + appgw_id=appgw_id, + appgw_subnet_id=appgw_subnet_id, + appgw_watch_namespace=appgw_watch_namespace, + enable_sgxquotehelper=enable_sgxquotehelper, + enable_secret_rotation=enable_secret_rotation, + rotation_poll_interval=rotation_poll_interval, + no_wait=no_wait, + enable_msi_auth_for_monitoring=enable_msi_auth_for_monitoring, + dns_zone_resource_id=dns_zone_resource_id, + dns_zone_resource_ids=dns_zone_resource_ids, + enable_syslog=enable_syslog, + data_collection_settings=data_collection_settings, + ) def aks_addon_disable(cmd, client, resource_group_name, name, addon, no_wait=False): return aks_disable_addons(cmd, client, resource_group_name, name, addon, no_wait) -def aks_addon_update(cmd, client, resource_group_name, name, addon, workspace_resource_id=None, - subnet_name=None, appgw_name=None, appgw_subnet_prefix=None, appgw_subnet_cidr=None, appgw_id=None, - appgw_subnet_id=None, - appgw_watch_namespace=None, enable_sgxquotehelper=False, enable_secret_rotation=False, rotation_poll_interval=None, - no_wait=False, enable_msi_auth_for_monitoring=None, - dns_zone_resource_id=None, dns_zone_resource_ids=None, enable_syslog=False, data_collection_settings=None): +def aks_addon_update( + cmd, + client, + resource_group_name, + name, + addon, + workspace_resource_id=None, + subnet_name=None, + appgw_name=None, + appgw_subnet_prefix=None, + appgw_subnet_cidr=None, + appgw_id=None, + appgw_subnet_id=None, + appgw_watch_namespace=None, + enable_sgxquotehelper=False, + enable_secret_rotation=False, + rotation_poll_interval=None, + no_wait=False, + enable_msi_auth_for_monitoring=None, + dns_zone_resource_id=None, + dns_zone_resource_ids=None, + enable_syslog=False, + data_collection_settings=None, +): instance = client.get(resource_group_name, name) addon_profiles = instance.addon_profiles @@ -1591,8 +1727,14 @@ def aks_addon_update(cmd, client, resource_group_name, name, addon, workspace_re enable_msi_auth_for_monitoring = False if addon == "web_application_routing": - if (instance.ingress_profile is None) or (instance.ingress_profile.web_app_routing is None) or not instance.ingress_profile.web_app_routing.enabled: - raise InvalidArgumentValueError(f'Addon "{addon}" is not enabled in this cluster.') + if ( + (instance.ingress_profile is None) or + (instance.ingress_profile.web_app_routing is None) or + not instance.ingress_profile.web_app_routing.enabled + ): + raise InvalidArgumentValueError( + f'Addon "{addon}" is not enabled in this cluster.' + ) elif addon == "monitoring" and enable_msi_auth_for_monitoring is None: enable_msi_auth_for_monitoring = True @@ -1602,15 +1744,31 @@ def aks_addon_update(cmd, client, resource_group_name, name, addon, workspace_re if not addon_profiles or addon_key not in addon_profiles or not addon_profiles[addon_key].enabled: raise InvalidArgumentValueError(f'Addon "{addon}" is not enabled in this cluster.') - return enable_addons(cmd, client, resource_group_name, name, addon, check_enabled=False, - workspace_resource_id=workspace_resource_id, - subnet_name=subnet_name, appgw_name=appgw_name, appgw_subnet_prefix=appgw_subnet_prefix, - appgw_subnet_cidr=appgw_subnet_cidr, appgw_id=appgw_id, appgw_subnet_id=appgw_subnet_id, - appgw_watch_namespace=appgw_watch_namespace, enable_sgxquotehelper=enable_sgxquotehelper, - enable_secret_rotation=enable_secret_rotation, rotation_poll_interval=rotation_poll_interval, no_wait=no_wait, - enable_msi_auth_for_monitoring=enable_msi_auth_for_monitoring, - dns_zone_resource_id=dns_zone_resource_id, dns_zone_resource_ids=dns_zone_resource_ids, - enable_syslog=enable_syslog, data_collection_settings=data_collection_settings) + return enable_addons( + cmd, + client, + resource_group_name, + name, + addon, + check_enabled=False, + workspace_resource_id=workspace_resource_id, + subnet_name=subnet_name, + appgw_name=appgw_name, + appgw_subnet_prefix=appgw_subnet_prefix, + appgw_subnet_cidr=appgw_subnet_cidr, + appgw_id=appgw_id, + appgw_subnet_id=appgw_subnet_id, + appgw_watch_namespace=appgw_watch_namespace, + enable_sgxquotehelper=enable_sgxquotehelper, + enable_secret_rotation=enable_secret_rotation, + rotation_poll_interval=rotation_poll_interval, + no_wait=no_wait, + enable_msi_auth_for_monitoring=enable_msi_auth_for_monitoring, + dns_zone_resource_id=dns_zone_resource_id, + dns_zone_resource_ids=dns_zone_resource_ids, + enable_syslog=enable_syslog, + data_collection_settings=data_collection_settings, + ) def aks_disable_addons(cmd, client, resource_group_name, name, addons, no_wait=False): @@ -1618,10 +1776,18 @@ def aks_disable_addons(cmd, client, resource_group_name, name, addons, no_wait=F subscription_id = get_subscription_id(cmd.cli_ctx) try: - if addons == "monitoring" and CONST_MONITORING_ADDON_NAME in instance.addon_profiles and \ - instance.addon_profiles[CONST_MONITORING_ADDON_NAME].enabled and \ - CONST_MONITORING_USING_AAD_MSI_AUTH in instance.addon_profiles[CONST_MONITORING_ADDON_NAME].config and \ - str(instance.addon_profiles[CONST_MONITORING_ADDON_NAME].config[CONST_MONITORING_USING_AAD_MSI_AUTH]).lower() == 'true': + if ( + addons == "monitoring" and + CONST_MONITORING_ADDON_NAME in instance.addon_profiles and + instance.addon_profiles[CONST_MONITORING_ADDON_NAME].enabled and + CONST_MONITORING_USING_AAD_MSI_AUTH in + instance.addon_profiles[CONST_MONITORING_ADDON_NAME].config and + str( + instance.addon_profiles[CONST_MONITORING_ADDON_NAME].config[ + CONST_MONITORING_USING_AAD_MSI_AUTH + ] + ).lower() == "true" + ): # remove the DCR association because otherwise the DCR can't be deleted ensure_container_insights_for_monitoring( cmd, @@ -1655,10 +1821,31 @@ def aks_disable_addons(cmd, client, resource_group_name, name, addons, no_wait=F return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, name, instance) -def aks_enable_addons(cmd, client, resource_group_name, name, addons, workspace_resource_id=None, - subnet_name=None, appgw_name=None, appgw_subnet_prefix=None, appgw_subnet_cidr=None, appgw_id=None, appgw_subnet_id=None, - appgw_watch_namespace=None, enable_sgxquotehelper=False, enable_secret_rotation=False, rotation_poll_interval=None, no_wait=False, enable_msi_auth_for_monitoring=True, - dns_zone_resource_id=None, dns_zone_resource_ids=None, enable_syslog=False, data_collection_settings=None, aks_custom_headers=None): +def aks_enable_addons( + cmd, + client, + resource_group_name, + name, + addons, + workspace_resource_id=None, + subnet_name=None, + appgw_name=None, + appgw_subnet_prefix=None, + appgw_subnet_cidr=None, + appgw_id=None, + appgw_subnet_id=None, + appgw_watch_namespace=None, + enable_sgxquotehelper=False, + enable_secret_rotation=False, + rotation_poll_interval=None, + no_wait=False, + enable_msi_auth_for_monitoring=True, + dns_zone_resource_id=None, + dns_zone_resource_ids=None, + enable_syslog=False, + data_collection_settings=None, + aks_custom_headers=None, +): headers = get_aks_custom_headers(aks_custom_headers) instance = client.get(resource_group_name, name) # this is overwritten by _update_addons(), so the value needs to be recorded here @@ -1669,33 +1856,62 @@ def aks_enable_addons(cmd, client, resource_group_name, name, addons, workspace_ enable_msi_auth_for_monitoring = False subscription_id = get_subscription_id(cmd.cli_ctx) - instance = _update_addons(cmd, instance, subscription_id, resource_group_name, name, addons, enable=True, - workspace_resource_id=workspace_resource_id, enable_msi_auth_for_monitoring=enable_msi_auth_for_monitoring, subnet_name=subnet_name, - appgw_name=appgw_name, appgw_subnet_prefix=appgw_subnet_prefix, appgw_subnet_cidr=appgw_subnet_cidr, appgw_id=appgw_id, appgw_subnet_id=appgw_subnet_id, appgw_watch_namespace=appgw_watch_namespace, - enable_sgxquotehelper=enable_sgxquotehelper, enable_secret_rotation=enable_secret_rotation, rotation_poll_interval=rotation_poll_interval, no_wait=no_wait, - dns_zone_resource_id=dns_zone_resource_id, dns_zone_resource_ids=dns_zone_resource_ids, enable_syslog=enable_syslog, data_collection_settings=data_collection_settings) - - if CONST_MONITORING_ADDON_NAME in instance.addon_profiles and instance.addon_profiles[CONST_MONITORING_ADDON_NAME].enabled: - if CONST_MONITORING_USING_AAD_MSI_AUTH in instance.addon_profiles[CONST_MONITORING_ADDON_NAME].config and \ - str(instance.addon_profiles[CONST_MONITORING_ADDON_NAME].config[CONST_MONITORING_USING_AAD_MSI_AUTH]).lower() == 'true': + instance = _update_addons( + cmd, + instance, + subscription_id, + resource_group_name, + name, + addons, + enable=True, + workspace_resource_id=workspace_resource_id, + enable_msi_auth_for_monitoring=enable_msi_auth_for_monitoring, + subnet_name=subnet_name, + appgw_name=appgw_name, + appgw_subnet_prefix=appgw_subnet_prefix, + appgw_subnet_cidr=appgw_subnet_cidr, + appgw_id=appgw_id, + appgw_subnet_id=appgw_subnet_id, + appgw_watch_namespace=appgw_watch_namespace, + enable_sgxquotehelper=enable_sgxquotehelper, + enable_secret_rotation=enable_secret_rotation, + rotation_poll_interval=rotation_poll_interval, + no_wait=no_wait, + dns_zone_resource_id=dns_zone_resource_id, + dns_zone_resource_ids=dns_zone_resource_ids, + enable_syslog=enable_syslog, + data_collection_settings=data_collection_settings, + ) + if ( + CONST_MONITORING_ADDON_NAME in instance.addon_profiles and + instance.addon_profiles[CONST_MONITORING_ADDON_NAME].enabled + ): + if ( + CONST_MONITORING_USING_AAD_MSI_AUTH in + instance.addon_profiles[CONST_MONITORING_ADDON_NAME].config and + str( + instance.addon_profiles[CONST_MONITORING_ADDON_NAME].config[ + CONST_MONITORING_USING_AAD_MSI_AUTH + ] + ).lower() == "true" + ): if not msi_auth: raise ArgumentUsageError( "--enable-msi-auth-for-monitoring can not be used on clusters with service principal auth.") - else: - # create a Data Collection Rule (DCR) and associate it with the cluster - ensure_container_insights_for_monitoring( - cmd, - instance.addon_profiles[CONST_MONITORING_ADDON_NAME], - subscription_id, - resource_group_name, - name, - instance.location, - aad_route=True, - create_dcr=True, - create_dcra=True, - enable_syslog=enable_syslog, - data_collection_settings=data_collection_settings, - ) + # create a Data Collection Rule (DCR) and associate it with the cluster + ensure_container_insights_for_monitoring( + cmd, + instance.addon_profiles[CONST_MONITORING_ADDON_NAME], + subscription_id, + resource_group_name, + name, + instance.location, + aad_route=True, + create_dcr=True, + create_dcra=True, + enable_syslog=enable_syslog, + data_collection_settings=data_collection_settings, + ) else: # monitoring addon will use legacy path if enable_syslog: @@ -1826,7 +2042,7 @@ def _update_addons(cmd, # pylint: disable=too-many-branches,too-many-statements continue if addon_arg not in ADDONS: - raise CLIError("Invalid addon name: {}.".format(addon_arg)) + raise CLIError(f"Invalid addon name: {addon_arg}.") addon = ADDONS[addon_arg] if addon == CONST_VIRTUAL_NODE_ADDON_NAME: # only linux is supported for now, in the future this will be a user flag @@ -1858,13 +2074,23 @@ def _update_addons(cmd, # pylint: disable=too-many-branches,too-many-statements cloud_name = cmd.cli_ctx.cloud.name if enable_msi_auth_for_monitoring and (cloud_name.lower() == 'ussec' or cloud_name.lower() == 'usnat'): - if instance.identity is not None and instance.identity.type is not None and instance.identity.type == "userassigned": - logger.warning("--enable_msi_auth_for_monitoring is not supported in %s cloud and continuing monitoring enablement without this flag.", cloud_name) + if ( + instance.identity is not None and + instance.identity.type is not None and + instance.identity.type == "userassigned" + ): + logger.warning( + "--enable_msi_auth_for_monitoring is not supported in %s cloud and continuing " + "monitoring enablement without this flag.", + cloud_name, + ) enable_msi_auth_for_monitoring = False addon_profile.config = { logAnalyticsConstName: workspace_resource_id} - addon_profile.config[CONST_MONITORING_USING_AAD_MSI_AUTH] = "true" if enable_msi_auth_for_monitoring else "false" + addon_profile.config[CONST_MONITORING_USING_AAD_MSI_AUTH] = ( + "true" if enable_msi_auth_for_monitoring else "false" + ) elif addon == (CONST_VIRTUAL_NODE_ADDON_NAME + os_type): if addon_profile.enabled: raise CLIError('The virtual-node addon is already enabled for this managed cluster.\n' @@ -1916,10 +2142,12 @@ def _update_addons(cmd, # pylint: disable=too-many-branches,too-many-statements addon_profile.config[CONST_ACC_SGX_QUOTE_HELPER_ENABLED] = "true" elif addon == CONST_AZURE_KEYVAULT_SECRETS_PROVIDER_ADDON_NAME: if addon_profile.enabled: - raise CLIError('The azure-keyvault-secrets-provider addon is already enabled for this managed cluster.\n' - 'To change azure-keyvault-secrets-provider configuration, run ' - f'"az aks disable-addons -a azure-keyvault-secrets-provider -n {name} -g {resource_group_name}" ' - 'before enabling it again.') + raise CLIError( + "The azure-keyvault-secrets-provider addon is already enabled for this managed cluster.\n" + 'To change azure-keyvault-secrets-provider configuration, run "az aks disable-addons ' + f'-a azure-keyvault-secrets-provider -n {name} -g {resource_group_name}" ' + "before enabling it again." + ) addon_profile = ManagedClusterAddonProfile( enabled=True, config={CONST_SECRET_ROTATION_ENABLED: "false", CONST_ROTATION_POLL_INTERVAL: "2m"}) if enable_secret_rotation: @@ -1936,8 +2164,7 @@ def _update_addons(cmd, # pylint: disable=too-many-branches,too-many-statements addon_profiles[addon] = ManagedClusterAddonProfile( enabled=False) else: - raise CLIError( - "The addon {} is not installed.".format(addon)) + raise CLIError(f"The addon {addon} is not installed.") addon_profiles[addon].config = None addon_profiles[addon].enabled = enable @@ -2096,7 +2323,14 @@ def aks_pod_identity_add( headers = get_aks_custom_headers(aks_custom_headers) # send the managed cluster represeentation to update the pod identity addon - return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, cluster_name, instance, headers=headers) + return sdk_no_wait( + no_wait, + client.begin_create_or_update, + resource_group_name, + cluster_name, + instance, + headers=headers + ) def aks_pod_identity_delete( @@ -2133,7 +2367,14 @@ def aks_pod_identity_delete( headers = get_aks_custom_headers(aks_custom_headers) # send the managed cluster represeentation to update the pod identity addon - return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, cluster_name, instance, headers=headers) + return sdk_no_wait( + no_wait, + client.begin_create_or_update, + resource_group_name, + cluster_name, + instance, + headers=headers + ) def aks_pod_identity_list(cmd, client, resource_group_name, cluster_name): # pylint: disable=unused-argument @@ -2181,7 +2422,14 @@ def aks_pod_identity_exception_add( headers = get_aks_custom_headers(aks_custom_headers) # send the managed cluster represeentation to update the pod identity addon - return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, cluster_name, instance, headers=headers) + return sdk_no_wait( + no_wait, + client.begin_create_or_update, + resource_group_name, + cluster_name, + instance, + headers=headers + ) def aks_pod_identity_exception_delete( @@ -2218,7 +2466,14 @@ def aks_pod_identity_exception_delete( headers = get_aks_custom_headers(aks_custom_headers) # send the managed cluster represeentation to update the pod identity addon - return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, cluster_name, instance, headers=headers) + return sdk_no_wait( + no_wait, + client.begin_create_or_update, + resource_group_name, + cluster_name, + instance, + headers=headers + ) def aks_pod_identity_exception_update( @@ -2254,8 +2509,7 @@ def aks_pod_identity_exception_update( pod_identity_exceptions.append(exc) if not found_target: - raise CLIError( - 'pod identity exception {}/{} not found'.format(exc_namespace, exc_name)) + raise CLIError(f"pod identity exception {exc_namespace}/{exc_name} not found") from azext_aks_preview.managed_cluster_decorator import AKSPreviewManagedClusterModels # store all the models used by pod identity @@ -2270,7 +2524,14 @@ def aks_pod_identity_exception_update( headers = get_aks_custom_headers(aks_custom_headers) # send the managed cluster represeentation to update the pod identity addon - return sdk_no_wait(no_wait, client.begin_create_or_update, resource_group_name, cluster_name, instance, headers=headers) + return sdk_no_wait( + no_wait, + client.begin_create_or_update, + resource_group_name, + cluster_name, + instance, + headers=headers, + ) def aks_pod_identity_exception_list(cmd, client, resource_group_name, cluster_name): @@ -2333,10 +2594,10 @@ def aks_snapshot_delete(cmd, # pylint: disable=unused-argument name, no_wait=False, yes=False): - - from knack.prompting import prompt_y_n - msg = 'This will delete the cluster snapshot "{}" in resource group "{}", Are you sure?'.format( - name, resource_group_name) + msg = ( + f'This will delete the cluster snapshot "{name}" in resource group "{resource_group_name}".\n' + "Are you sure?" + ) if not yes and not prompt_y_n(msg, default="n"): return None @@ -2414,10 +2675,10 @@ def aks_nodepool_snapshot_delete(cmd, # pylint: disable=unused-argument snapshot_name, no_wait=False, yes=False): - - from knack.prompting import prompt_y_n - msg = 'This will delete the nodepool snapshot "{}" in resource group "{}", Are you sure?'.format( - snapshot_name, resource_group_name) + msg = ( + f'This will delete the nodepool snapshot "{snapshot_name}" in resource group "{resource_group_name}".\n' + "Are you sure?" + ) if not yes and not prompt_y_n(msg, default="n"): return None @@ -2457,7 +2718,11 @@ def aks_trustedaccess_role_binding_create(cmd, client, resource_group_name, clus pass if existedBinding: - raise Exception("TrustedAccess RoleBinding " + role_binding_name + " already existed, please use 'az aks trustedaccess rolebinding update' command to update!") + raise Exception( # pylint: disable=broad-exception-raised + "TrustedAccess RoleBinding " + + role_binding_name + + " already existed, please use 'az aks trustedaccess rolebinding update' command to update!" + ) roleList = roles.split(',') roleBinding = TrustedAccessRoleBinding(source_resource_id=source_resource_id, roles=roleList) @@ -2482,34 +2747,51 @@ def aks_trustedaccess_role_binding_delete(cmd, client, resource_group_name, clus def aks_mesh_enable( + cmd, + client, + resource_group_name, + name, + revision=None, + key_vault_id=None, + ca_cert_object_name=None, + ca_key_object_name=None, + root_cert_object_name=None, + cert_chain_object_name=None, +): + instance = client.get(resource_group_name, name) + addon_profiles = instance.addon_profiles + if ( + key_vault_id is not None and + ca_cert_object_name is not None and + ca_key_object_name is not None and + root_cert_object_name is not None and + cert_chain_object_name is not None + ): + if ( + not addon_profiles or + not addon_profiles[CONST_AZURE_KEYVAULT_SECRETS_PROVIDER_ADDON_NAME] or + not addon_profiles[ + CONST_AZURE_KEYVAULT_SECRETS_PROVIDER_ADDON_NAME + ].enabled + ): + raise CLIError( + "AzureKeyvaultSecretsProvider addon is required for Azure Service Mesh plugin " + "certificate authority feature." + ) + + return _aks_mesh_update( cmd, client, resource_group_name, name, - revision=None, - key_vault_id=None, - ca_cert_object_name=None, - ca_key_object_name=None, - root_cert_object_name=None, - cert_chain_object_name=None -): - instance = client.get(resource_group_name, name) - addon_profiles = instance.addon_profiles - if key_vault_id is not None and ca_cert_object_name is not None and ca_key_object_name is not None and root_cert_object_name is not None and cert_chain_object_name is not None: - if not addon_profiles or not addon_profiles[CONST_AZURE_KEYVAULT_SECRETS_PROVIDER_ADDON_NAME] or not addon_profiles[CONST_AZURE_KEYVAULT_SECRETS_PROVIDER_ADDON_NAME].enabled: - raise CLIError('AzureKeyvaultSecretsProvider addon is required for Azure Service Mesh plugin certificate authority feature.') - - return _aks_mesh_update(cmd, - client, - resource_group_name, - name, - key_vault_id, - ca_cert_object_name, - ca_key_object_name, - root_cert_object_name, - cert_chain_object_name, - revision=revision, - enable_azure_service_mesh=True) + key_vault_id, + ca_cert_object_name, + ca_key_object_name, + root_cert_object_name, + cert_chain_object_name, + revision=revision, + enable_azure_service_mesh=True, + ) def aks_mesh_disable( @@ -2599,8 +2881,7 @@ def aks_mesh_get_revisions( if revisions: return revisions[0].properties - else: - return None + return None def aks_mesh_get_upgrades( @@ -2619,8 +2900,7 @@ def aks_mesh_get_upgrades( if upgrades: return upgrades[0].properties - else: - return None + return None def aks_mesh_upgrade_start( @@ -2666,6 +2946,7 @@ def aks_mesh_upgrade_rollback( mesh_upgrade_command=CONST_AZURE_SERVICE_MESH_UPGRADE_COMMAND_ROLLBACK) +# pylint: disable=unused-argument def _aks_mesh_update( cmd, client, @@ -2836,6 +3117,7 @@ def aks_approuting_zone_list( raise CLIError('App routing addon is not enabled') +# pylint: disable=unused-argument def _aks_approuting_update( cmd, client, @@ -2909,14 +3191,29 @@ def _keyvault_update( try: if keyvault.properties.enable_rbac_authorization: - if not add_role_assignment(cmd, 'Key Vault Secrets User', managed_identity_object_id, is_service_principal, scope=keyvault_id): + if not add_role_assignment( + cmd, + "Key Vault Secrets User", + managed_identity_object_id, + is_service_principal, + scope=keyvault_id, + ): logger.warning( - 'Could not create a role assignment for App Routing. ' - 'Are you an Owner on this subscription?') + "Could not create a role assignment for App Routing. " + "Are you an Owner on this subscription?" + ) else: - keyvault = set_policy(cmd, keyvault_client, keyvault_rg, keyvault_name, object_id=managed_identity_object_id, secret_permissions=['Get'], certificate_permissions=['Get']) + keyvault = set_policy( + cmd, + keyvault_client, + keyvault_rg, + keyvault_name, + object_id=managed_identity_object_id, + secret_permissions=["Get"], + certificate_permissions=["Get"], + ) except Exception as ex: - raise CLIError(f'Error in granting keyvault permissions to managed identity: {ex}\n') + raise CLIError('Error in granting keyvault permissions to managed identity.\n') from ex else: raise CLIError('App Routing is not enabled.\n') diff --git a/src/aks-preview/azext_aks_preview/maintenanceconfiguration.py b/src/aks-preview/azext_aks_preview/maintenanceconfiguration.py index b8783be410e..5dbd708189c 100644 --- a/src/aks-preview/azext_aks_preview/maintenanceconfiguration.py +++ b/src/aks-preview/azext_aks_preview/maintenanceconfiguration.py @@ -4,7 +4,6 @@ # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- -from knack.util import CLIError from knack.log import get_logger from azure.cli.core.util import get_file_json from azure.cli.core.azclierror import ( @@ -33,7 +32,12 @@ def aks_maintenanceconfiguration_update_internal(cmd, client, raw_parameters): cluster_name = raw_parameters.get("cluster_name") config_name = raw_parameters.get("config_name") config = getMaintenanceConfiguration(cmd, raw_parameters) - return client.create_or_update(resource_group_name=resource_group_name, resource_name=cluster_name, config_name=config_name, parameters=config) + return client.create_or_update( + resource_group_name=resource_group_name, + resource_name=cluster_name, + config_name=config_name, + parameters=config + ) def getMaintenanceConfiguration(cmd, raw_parameters): @@ -46,10 +50,12 @@ def getMaintenanceConfiguration(cmd, raw_parameters): config_name = raw_parameters.get("config_name") if config_name == CONST_DEFAULT_CONFIGURATION_NAME: return constructDefaultMaintenanceConfiguration(cmd, raw_parameters) - elif config_name == CONST_AUTOUPGRADE_CONFIGURATION_NAME or config_name == CONST_NODEOSUPGRADE_CONFIGURATION_NAME: + if config_name in (CONST_AUTOUPGRADE_CONFIGURATION_NAME, CONST_NODEOSUPGRADE_CONFIGURATION_NAME): return constructDedicatedMaintenanceConfiguration(cmd, raw_parameters) - else: - raise InvalidArgumentValueError('--config-name must be one of default, aksManagedAutoUpgradeSchedule or aksManagedNodeOSUpgradeSchedule, not {}'.format(config_name)) + raise InvalidArgumentValueError( + "--config-name must be one of default, aksManagedAutoUpgradeSchedule or " + f"aksManagedNodeOSUpgradeSchedule, not {config_name}" + ) def constructDefaultMaintenanceConfiguration(cmd, raw_parameters): @@ -58,17 +64,28 @@ def constructDefaultMaintenanceConfiguration(cmd, raw_parameters): schedule_type = raw_parameters.get("schedule_type") if weekday is None or start_hour is None: - raise RequiredArgumentMissingError('Please specify --weekday and --start-hour for default maintenance configuration, or use --config-file instead.') + raise RequiredArgumentMissingError( + "Please specify --weekday and --start-hour for default maintenance configuration, " + "or use --config-file instead." + ) if schedule_type is not None: - raise MutuallyExclusiveArgumentError('--schedule-type is not supported for default maintenance configuration.') + raise MutuallyExclusiveArgumentError("--schedule-type is not supported for default maintenance configuration.") - MaintenanceConfiguration = cmd.get_models('MaintenanceConfiguration', resource_type=CUSTOM_MGMT_AKS_PREVIEW, operation_group='maintenance_configurations') - TimeInWeek = cmd.get_models('TimeInWeek', resource_type=CUSTOM_MGMT_AKS_PREVIEW, operation_group='maintenance_configurations') + MaintenanceConfiguration = cmd.get_models( + "MaintenanceConfiguration", + resource_type=CUSTOM_MGMT_AKS_PREVIEW, + operation_group="maintenance_configurations" + ) + TimeInWeek = cmd.get_models( + "TimeInWeek", + resource_type=CUSTOM_MGMT_AKS_PREVIEW, + operation_group="maintenance_configurations" + ) - dict = {} - dict["day"] = weekday - dict["hour_slots"] = [start_hour] - timeInWeek = TimeInWeek(**dict) + time_in_week_config = {} + time_in_week_config["day"] = weekday + time_in_week_config["hour_slots"] = [start_hour] + timeInWeek = TimeInWeek(**time_in_week_config) result = MaintenanceConfiguration() result.time_in_week = [timeInWeek] result.not_allowed_time = [] @@ -79,9 +96,15 @@ def constructDedicatedMaintenanceConfiguration(cmd, raw_parameters): weekday = raw_parameters.get("weekday") start_hour = raw_parameters.get("start_hour") if weekday is not None or start_hour is not None: - raise MutuallyExclusiveArgumentError('--weekday and --start-hour are only applicable to default maintenance configuration.') - - maintenanceConfiguration = cmd.get_models('MaintenanceConfiguration', resource_type=CUSTOM_MGMT_AKS_PREVIEW, operation_group='maintenance_configurations') + raise MutuallyExclusiveArgumentError( + "--weekday and --start-hour are only applicable to default maintenance configuration." + ) + + maintenanceConfiguration = cmd.get_models( + "MaintenanceConfiguration", + resource_type=CUSTOM_MGMT_AKS_PREVIEW, + operation_group="maintenance_configurations" + ) result = maintenanceConfiguration() result.maintenance_window = constructMaintenanceWindow(cmd, raw_parameters) return result @@ -99,7 +122,11 @@ def constructMaintenanceWindow(cmd, raw_parameters): if duration_hours is None: raise RequiredArgumentMissingError('Please specify --duration for maintenance window.') - MaintenanceWindow = cmd.get_models('MaintenanceWindow', resource_type=CUSTOM_MGMT_AKS_PREVIEW, operation_group='maintenance_configurations') + MaintenanceWindow = cmd.get_models( + "MaintenanceWindow", + resource_type=CUSTOM_MGMT_AKS_PREVIEW, + operation_group="maintenance_configurations" + ) maintenanceWindow = MaintenanceWindow( schedule=schedule, start_date=start_date, @@ -119,29 +146,82 @@ def constructSchedule(cmd, raw_parameters): day_of_month = raw_parameters.get("day_of_month") week_index = raw_parameters.get("week_index") - Schedule = cmd.get_models('Schedule', resource_type=CUSTOM_MGMT_AKS_PREVIEW, operation_group='maintenance_configurations') + Schedule = cmd.get_models( + "Schedule", + resource_type=CUSTOM_MGMT_AKS_PREVIEW, + operation_group="maintenance_configurations" + ) schedule = Schedule() if schedule_type == CONST_DAILY_MAINTENANCE_SCHEDULE: - schedule.daily = constructDailySchedule(cmd, interval_days, interval_weeks, interval_months, day_of_week, day_of_month, week_index) + schedule.daily = constructDailySchedule( + cmd, + interval_days, + interval_weeks, + interval_months, + day_of_week, + day_of_month, + week_index + ) elif schedule_type == CONST_WEEKLY_MAINTENANCE_SCHEDULE: - schedule.weekly = constructWeeklySchedule(cmd, interval_days, interval_weeks, interval_months, day_of_week, day_of_month, week_index) + schedule.weekly = constructWeeklySchedule( + cmd, + interval_days, + interval_weeks, + interval_months, + day_of_week, + day_of_month, + week_index + ) elif schedule_type == CONST_ABSOLUTEMONTHLY_MAINTENANCE_SCHEDULE: - schedule.absolute_monthly = constructAbsoluteMonthlySchedule(cmd, interval_days, interval_weeks, interval_months, day_of_week, day_of_month, week_index) + schedule.absolute_monthly = constructAbsoluteMonthlySchedule( + cmd, + interval_days, + interval_weeks, + interval_months, + day_of_week, + day_of_month, + week_index + ) elif schedule_type == CONST_RELATIVEMONTHLY_MAINTENANCE_SCHEDULE: - schedule.relative_monthly = constructRelativeMonthlySchedule(cmd, interval_days, interval_weeks, interval_months, day_of_week, day_of_month, week_index) + schedule.relative_monthly = constructRelativeMonthlySchedule( + cmd, + interval_days, + interval_weeks, + interval_months, + day_of_week, + day_of_month, + week_index + ) else: - raise InvalidArgumentValueError('--schedule-type must be one of Daily, Weekly, AbsoluteMonthly or RelativeMonthly.') + raise InvalidArgumentValueError( + "--schedule-type must be one of Daily, Weekly, AbsoluteMonthly or RelativeMonthly." + ) return schedule def constructDailySchedule(cmd, interval_days, interval_weeks, interval_months, day_of_week, day_of_month, week_index): if interval_days is None: - raise RequiredArgumentMissingError("Please specify --interval-days when using daily schedule.") - if interval_weeks is not None or interval_months is not None or day_of_week is not None or day_of_month is not None or week_index is not None: - raise MutuallyExclusiveArgumentError('--interval-weeks, --interval-months, --day-of-week, --day-of-month and --week-index cannot be used for Daily schedule.') - - DailySchedule = cmd.get_models('DailySchedule', resource_type=CUSTOM_MGMT_AKS_PREVIEW, operation_group='maintenance_configurations') + raise RequiredArgumentMissingError( + "Please specify --interval-days when using daily schedule." + ) + if ( + interval_weeks is not None or + interval_months is not None or + day_of_week is not None or + day_of_month is not None or + week_index is not None + ): + raise MutuallyExclusiveArgumentError( + "--interval-weeks, --interval-months, --day-of-week, --day-of-month and " + "--week-index cannot be used for Daily schedule." + ) + + DailySchedule = cmd.get_models( + "DailySchedule", + resource_type=CUSTOM_MGMT_AKS_PREVIEW, + operation_group="maintenance_configurations" + ) dailySchedule = DailySchedule( interval_days=interval_days ) @@ -150,11 +230,19 @@ def constructDailySchedule(cmd, interval_days, interval_weeks, interval_months, def constructWeeklySchedule(cmd, interval_days, interval_weeks, interval_months, day_of_week, day_of_month, week_index): if interval_weeks is None or day_of_week is None: - raise RequiredArgumentMissingError("Please specify --interval-weeks and --day-of-week when using weekly schedule.") + raise RequiredArgumentMissingError( + "Please specify --interval-weeks and --day-of-week when using weekly schedule." + ) if interval_days is not None or interval_months is not None or day_of_month is not None or week_index is not None: - raise MutuallyExclusiveArgumentError('--interval-months, --day-of-month and --week-index cannot be used for Weekly schedule.') - - WeeklySchedule = cmd.get_models('WeeklySchedule', resource_type=CUSTOM_MGMT_AKS_PREVIEW, operation_group='maintenance_configurations') + raise MutuallyExclusiveArgumentError( + "--interval-months, --day-of-month and --week-index cannot be used for Weekly schedule." + ) + + WeeklySchedule = cmd.get_models( + "WeeklySchedule", + resource_type=CUSTOM_MGMT_AKS_PREVIEW, + operation_group="maintenance_configurations" + ) weeklySchedule = WeeklySchedule( interval_weeks=interval_weeks, day_of_week=day_of_week @@ -162,13 +250,30 @@ def constructWeeklySchedule(cmd, interval_days, interval_weeks, interval_months, return weeklySchedule -def constructAbsoluteMonthlySchedule(cmd, interval_days, interval_weeks, interval_months, day_of_week, day_of_month, week_index): +def constructAbsoluteMonthlySchedule( + cmd, + interval_days, + interval_weeks, + interval_months, + day_of_week, + day_of_month, + week_index +): if interval_months is None or day_of_month is None: - raise RequiredArgumentMissingError("Please specify --interval-months and --day-of-month when using absolute monthly schedule.") + raise RequiredArgumentMissingError( + "Please specify --interval-months and --day-of-month when using absolute monthly schedule." + ) if interval_days is not None or interval_weeks is not None or day_of_week is not None or week_index is not None: - raise MutuallyExclusiveArgumentError('--interval-days, --interval-weeks, --day-of-week and --week-index cannot be used for AbsoluteMonthly schedule.') - - AbsoluteMonthlySchedule = cmd.get_models('AbsoluteMonthlySchedule', resource_type=CUSTOM_MGMT_AKS_PREVIEW, operation_group='maintenance_configurations') + raise MutuallyExclusiveArgumentError( + "--interval-days, --interval-weeks, --day-of-week and --week-index cannot be used for " + "AbsoluteMonthly schedule." + ) + + AbsoluteMonthlySchedule = cmd.get_models( + 'AbsoluteMonthlySchedule', + resource_type=CUSTOM_MGMT_AKS_PREVIEW, + operation_group='maintenance_configurations' + ) absoluteMonthlySchedule = AbsoluteMonthlySchedule( interval_months=interval_months, day_of_month=day_of_month @@ -176,13 +281,29 @@ def constructAbsoluteMonthlySchedule(cmd, interval_days, interval_weeks, interva return absoluteMonthlySchedule -def constructRelativeMonthlySchedule(cmd, interval_days, interval_weeks, interval_months, day_of_week, day_of_month, week_index): +def constructRelativeMonthlySchedule( + cmd, + interval_days, + interval_weeks, + interval_months, + day_of_week, + day_of_month, + week_index +): if interval_months is None or day_of_week is None or week_index is None: - raise RequiredArgumentMissingError("Please specify --interval-months, --day-of-week and --week-index when using relative monthly schedule.") + raise RequiredArgumentMissingError( + "Please specify --interval-months, --day-of-week and --week-index when using relative monthly schedule." + ) if interval_days is not None or interval_weeks is not None or day_of_month is not None: - raise MutuallyExclusiveArgumentError('--interval-days, --interval-weeks and --day-of-month cannot be used for RelativeMonthly schedule.') - - RelativeMonthlySchedule = cmd.get_models('RelativeMonthlySchedule', resource_type=CUSTOM_MGMT_AKS_PREVIEW, operation_group='maintenance_configurations') + raise MutuallyExclusiveArgumentError( + "--interval-days, --interval-weeks and --day-of-month cannot be used for RelativeMonthly schedule." + ) + + RelativeMonthlySchedule = cmd.get_models( + 'RelativeMonthlySchedule', + resource_type=CUSTOM_MGMT_AKS_PREVIEW, + operation_group='maintenance_configurations' + ) relativeMonthlySchedule = RelativeMonthlySchedule( interval_months=interval_months, day_of_week=day_of_week, diff --git a/src/aks-preview/azext_aks_preview/managed_cluster_decorator.py b/src/aks-preview/azext_aks_preview/managed_cluster_decorator.py index 470c866ffd1..cf79f6de9d6 100644 --- a/src/aks-preview/azext_aks_preview/managed_cluster_decorator.py +++ b/src/aks-preview/azext_aks_preview/managed_cluster_decorator.py @@ -3,86 +3,39 @@ # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- +# pylint: disable=too-many-lines import copy import datetime import os -import semver from types import SimpleNamespace from typing import Any, Dict, List, Optional, Tuple, TypeVar, Union -from knack.util import CLIError - -from azure.mgmt.containerservice.models import KubernetesSupportPlan - -from azure.cli.command_modules.acs._consts import ( - DecoratorEarlyExitException, - DecoratorMode, - CONST_OUTBOUND_TYPE_LOAD_BALANCER, - CONST_OUTBOUND_TYPE_MANAGED_NAT_GATEWAY, - CONST_OUTBOUND_TYPE_USER_ASSIGNED_NAT_GATEWAY, - CONST_OUTBOUND_TYPE_USER_DEFINED_ROUTING, -) -from azure.cli.command_modules.acs._helpers import ( - check_is_msi_cluster, - format_parameter_name_to_option_name, - safe_lower, -) -from azure.cli.command_modules.acs._validators import ( - extract_comma_separated_string, -) -from azext_aks_preview.azuremonitormetrics.azuremonitorprofile import ( - ensure_azure_monitor_profile_prerequisites -) -from azext_aks_preview.azurecontainerstorage.acstor_ops import ( - perform_enable_azure_container_storage, - perform_disable_azure_container_storage, -) -from azure.cli.command_modules.acs.managed_cluster_decorator import ( - AKSManagedClusterContext, - AKSManagedClusterCreateDecorator, - AKSManagedClusterModels, - AKSManagedClusterParamDict, - AKSManagedClusterUpdateDecorator, -) -from azure.cli.core import AzCommandsLoader -from azure.cli.core.azclierror import ( - ArgumentUsageError, - InvalidArgumentValueError, - MutuallyExclusiveArgumentError, - RequiredArgumentMissingError, - UnknownError, -) -from azure.cli.core.commands import AzCliCommand -from azure.cli.core.profiles import ResourceType -from azure.cli.core.util import get_file_json -from azure.cli.core.util import read_file_content -from knack.log import get_logger -from knack.prompting import prompt_y_n +import semver from azext_aks_preview._consts import ( + CONST_AZURE_KEYVAULT_SECRETS_PROVIDER_ADDON_NAME, CONST_AZURE_SERVICE_MESH_MODE_DISABLED, CONST_AZURE_SERVICE_MESH_MODE_ISTIO, + CONST_AZURE_SERVICE_MESH_UPGRADE_COMMAND_COMPLETE, + CONST_AZURE_SERVICE_MESH_UPGRADE_COMMAND_ROLLBACK, + CONST_AZURE_SERVICE_MESH_UPGRADE_COMMAND_START, CONST_LOAD_BALANCER_SKU_BASIC, CONST_MANAGED_CLUSTER_SKU_TIER_FREE, - CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD, CONST_MANAGED_CLUSTER_SKU_TIER_PREMIUM, + CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD, + CONST_NETWORK_DATAPLANE_CILIUM, CONST_NETWORK_PLUGIN_AZURE, CONST_NETWORK_PLUGIN_MODE_OVERLAY, - CONST_NETWORK_DATAPLANE_CILIUM, CONST_NETWORK_POLICY_CILIUM, CONST_PRIVATE_DNS_ZONE_NONE, CONST_PRIVATE_DNS_ZONE_SYSTEM, - CONST_AZURE_KEYVAULT_SECRETS_PROVIDER_ADDON_NAME, - CONST_SECRET_ROTATION_ENABLED, CONST_ROTATION_POLL_INTERVAL, - CONST_AZURE_SERVICE_MESH_UPGRADE_COMMAND_START, - CONST_AZURE_SERVICE_MESH_UPGRADE_COMMAND_COMPLETE, - CONST_AZURE_SERVICE_MESH_UPGRADE_COMMAND_ROLLBACK, + CONST_SECRET_ROTATION_ENABLED, ) from azext_aks_preview._helpers import ( - check_is_private_cluster, check_is_apiserver_vnet_integration_cluster, + check_is_private_cluster, get_cluster_snapshot_by_snapshot_id, - setup_common_guardrails_profile + setup_common_guardrails_profile, ) from azext_aks_preview._loadbalancer import create_load_balancer_profile from azext_aks_preview._loadbalancer import ( @@ -93,14 +46,57 @@ _is_pod_identity_addon_enabled, _update_addon_pod_identity, ) +from azext_aks_preview._roleassignments import add_role_assignment from azext_aks_preview.agentpool_decorator import ( AKSPreviewAgentPoolAddDecorator, AKSPreviewAgentPoolUpdateDecorator, ) -from azext_aks_preview._roleassignments import add_role_assignment -from msrestazure.tools import is_valid_resource_id, parse_resource_id - +from azext_aks_preview.azurecontainerstorage.acstor_ops import ( + perform_disable_azure_container_storage, + perform_enable_azure_container_storage, +) +from azext_aks_preview.azuremonitormetrics.azuremonitorprofile import ( + ensure_azure_monitor_profile_prerequisites, +) +from azure.cli.command_modules.acs._consts import ( + CONST_OUTBOUND_TYPE_LOAD_BALANCER, + CONST_OUTBOUND_TYPE_MANAGED_NAT_GATEWAY, + CONST_OUTBOUND_TYPE_USER_ASSIGNED_NAT_GATEWAY, + CONST_OUTBOUND_TYPE_USER_DEFINED_ROUTING, + DecoratorEarlyExitException, + DecoratorMode, +) +from azure.cli.command_modules.acs._helpers import ( + check_is_msi_cluster, + 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.managed_cluster_decorator import ( + AKSManagedClusterContext, + AKSManagedClusterCreateDecorator, + AKSManagedClusterModels, + AKSManagedClusterParamDict, + AKSManagedClusterUpdateDecorator, +) +from azure.cli.core import AzCommandsLoader +from azure.cli.core.azclierror import ( + ArgumentUsageError, + InvalidArgumentValueError, + MutuallyExclusiveArgumentError, + RequiredArgumentMissingError, + UnknownError, +) +from azure.cli.core.commands import AzCliCommand +from azure.cli.core.profiles import ResourceType +from azure.cli.core.util import get_file_json, read_file_content +from azure.mgmt.containerservice.models import KubernetesSupportPlan from dateutil.parser import parse +from knack.log import get_logger +from knack.prompting import prompt_y_n +from knack.util import CLIError +from msrestazure.tools import is_valid_resource_id + logger = get_logger(__name__) @@ -149,12 +145,17 @@ def pod_identity_models(self) -> SimpleNamespace: """ if self.__pod_identity_models is None: pod_identity_models = {} - pod_identity_models["ManagedClusterPodIdentityProfile"] = self.ManagedClusterPodIdentityProfile - pod_identity_models["ManagedClusterPodIdentityException"] = self.ManagedClusterPodIdentityException + pod_identity_models["ManagedClusterPodIdentityProfile"] = ( + self.ManagedClusterPodIdentityProfile # pylint: disable=no-member + ) + pod_identity_models["ManagedClusterPodIdentityException"] = ( + self.ManagedClusterPodIdentityException # pylint: disable=no-member + ) self.__pod_identity_models = SimpleNamespace(**pod_identity_models) return self.__pod_identity_models +# pylint: disable=too-many-public-methods class AKSPreviewManagedClusterContext(AKSManagedClusterContext): def __init__( self, @@ -192,7 +193,6 @@ def get_guardrails_excluded_namespaces(self) -> Union[str, None]: def get_guardrails_version(self) -> Union[str, None]: return self.raw_param.get("guardrails_version") - # pylint: disable=no-self-use def __validate_pod_identity_with_kubenet(self, mc, enable_pod_identity, enable_pod_identity_with_kubenet): """Helper function to check the validity of serveral pod identity related parameters. @@ -343,6 +343,7 @@ def _get_outbound_type( # validation # Note: The parameters involved in the validation are not verified in their own getters. + # pylint: disable=too-many-nested-blocks if enable_validation: if outbound_type in [ CONST_OUTBOUND_TYPE_USER_DEFINED_ROUTING, @@ -364,7 +365,10 @@ def _get_outbound_type( "be pre-configured with a route table with egress rules" ) - if self.decorator_mode == DecoratorMode.CREATE and outbound_type == CONST_OUTBOUND_TYPE_USER_DEFINED_ROUTING: + if ( + self.decorator_mode == DecoratorMode.CREATE and + outbound_type == CONST_OUTBOUND_TYPE_USER_DEFINED_ROUTING + ): if load_balancer_profile: if ( load_balancer_profile.managed_outbound_i_ps or @@ -627,6 +631,7 @@ def get_enable_network_observability(self) -> Optional[bool]: return enable_network_observability if disable_network_observability is not None: return not disable_network_observability + return None def get_load_balancer_managed_outbound_ip_count(self) -> Union[int, None]: """Obtain the value of load_balancer_managed_outbound_ip_count. @@ -711,17 +716,13 @@ def get_kube_proxy_config(self) -> Union[Dict, ContainerServiceNetworkProfileKub if kube_proxy_config_file_path: if not os.path.isfile(kube_proxy_config_file_path): raise InvalidArgumentValueError( - "{} is not valid file, or not accessible.".format( - kube_proxy_config_file_path - ) + f"{kube_proxy_config_file_path} is not valid file, or not accessible." ) kube_proxy_config = get_file_json(kube_proxy_config_file_path) if not isinstance(kube_proxy_config, dict): raise InvalidArgumentValueError( - "Error reading kube-proxy config from {}. " - "Please see https://aka.ms/KubeProxyConfig for correct format.".format( - kube_proxy_config_file_path - ) + f"Error reading kube-proxy config from {kube_proxy_config_file_path}. " + "Please see https://aka.ms/KubeProxyConfig for correct format." ) # try to read the property value corresponding to the parameter from the `mc` object @@ -1039,7 +1040,7 @@ def get_workload_identity_profile(self) -> Optional[ManagedClusterSecurityProfil if not hasattr(self.models, "ManagedClusterSecurityProfileWorkloadIdentity"): raise UnknownError("Workload Identity's data model not found") - profile = self.models.ManagedClusterSecurityProfileWorkloadIdentity() + profile = self.models.ManagedClusterSecurityProfileWorkloadIdentity() # pylint: disable=no-member if self.decorator_mode == DecoratorMode.UPDATE: if self.mc.security_profile is not None and self.mc.security_profile.workload_identity is not None: @@ -1196,7 +1197,7 @@ def get_disk_driver(self) -> Optional[ManagedClusterStorageProfileDiskCSIDriver] if not enable_disk_driver and not disable_disk_driver and not disk_driver_version: return None - profile = self.models.ManagedClusterStorageProfileDiskCSIDriver() + profile = self.models.ManagedClusterStorageProfileDiskCSIDriver() # pylint: disable=no-member if enable_disk_driver and disable_disk_driver: raise MutuallyExclusiveArgumentError( @@ -1338,7 +1339,8 @@ def _get_enable_private_cluster(self, enable_validation: bool = False) -> bool: This function supports the option of enable_validation during update. When enable_private_cluster is specified, if api_server_authorized_ip_ranges is assigned, raise an MutuallyExclusiveArgumentError; - When enable_private_cluster is not specified, disable_public_fqdn, enable_public_fqdn or private_dns_zone is assigned, raise an InvalidArgumentValueError. + When enable_private_cluster is not specified, disable_public_fqdn, enable_public_fqdn or private_dns_zone + is assigned, raise an InvalidArgumentValueError. For UPDATE: if existing cluster is not using apiserver vnet integration, raise an ArgumentUsageError; @@ -1407,7 +1409,8 @@ def _get_enable_private_cluster(self, enable_validation: bool = False) -> bool: if enable_private_cluster and not enable_apiserver_vnet_integration: if not is_apiserver_vnet_integration_cluster: raise ArgumentUsageError( - "Enabling private cluster requires enabling apiserver vnet integration(--enable-apiserver-vnet-integration)." + "Enabling private cluster requires enabling apiserver vnet integration" + "(--enable-apiserver-vnet-integration)." ) return enable_private_cluster @@ -1416,7 +1419,8 @@ def get_enable_private_cluster(self) -> bool: """Obtain the value of enable_private_cluster. This function will verify the parameter by default. When enable_private_cluster is specified, - For UPDATE: if enable-apiserver-vnet-integration is not used and existing cluster is not using apiserver vnet integration, raise an ArgumentUsageError + For UPDATE: if enable-apiserver-vnet-integration is not used and existing cluster is not using + apiserver vnet integration, raise an ArgumentUsageError :return: bool """ @@ -1450,9 +1454,13 @@ def _get_disable_private_cluster(self, enable_validation: bool = False) -> bool: ) # new validation added for apiserver vnet integration if disable_private_cluster and not enable_apiserver_vnet_integration: - if self.mc.api_server_access_profile is None or self.mc.api_server_access_profile.enable_vnet_integration is not True: + if ( + self.mc.api_server_access_profile is None or + self.mc.api_server_access_profile.enable_vnet_integration is not True + ): raise ArgumentUsageError( - "Disabling private cluster requires enabling apiserver vnet integration(--enable-apiserver-vnet-integration)." + "Disabling private cluster requires enabling apiserver vnet integration" + "(--enable-apiserver-vnet-integration)." ) return disable_private_cluster @@ -1461,7 +1469,8 @@ def get_disable_private_cluster(self) -> bool: """Obtain the value of disable_private_cluster. This function will verify the parameter by default. When disable_private_cluster is specified, - For UPDATE: if enable-apiserver-vnet-integration is not used and existing cluster is not using apiserver vnet integration, raise an ArgumentUsageError + For UPDATE: if enable-apiserver-vnet-integration is not used and existing cluster is not using + apiserver vnet integration, raise an ArgumentUsageError :return: bool """ @@ -1504,8 +1513,10 @@ def _get_disable_public_fqdn(self, enable_validation: bool = False) -> bool: "Cannot specify '--enable-public-fqdn' and '--disable-public-fqdn' at the same time" ) if ( - safe_lower(self._get_private_dns_zone(enable_validation=False)) == CONST_PRIVATE_DNS_ZONE_NONE or - safe_lower(self.mc.api_server_access_profile.private_dns_zone) == CONST_PRIVATE_DNS_ZONE_NONE + safe_lower(self._get_private_dns_zone(enable_validation=False)) == + CONST_PRIVATE_DNS_ZONE_NONE or + safe_lower(self.mc.api_server_access_profile.private_dns_zone) == + CONST_PRIVATE_DNS_ZONE_NONE ): raise InvalidArgumentValueError( "--disable-public-fqdn cannot be applied for none mode private dns zone cluster" @@ -1817,25 +1828,22 @@ def get_custom_ca_trust_certificates(self) -> Union[List[bytes], None]: return None if not os.path.isfile(custom_ca_certs_file_path): raise InvalidArgumentValueError( - "{} is not valid file, or not accessible.".format( - custom_ca_certs_file_path - ) + f"{custom_ca_certs_file_path} is not valid file, or not accessible." ) - # CAs are supposed to be separated with a new line, we filter out empty strings (e.g. some stray new line). We only allow up to 10 CAs + # CAs are supposed to be separated with a new line, we filter out empty strings (e.g. some stray new line). + # We only allow up to 10 CAs file_content = read_file_content(custom_ca_certs_file_path).split(os.linesep + os.linesep) certs = [str.encode(x) for x in file_content if len(x) > 1] if len(certs) > 10: raise InvalidArgumentValueError( - "Only up to 10 new-line separated CAs can be passed, got {} instead.".format( - len(certs) - ) + f"Only up to 10 new-line separated CAs can be passed, got {len(certs)} instead." ) return certs def _get_enable_node_restriction(self, enable_validation: bool = False) -> bool: """Internal function to obtain the value of enable_node_restriction. - This function supports the option of enable_node_restriction. When enabled, if both enable_node_restriction and disable_node_restriction are - specified, raise a MutuallyExclusiveArgumentError. + This function supports the option of enable_node_restriction. When enabled, if both enable_node_restriction and + disable_node_restriction are specified, raise a MutuallyExclusiveArgumentError. :return: bool """ @@ -1853,14 +1861,17 @@ def _get_enable_node_restriction(self, enable_validation: bool = False) -> bool: def _get_enable_azure_monitor_metrics(self, enable_validation: bool = False) -> bool: """Internal function to obtain the value of enable_azure_monitor_metrics. - This function supports the option of enable_validation. When enabled, if both enable_azure_monitor_metrics and disable_azure_monitor_metrics are - specified, raise a MutuallyExclusiveArgumentError. + This function supports the option of enable_validation. When enabled, if both enable_azure_monitor_metrics and + disable_azure_monitor_metrics are specified, raise a MutuallyExclusiveArgumentError. :return: bool """ # Read the original value passed by the command. # TODO: should remove get value from enable_azuremonitormetrics once the option is removed - enable_azure_monitor_metrics = self.raw_param.get("enable_azure_monitor_metrics") or self.raw_param.get("enable_azuremonitormetrics") + enable_azure_monitor_metrics = ( + self.raw_param.get("enable_azure_monitor_metrics") or + self.raw_param.get("enable_azuremonitormetrics") + ) # In create mode, try to read the property value corresponding to the parameter from the `mc` object. if self.decorator_mode == DecoratorMode.CREATE: if ( @@ -1883,29 +1894,34 @@ def _get_enable_azure_monitor_metrics(self, enable_validation: bool = False) -> def get_enable_azure_monitor_metrics(self) -> bool: """Obtain the value of enable_azure_monitor_metrics. - This function will verify the parameter by default. If both enable_azure_monitor_metrics and disable_azure_monitor_metrics are specified, raise a - MutuallyExclusiveArgumentError. + This function will verify the parameter by default. If both enable_azure_monitor_metrics and + disable_azure_monitor_metrics are specified, raise a MutuallyExclusiveArgumentError. :return: bool """ return self._get_enable_azure_monitor_metrics(enable_validation=True) def _get_disable_azure_monitor_metrics(self, enable_validation: bool = False) -> bool: """Internal function to obtain the value of disable_azure_monitor_metrics. - This function supports the option of enable_validation. When enabled, if both enable_azure_monitor_metrics and disable_azure_monitor_metrics are - specified, raise a MutuallyExclusiveArgumentError. + This function supports the option of enable_validation. When enabled, if both enable_azure_monitor_metrics and + disable_azure_monitor_metrics are specified, raise a MutuallyExclusiveArgumentError. :return: bool """ # Read the original value passed by the command. # TODO: should remove get value from disable_azuremonitormetrics once the option is removed - disable_azure_monitor_metrics = self.raw_param.get("disable_azure_monitor_metrics") or self.raw_param.get("disable_azuremonitormetrics") + disable_azure_monitor_metrics = ( + self.raw_param.get("disable_azure_monitor_metrics") or + self.raw_param.get("disable_azuremonitormetrics") + ) if disable_azure_monitor_metrics and self._get_enable_azure_monitor_metrics(False): - raise MutuallyExclusiveArgumentError("Cannot specify --enable-azuremonitormetrics and --disable-azuremonitormetrics at the same time.") + raise MutuallyExclusiveArgumentError( + "Cannot specify --enable-azuremonitormetrics and --disable-azuremonitormetrics at the same time." + ) return disable_azure_monitor_metrics def get_disable_azure_monitor_metrics(self) -> bool: """Obtain the value of disable_azure_monitor_metrics. - This function will verify the parameter by default. If both enable_azure_monitor_metrics and disable_azure_monitor_metrics are specified, raise a - MutuallyExclusiveArgumentError. + This function will verify the parameter by default. If both enable_azure_monitor_metrics and + disable_azure_monitor_metrics are specified, raise a MutuallyExclusiveArgumentError. :return: bool """ return self._get_disable_azure_monitor_metrics(enable_validation=True) @@ -1913,8 +1929,8 @@ def get_disable_azure_monitor_metrics(self) -> bool: def get_enable_node_restriction(self) -> bool: """Obtain the value of enable_node_restriction. - This function will verify the parameter by default. If both enable_node_restriction and disable_node_restriction are specified, raise a - MutuallyExclusiveArgumentError. + This function will verify the parameter by default. If both enable_node_restriction and + disable_node_restriction are specified, raise a MutuallyExclusiveArgumentError. :return: bool """ @@ -1923,8 +1939,8 @@ def get_enable_node_restriction(self) -> bool: def _get_disable_node_restriction(self, enable_validation: bool = False) -> bool: """Internal function to obtain the value of disable_node_restriction. - This function supports the option of enable_validation. When enabled, if both enable_node_restriction and disable_node_restriction are - specified, raise a MutuallyExclusiveArgumentError. + This function supports the option of enable_validation. When enabled, if both enable_node_restriction and + disable_node_restriction are specified, raise a MutuallyExclusiveArgumentError. :return: bool """ @@ -1944,8 +1960,8 @@ def _get_disable_node_restriction(self, enable_validation: bool = False) -> bool def get_disable_node_restriction(self) -> bool: """Obtain the value of disable_node_restriction. - This function will verify the parameter by default. If both enable_node_restriction and disable_node_restriction are specified, raise a - MutuallyExclusiveArgumentError. + This function will verify the parameter by default. If both enable_node_restriction and + disable_node_restriction are specified, raise a MutuallyExclusiveArgumentError. :return: bool """ @@ -2003,7 +2019,8 @@ def _get_disable_vpa(self, enable_validation: bool = False) -> bool: def get_disable_vpa(self) -> bool: """Obtain the value of disable_vpa. - This function will verify the parameter by default. If both enable_vpa and disable_vpa are specified, raise a MutuallyExclusiveArgumentError. + This function will verify the parameter by default. If both enable_vpa and disable_vpa are specified, + raise a MutuallyExclusiveArgumentError. :return: bool """ @@ -2014,9 +2031,9 @@ def get_ssh_key_value_for_update(self) -> Tuple[str, bool]: Note: no_ssh_key will not be decorated into the `mc` object. - If the user provides a string-like input for --ssh-key-value, the validator function "validate_ssh_key_for_update" will - check whether it is a file path, if so, read its content and return; if it is a valid public key, return it. - Otherwise, raise error. + If the user provides a string-like input for --ssh-key-value, the validator function + "validate_ssh_key_for_update" will check whether it is a file path, if so, read its content and return; + if it is a valid public key, return it. Otherwise, raise error. :return: ssh_key_value of string type """ @@ -2037,13 +2054,14 @@ def get_initial_service_mesh_profile(self) -> ServiceMeshProfile: # returns a service mesh profile only if '--enable-azure-service-mesh' is applied enable_asm = self.raw_param.get("enable_azure_service_mesh", False) if enable_asm: - return self.models.ServiceMeshProfile( + return self.models.ServiceMeshProfile( # pylint: disable=no-member mode=CONST_AZURE_SERVICE_MESH_MODE_ISTIO, - istio=self.models.IstioServiceMesh(), + istio=self.models.IstioServiceMesh(), # pylint: disable=no-member ) return None + # pylint: disable=too-many-branches,too-many-locals,too-many-statements def update_azure_service_mesh_profile(self) -> ServiceMeshProfile: """ Update azure service mesh profile. @@ -2056,8 +2074,11 @@ def update_azure_service_mesh_profile(self) -> ServiceMeshProfile: :return: updated service mesh profile """ updated = False - new_profile = self.models.ServiceMeshProfile(mode=CONST_AZURE_SERVICE_MESH_MODE_DISABLED) \ - if self.mc.service_mesh_profile is None else copy.deepcopy(self.mc.service_mesh_profile) + new_profile = ( + self.models.ServiceMeshProfile(mode=CONST_AZURE_SERVICE_MESH_MODE_DISABLED) # pylint: disable=no-member + if self.mc.service_mesh_profile is None + else copy.deepcopy(self.mc.service_mesh_profile) + ) # enable/disable enable_asm = self.raw_param.get("enable_azure_service_mesh", False) @@ -2080,13 +2101,13 @@ def update_azure_service_mesh_profile(self) -> ServiceMeshProfile: elif enable_asm: if new_profile is not None and new_profile.mode == CONST_AZURE_SERVICE_MESH_MODE_ISTIO: raise ArgumentUsageError( - "Istio has already been enabled for this cluster, please refer to https://aka.ms/asm-aks-upgrade-docs " - "for more details on updating the mesh profile." + "Istio has already been enabled for this cluster, please refer to " + "https://aka.ms/asm-aks-upgrade-docs for more details on updating the mesh profile." ) requested_revision = self.raw_param.get("revision", None) new_profile.mode = CONST_AZURE_SERVICE_MESH_MODE_ISTIO if new_profile.istio is None: - new_profile.istio = self.models.IstioServiceMesh() + new_profile.istio = self.models.IstioServiceMesh() # pylint: disable=no-member if mesh_upgrade_command is None and requested_revision is not None: new_profile.istio.revisions = [requested_revision] updated = True @@ -2116,7 +2137,7 @@ def update_azure_service_mesh_profile(self) -> ServiceMeshProfile: # ensure necessary fields if new_profile.istio.components is None: - new_profile.istio.components = self.models.IstioComponents() + new_profile.istio.components = self.models.IstioComponents() # pylint: disable=no-member updated = True if new_profile.istio.components.ingress_gateways is None: new_profile.istio.components.ingress_gateways = [] @@ -2134,7 +2155,7 @@ def update_azure_service_mesh_profile(self) -> ServiceMeshProfile: # ingress gateway not exist, append if not ingress_gateway_exists: new_profile.istio.components.ingress_gateways.append( - self.models.IstioIngressGateway( + self.models.IstioIngressGateway( # pylint: disable=no-member mode=ingress_gateway_type, enabled=enable_ingress_gateway, ) @@ -2160,7 +2181,7 @@ def update_azure_service_mesh_profile(self) -> ServiceMeshProfile: # ensure necessary fields if new_profile.istio.components is None: - new_profile.istio.components = self.models.IstioComponents() + new_profile.istio.components = self.models.IstioComponents() # pylint: disable=no-member updated = True if new_profile.istio.components.egress_gateways is None: new_profile.istio.components.egress_gateways = [] @@ -2179,14 +2200,14 @@ def update_azure_service_mesh_profile(self) -> ServiceMeshProfile: if not egress_gateway_exists: if egx_gtw_nodeselector: new_profile.istio.components.egress_gateways.append( - self.models.IstioEgressGateway( + self.models.IstioEgressGateway( # pylint: disable=no-member enabled=enable_egress_gateway, node_selector=egx_gtw_nodeselector, ) ) else: new_profile.istio.components.egress_gateways.append( - self.models.IstioEgressGateway( + self.models.IstioEgressGateway( # pylint: disable=no-member enabled=enable_egress_gateway, ) ) @@ -2201,15 +2222,25 @@ def update_azure_service_mesh_profile(self) -> ServiceMeshProfile: if any([key_vault_id, ca_cert_object_name, ca_key_object_name, root_cert_object_name, cert_chain_object_name]): if key_vault_id is None: - raise InvalidArgumentValueError('--key-vault-id is required to use Azure Service Mesh plugin CA feature.') + raise InvalidArgumentValueError( + '--key-vault-id is required to use Azure Service Mesh plugin CA feature.' + ) if ca_cert_object_name is None: - raise InvalidArgumentValueError('--ca-cert-object-name is required to use Azure Service Mesh plugin CA feature.') + raise InvalidArgumentValueError( + '--ca-cert-object-name is required to use Azure Service Mesh plugin CA feature.' + ) if ca_key_object_name is None: - raise InvalidArgumentValueError('--ca-key-object-name is required to use Azure Service Mesh plugin CA feature.') + raise InvalidArgumentValueError( + '--ca-key-object-name is required to use Azure Service Mesh plugin CA feature.' + ) if root_cert_object_name is None: - raise InvalidArgumentValueError('--root-cert-object-name is required to use Azure Service Mesh plugin CA feature.') + raise InvalidArgumentValueError( + '--root-cert-object-name is required to use Azure Service Mesh plugin CA feature.' + ) if cert_chain_object_name is None: - raise InvalidArgumentValueError('--cert-chain-object-name is required to use Azure Service Mesh plugin CA feature.') + raise InvalidArgumentValueError( + '--cert-chain-object-name is required to use Azure Service Mesh plugin CA feature.' + ) if key_vault_id is not None and ( not is_valid_resource_id(key_vault_id) or "providers/Microsoft.KeyVault/vaults" not in key_vault_id): @@ -2217,11 +2248,23 @@ def update_azure_service_mesh_profile(self) -> ServiceMeshProfile: key_vault_id + " is not a valid Azure Keyvault resource ID." ) - if enable_asm and all([key_vault_id, ca_cert_object_name, ca_key_object_name, root_cert_object_name, cert_chain_object_name]): + if enable_asm and all( + [ + key_vault_id, + ca_cert_object_name, + ca_key_object_name, + root_cert_object_name, + cert_chain_object_name, + ] + ): if new_profile.istio.certificate_authority is None: - new_profile.istio.certificate_authority = self.models.IstioCertificateAuthority() + new_profile.istio.certificate_authority = ( + self.models.IstioCertificateAuthority() # pylint: disable=no-member + ) if new_profile.istio.certificate_authority.plugin is None: - new_profile.istio.certificate_authority.plugin = self.models.IstioPluginCertificateAuthority() + new_profile.istio.certificate_authority.plugin = ( + self.models.IstioPluginCertificateAuthority() # pylint: disable=no-member + ) new_profile.istio.certificate_authority.plugin.key_vault_id = key_vault_id new_profile.istio.certificate_authority.plugin.cert_object_name = ca_cert_object_name new_profile.istio.certificate_authority.plugin.key_object_name = ca_key_object_name @@ -2237,7 +2280,10 @@ def update_azure_service_mesh_profile(self) -> ServiceMeshProfile: "for more details on enabling Azure Service Mesh." ) requested_revision = self.raw_param.get("revision", None) - if mesh_upgrade_command == CONST_AZURE_SERVICE_MESH_UPGRADE_COMMAND_COMPLETE or mesh_upgrade_command == CONST_AZURE_SERVICE_MESH_UPGRADE_COMMAND_ROLLBACK: + if mesh_upgrade_command in ( + CONST_AZURE_SERVICE_MESH_UPGRADE_COMMAND_COMPLETE, + CONST_AZURE_SERVICE_MESH_UPGRADE_COMMAND_ROLLBACK, + ): if len(new_profile.istio.revisions) < 2: raise ArgumentUsageError('Azure Service Mesh upgrade is not in progress.') @@ -2248,13 +2294,18 @@ def update_azure_service_mesh_profile(self) -> ServiceMeshProfile: else: revision_to_remove = sorted_revisons[-1] revision_to_keep = sorted_revisons[0] - msg = (f"This operation will remove Istio control plane for revision {revision_to_remove}. " - f"Please ensure all data plane workloads have been rolled over to revision {revision_to_keep} so that they are still part of the mesh. " - "\nAre you sure you want to proceed?") + msg = ( + f"This operation will remove Istio control plane for revision {revision_to_remove}. " + f"Please ensure all data plane workloads have been rolled over to revision {revision_to_keep} " + "so that they are still part of the mesh.\nAre you sure you want to proceed?" + ) if prompt_y_n(msg, default="y"): new_profile.istio.revisions.remove(revision_to_remove) updated = True - elif mesh_upgrade_command == CONST_AZURE_SERVICE_MESH_UPGRADE_COMMAND_START and requested_revision is not None: + elif ( + mesh_upgrade_command == CONST_AZURE_SERVICE_MESH_UPGRADE_COMMAND_START and + requested_revision is not None + ): if new_profile.istio.revisions is None: new_profile.istio.revisions = [] new_profile.istio.revisions.append(requested_revision) @@ -2262,8 +2313,7 @@ def update_azure_service_mesh_profile(self) -> ServiceMeshProfile: if updated: return new_profile - else: - return self.mc.service_mesh_profile + return self.mc.service_mesh_profile def _sort_revisions(self, revisions): def _convert_revision_to_semver(rev): @@ -2500,6 +2550,7 @@ def get_node_provisioning_mode(self) -> Union[str, None]: return self.raw_param.get("node_provisioning_mode") +# pylint: disable=too-many-public-methods class AKSPreviewManagedClusterCreateDecorator(AKSManagedClusterCreateDecorator): def __init__( self, cmd: AzCliCommand, client: ContainerServiceClient, raw_parameters: Dict, resource_type: ResourceType @@ -2573,7 +2624,10 @@ def set_up_network_profile(self, mc: ManagedCluster) -> ManagedCluster: network_profile.ip_families = ip_families # recreate the load balancer profile if load_balancer_managed_outbound_ipv6_count is not None - if self.context.get_load_balancer_managed_outbound_ipv6_count() is not None or self.context.get_load_balancer_backend_pool_type() is not None: + if ( + self.context.get_load_balancer_managed_outbound_ipv6_count() is not None or + self.context.get_load_balancer_backend_pool_type() is not None + ): network_profile.load_balancer_profile = create_load_balancer_profile( self.context.get_load_balancer_managed_outbound_ip_count(), self.context.get_load_balancer_managed_outbound_ipv6_count(), @@ -2601,7 +2655,7 @@ def set_up_network_profile(self, mc: ManagedCluster) -> ManagedCluster: network_observability = self.context.get_enable_network_observability() if network_observability is not None: - network_profile.monitoring = self.models.NetworkMonitoring( + network_profile.monitoring = self.models.NetworkMonitoring( # pylint: disable=no-member enabled=network_observability ) @@ -2617,6 +2671,7 @@ def set_up_api_server_access_profile(self, mc: ManagedCluster) -> ManagedCluster mc = super().set_up_api_server_access_profile(mc) if self.context.get_enable_apiserver_vnet_integration(): if mc.api_server_access_profile is None: + # pylint: disable=no-member mc.api_server_access_profile = self.models.ManagedClusterAPIServerAccessProfile() mc.api_server_access_profile.enable_vnet_integration = True if self.context.get_apiserver_subnet_id(): @@ -2629,7 +2684,7 @@ def build_gitops_addon_profile(self) -> ManagedClusterAddonProfile: :return: a ManagedClusterAddonProfile object """ - gitops_addon_profile = self.models.ManagedClusterAddonProfile( + gitops_addon_profile = self.models.ManagedClusterAddonProfile( # pylint: disable=no-member enabled=True, ) return gitops_addon_profile @@ -2677,6 +2732,7 @@ def set_up_pod_identity_profile(self, mc: ManagedCluster) -> ManagedCluster: enable_pod_identity = self.context.get_enable_pod_identity() enable_pod_identity_with_kubenet = self.context.get_enable_pod_identity_with_kubenet() if enable_pod_identity: + # pylint: disable=no-member pod_identity_profile = self.models.pod_identity_models.ManagedClusterPodIdentityProfile( enabled=True, allow_network_plugin_kubenet=enable_pod_identity_with_kubenet, @@ -2694,7 +2750,7 @@ def set_up_workload_identity_profile(self, mc: ManagedCluster) -> ManagedCluster profile = self.context.get_workload_identity_profile() if profile: if mc.security_profile is None: - mc.security_profile = self.models.ManagedClusterSecurityProfile() + mc.security_profile = self.models.ManagedClusterSecurityProfile() # pylint: disable=no-member mc.security_profile.workload_identity = profile return mc @@ -2708,9 +2764,11 @@ def set_up_image_integrity(self, mc: ManagedCluster) -> ManagedCluster: if self.context.get_enable_image_integrity(): if mc.security_profile is None: - mc.security_profile = self.models.ManagedClusterSecurityProfile() - mc.security_profile.image_integrity = self.models.ManagedClusterSecurityProfileImageIntegrity( - enabled=True, + mc.security_profile = self.models.ManagedClusterSecurityProfile() # pylint: disable=no-member + mc.security_profile.image_integrity = ( + self.models.ManagedClusterSecurityProfileImageIntegrity( # pylint: disable=no-member + enabled=True, + ) ) return mc @@ -2726,7 +2784,7 @@ def set_up_creationdata_of_cluster_snapshot(self, mc: ManagedCluster) -> Managed creation_data = None snapshot_id = self.context.get_cluster_snapshot_id() if snapshot_id: - creation_data = self.models.CreationData( + creation_data = self.models.CreationData( # pylint: disable=no-member source_resource_id=snapshot_id ) mc.creation_data = creation_data @@ -2753,8 +2811,10 @@ def set_up_ingress_web_app_routing(self, mc: ManagedCluster) -> ManagedCluster: addons = self.context.get_enable_addons() if "web_application_routing" in addons or self.context.get_enable_app_routing(): if mc.ingress_profile is None: - mc.ingress_profile = self.models.ManagedClusterIngressProfile() - mc.ingress_profile.web_app_routing = self.models.ManagedClusterIngressProfileWebAppRouting(enabled=True) + mc.ingress_profile = self.models.ManagedClusterIngressProfile() # pylint: disable=no-member + mc.ingress_profile.web_app_routing = ( + self.models.ManagedClusterIngressProfileWebAppRouting(enabled=True) # pylint: disable=no-member + ) if "web_application_routing" in addons: dns_zone_resource_ids = self.context.get_dns_zone_resource_ids() mc.ingress_profile.web_app_routing.dns_zone_resource_ids = dns_zone_resource_ids @@ -2770,8 +2830,12 @@ def set_up_workload_auto_scaler_profile(self, mc: ManagedCluster) -> ManagedClus 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) + mc.workload_auto_scaler_profile = ( + self.models.ManagedClusterWorkloadAutoScalerProfile() # pylint: disable=no-member + ) + mc.workload_auto_scaler_profile.keda = ( + self.models.ManagedClusterWorkloadAutoScalerProfileKeda(enabled=True) # pylint: disable=no-member + ) return mc @@ -2785,7 +2849,7 @@ def set_up_custom_ca_trust_certificates(self, mc: ManagedCluster) -> ManagedClus ca_certs = self.context.get_custom_ca_trust_certificates() if ca_certs: if mc.security_profile is None: - mc.security_profile = self.models.ManagedClusterSecurityProfile() + mc.security_profile = self.models.ManagedClusterSecurityProfile() # pylint: disable=no-member mc.security_profile.custom_ca_trust_certificates = ca_certs @@ -2800,7 +2864,8 @@ def set_up_node_restriction(self, mc: ManagedCluster) -> ManagedCluster: if self.context.get_enable_node_restriction(): if mc.security_profile is None: - mc.security_profile = self.models.ManagedClusterSecurityProfile() + mc.security_profile = self.models.ManagedClusterSecurityProfile() # pylint: disable=no-member + # pylint: disable=no-member mc.security_profile.node_restriction = self.models.ManagedClusterSecurityProfileNodeRestriction( enabled=True, ) @@ -2816,9 +2881,17 @@ def set_up_vpa(self, mc: ManagedCluster) -> ManagedCluster: if self.context.get_enable_vpa(): if mc.workload_auto_scaler_profile is None: - mc.workload_auto_scaler_profile = self.models.ManagedClusterWorkloadAutoScalerProfile() + mc.workload_auto_scaler_profile = ( + # pylint: disable=no-member + self.models.ManagedClusterWorkloadAutoScalerProfile() + ) if mc.workload_auto_scaler_profile.vertical_pod_autoscaler is None: - mc.workload_auto_scaler_profile.vertical_pod_autoscaler = self.models.ManagedClusterWorkloadAutoScalerProfileVerticalPodAutoscaler(enabled=True) + mc.workload_auto_scaler_profile.vertical_pod_autoscaler = ( + # pylint: disable=no-member + self.models.ManagedClusterWorkloadAutoScalerProfileVerticalPodAutoscaler( + enabled=True + ) + ) else: mc.workload_auto_scaler_profile.vertical_pod_autoscaler.enabled = True return mc @@ -2847,7 +2920,10 @@ def set_up_node_resource_group_profile(self, mc: ManagedCluster) -> ManagedClust node_resource_group_profile = None nrg_lockdown_restriction_level = self.context.get_nrg_lockdown_restriction_level() if nrg_lockdown_restriction_level: - node_resource_group_profile = self.models.ManagedClusterNodeResourceGroupProfile(restriction_level=nrg_lockdown_restriction_level) + # pylint: disable=no-member + node_resource_group_profile = self.models.ManagedClusterNodeResourceGroupProfile( + restriction_level=nrg_lockdown_restriction_level + ) mc.node_resource_group_profile = node_resource_group_profile return mc @@ -2865,9 +2941,12 @@ def set_up_azure_monitor_profile(self, mc: ManagedCluster) -> ManagedCluster: ksm_metric_annotations_allow_list = "" if self.context.get_enable_azure_monitor_metrics(): if mc.azure_monitor_profile is None: - mc.azure_monitor_profile = self.models.ManagedClusterAzureMonitorProfile() - mc.azure_monitor_profile.metrics = self.models.ManagedClusterAzureMonitorProfileMetrics(enabled=False) - mc.azure_monitor_profile.metrics.kube_state_metrics = self.models.ManagedClusterAzureMonitorProfileKubeStateMetrics( # pylint:disable=line-too-long + mc.azure_monitor_profile = self.models.ManagedClusterAzureMonitorProfile() # pylint: disable=no-member + mc.azure_monitor_profile.metrics = ( + self.models.ManagedClusterAzureMonitorProfileMetrics(enabled=False) # pylint: disable=no-member + ) + # pylint: disable=line-too-long, no-member + mc.azure_monitor_profile.metrics.kube_state_metrics = self.models.ManagedClusterAzureMonitorProfileKubeStateMetrics( metric_labels_allowlist=str(ksm_metric_labels_allow_list), metric_annotations_allow_list=str(ksm_metric_annotations_allow_list)) self.context.set_intermediate("azuremonitormetrics_addon_enabled", True, overwrite_exists=True) @@ -2940,7 +3019,7 @@ def set_up_auto_upgrade_profile(self, mc: ManagedCluster) -> ManagedCluster: node_os_upgrade_channel = self.context.get_node_os_upgrade_channel() if node_os_upgrade_channel: if mc.auto_upgrade_profile is None: - mc.auto_upgrade_profile = self.models.ManagedClusterAutoUpgradeProfile() + mc.auto_upgrade_profile = self.models.ManagedClusterAutoUpgradeProfile() # pylint: disable=no-member mc.auto_upgrade_profile.node_os_upgrade_channel = node_os_upgrade_channel return mc @@ -2975,13 +3054,13 @@ def set_up_sku(self, mc: ManagedCluster) -> ManagedCluster: self._ensure_mc(mc) if self.context.get_uptime_sla() or self.context.get_tier() == CONST_MANAGED_CLUSTER_SKU_TIER_STANDARD: - mc.sku = self.models.ManagedClusterSKU( + mc.sku = self.models.ManagedClusterSKU( # pylint: disable=no-member name="Base", tier="Standard" ) if self.context.get_tier() == CONST_MANAGED_CLUSTER_SKU_TIER_PREMIUM: - mc.sku = self.models.ManagedClusterSKU( + mc.sku = self.models.ManagedClusterSKU( # pylint: disable=no-member name="Base", tier="Premium" ) @@ -3006,9 +3085,11 @@ def set_up_cost_analysis(self, mc: ManagedCluster) -> ManagedCluster: if self.context.get_enable_cost_analysis(): if mc.metrics_profile is None: - mc.metrics_profile = self.models.ManagedClusterMetricsProfile() + mc.metrics_profile = self.models.ManagedClusterMetricsProfile() # pylint: disable=no-member if mc.metrics_profile.cost_analysis is None: - mc.metrics_profile.cost_analysis = self.models.ManagedClusterCostAnalysis() + mc.metrics_profile.cost_analysis = ( + self.models.ManagedClusterCostAnalysis() # pylint: disable=no-member + ) # set enabled mc.metrics_profile.cost_analysis.enabled = True @@ -3030,7 +3111,9 @@ def set_up_node_provisioning_mode(self, mc: ManagedCluster) -> ManagedCluster: mode = self.context.get_node_provisioning_mode() if mode is not None: if mc.node_provisioning_profile is None: - mc.node_provisioning_profile = self.models.ManagedClusterNodeProvisioningProfile() + mc.node_provisioning_profile = ( + self.models.ManagedClusterNodeProvisioningProfile() # pylint: disable=no-member + ) # set mode mc.node_provisioning_profile.mode = mode @@ -3044,6 +3127,7 @@ def set_up_node_provisioning_profile(self, mc: ManagedCluster) -> ManagedCluster return mc + # pylint: disable=unused-argument def construct_mc_profile_preview(self, bypass_restore_defaults: bool = False) -> ManagedCluster: """The overall controller used to construct the default ManagedCluster profile. @@ -3120,8 +3204,12 @@ def check_is_postprocessing_required(self, mc: ManagedCluster) -> bool: need_grant_vnet_permission_to_cluster_identity = self.context.get_intermediate( "need_post_creation_vnet_permission_granting", default_value=False ) - enable_azure_container_storage = self.context.get_intermediate("enable_azure_container_storage", default_value=False) + enable_azure_container_storage = self.context.get_intermediate( + "enable_azure_container_storage", + default_value=False + ) + # pylint: disable=too-many-boolean-expressions if ( monitoring_addon_enabled or ingress_appgw_addon_enabled or @@ -3389,13 +3477,11 @@ def check_raw_parameters(self): return option_names = sorted([ - '"{}"'.format(format_parameter_name_to_option_name(x)) + f'"{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) - ) + error_msg = f"Please specify one or more of {' or '.join(option_names)}." raise RequiredArgumentMissingError(error_msg) def update_network_plugin_settings(self, mc: ManagedCluster) -> ManagedCluster: @@ -3405,7 +3491,8 @@ def update_network_plugin_settings(self, mc: ManagedCluster) -> ManagedCluster: """ self._ensure_mc(mc) - network_plugin = self.context._get_network_plugin() + # TODO: replace protected access with public access + network_plugin = self.context._get_network_plugin() # pylint: disable=protected-access if network_plugin: mc.network_profile.network_plugin = network_plugin @@ -3427,7 +3514,8 @@ def update_network_plugin_settings(self, mc: ManagedCluster) -> ManagedCluster: elif network_dataplane == CONST_NETWORK_DATAPLANE_CILIUM: # force network_policy to "cilium" when network_dataplane is "cilium" to pass validation in aks rp # this was needed because api version 2023-08-02preview introduced --network-policy=none - # without forcing network_policy to "cilium" here, when upgrading to cilium without specifying --network-policy, it will be set to none by default and validation in aks rp will fail. + # without forcing network_policy to "cilium" here, when upgrading to cilium without specifying + # --network-policy, it will be set to none by default and validation in aks rp will fail. mc.network_profile.network_policy = CONST_NETWORK_POLICY_CILIUM return mc @@ -3441,7 +3529,7 @@ def update_enable_network_observability_in_network_profile(self, mc: ManagedClus network_observability = self.context.get_enable_network_observability() if network_observability is not None: - mc.network_profile.monitoring = self.models.NetworkMonitoring( + mc.network_profile.monitoring = self.models.NetworkMonitoring( # pylint: disable=no-member enabled=network_observability ) return mc @@ -3472,8 +3560,8 @@ def update_azure_container_storage(self, mc: ManagedCluster) -> ManagedCluster: if enable_azure_container_storage: if not mc.agent_pool_profiles: raise UnknownError( - "Encounter an unexpected error while getting agent pool profiles from the cluster in the process of " - "updating agentpool profile." + "Encounter an unexpected error while getting agent pool profiles from the cluster " + "in the process of updating agentpool profile." ) for agentpool in mc.agent_pool_profiles: @@ -3533,16 +3621,22 @@ def update_azure_container_storage(self, mc: ManagedCluster) -> ManagedCluster: if disable_azure_container_storage: pre_uninstall_validate = False - msg = 'Disabling Azure Container Storage will forcefully delete all the storagepools on the cluster and ' \ - 'affect the applications using these storagepools. Forceful deletion of storagepools can also lead to ' \ - 'leaking of storage resources which are being consumed. Do you want to validate whether any of ' \ - 'the storagepools are being used before disabling Azure Container Storage?' + msg = ( + "Disabling Azure Container Storage will forcefully delete all the storagepools on the cluster and " + "affect the applications using these storagepools. Forceful deletion of storagepools can also lead to " + "leaking of storage resources which are being consumed. Do you want to validate whether any of " + "the storagepools are being used before disabling Azure Container Storage?" + ) if self.context.get_yes() or prompt_y_n(msg, default="y"): pre_uninstall_validate = True # set intermediate self.context.set_intermediate("disable_azure_container_storage", True, overwrite_exists=True) - self.context.set_intermediate("pre_uninstall_validate_azure_container_storage", pre_uninstall_validate, overwrite_exists=True) + self.context.set_intermediate( + "pre_uninstall_validate_azure_container_storage", + pre_uninstall_validate, + overwrite_exists=True + ) return mc @@ -3601,7 +3695,7 @@ def update_api_server_access_profile(self, mc: ManagedCluster) -> ManagedCluster self._ensure_mc(mc) if mc.api_server_access_profile is None: - profile_holder = self.models.ManagedClusterAPIServerAccessProfile() + profile_holder = self.models.ManagedClusterAPIServerAccessProfile() # pylint: disable=no-member else: profile_holder = mc.api_server_access_profile @@ -3632,7 +3726,7 @@ def update_api_server_access_profile(self, mc: ManagedCluster) -> ManagedCluster # keep api_server_access_profile empty if none of its properties are updated if ( profile_holder != mc.api_server_access_profile and - profile_holder == self.models.ManagedClusterAPIServerAccessProfile() + profile_holder == self.models.ManagedClusterAPIServerAccessProfile() # pylint: disable=no-member ): profile_holder = None mc.api_server_access_profile = profile_holder @@ -3712,7 +3806,7 @@ def update_workload_identity_profile(self, mc: ManagedCluster) -> ManagedCluster return mc if mc.security_profile is None: - mc.security_profile = self.models.ManagedClusterSecurityProfile() + mc.security_profile = self.models.ManagedClusterSecurityProfile() # pylint: disable=no-member mc.security_profile.workload_identity = profile return mc @@ -3754,12 +3848,14 @@ def update_image_integrity(self, mc: ManagedCluster) -> ManagedCluster: shouldEnable_image_integrity = True if mc.security_profile is None: - mc.security_profile = self.models.ManagedClusterSecurityProfile() + mc.security_profile = self.models.ManagedClusterSecurityProfile() # pylint: disable=no-member image_integrity_profile = mc.security_profile.image_integrity if image_integrity_profile is None: - image_integrity_profile = self.models.ManagedClusterSecurityProfileImageIntegrity() + image_integrity_profile = ( + self.models.ManagedClusterSecurityProfileImageIntegrity() # pylint: disable=no-member + ) mc.security_profile.image_integrity = image_integrity_profile image_integrity_profile.enabled = shouldEnable_image_integrity @@ -3786,13 +3882,21 @@ def update_workload_auto_scaler_profile(self, mc: ManagedCluster) -> ManagedClus 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) + mc.workload_auto_scaler_profile = ( + self.models.ManagedClusterWorkloadAutoScalerProfile() # pylint: disable=no-member + ) + mc.workload_auto_scaler_profile.keda = ( + self.models.ManagedClusterWorkloadAutoScalerProfileKeda(enabled=True) # pylint: disable=no-member + ) 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) + mc.workload_auto_scaler_profile = ( + self.models.ManagedClusterWorkloadAutoScalerProfile() # pylint: disable=no-member + ) + mc.workload_auto_scaler_profile.keda = ( + self.models.ManagedClusterWorkloadAutoScalerProfileKeda(enabled=False) # pylint: disable=no-member + ) return mc @@ -3806,7 +3910,7 @@ def update_custom_ca_trust_certificates(self, mc: ManagedCluster) -> ManagedClus ca_certs = self.context.get_custom_ca_trust_certificates() if ca_certs: if mc.security_profile is None: - mc.security_profile = self.models.ManagedClusterSecurityProfile() + mc.security_profile = self.models.ManagedClusterSecurityProfile() # pylint: disable=no-member mc.security_profile.custom_ca_trust_certificates = ca_certs @@ -3829,16 +3933,23 @@ def update_azure_monitor_profile(self, mc: ManagedCluster) -> ManagedCluster: if self.context.get_enable_azure_monitor_metrics(): if mc.azure_monitor_profile is None: - mc.azure_monitor_profile = self.models.ManagedClusterAzureMonitorProfile() - mc.azure_monitor_profile.metrics = self.models.ManagedClusterAzureMonitorProfileMetrics(enabled=True) - mc.azure_monitor_profile.metrics.kube_state_metrics = self.models.ManagedClusterAzureMonitorProfileKubeStateMetrics( - metric_labels_allowlist=str(ksm_metric_labels_allow_list), - metric_annotations_allow_list=str(ksm_metric_annotations_allow_list)) + mc.azure_monitor_profile = self.models.ManagedClusterAzureMonitorProfile() # pylint: disable=no-member + mc.azure_monitor_profile.metrics = ( + self.models.ManagedClusterAzureMonitorProfileMetrics(enabled=True) # pylint: disable=no-member + ) + mc.azure_monitor_profile.metrics.kube_state_metrics = ( + self.models.ManagedClusterAzureMonitorProfileKubeStateMetrics( # pylint: disable=no-member + metric_labels_allowlist=str(ksm_metric_labels_allow_list), + metric_annotations_allow_list=str(ksm_metric_annotations_allow_list) + ) + ) if self.context.get_disable_azure_monitor_metrics(): if mc.azure_monitor_profile is None: - mc.azure_monitor_profile = self.models.ManagedClusterAzureMonitorProfile() - mc.azure_monitor_profile.metrics = self.models.ManagedClusterAzureMonitorProfileMetrics(enabled=False) + mc.azure_monitor_profile = self.models.ManagedClusterAzureMonitorProfile() # pylint: disable=no-member + mc.azure_monitor_profile.metrics = ( + self.models.ManagedClusterAzureMonitorProfileMetrics(enabled=False) # pylint: disable=no-member + ) # TODO: should remove get value from enable_azuremonitormetrics once the option is removed # TODO: should remove get value from disable_azuremonitormetrics once the option is removed @@ -3868,18 +3979,23 @@ def update_node_restriction(self, mc: ManagedCluster) -> ManagedCluster: if self.context.get_enable_node_restriction(): if mc.security_profile is None: - mc.security_profile = self.models.ManagedClusterSecurityProfile() + mc.security_profile = self.models.ManagedClusterSecurityProfile() # pylint: disable=no-member if mc.security_profile.node_restriction is None: - mc.security_profile.node_restriction = self.models.ManagedClusterSecurityProfileNodeRestriction() + mc.security_profile.node_restriction = ( + self.models.ManagedClusterSecurityProfileNodeRestriction() # pylint: disable=no-member + ) # set enabled mc.security_profile.node_restriction.enabled = True if self.context.get_disable_node_restriction(): if mc.security_profile is None: - mc.security_profile = self.models.ManagedClusterSecurityProfile() + mc.security_profile = self.models.ManagedClusterSecurityProfile() # pylint: disable=no-member if mc.security_profile.node_restriction is None: - mc.security_profile.node_restriction = self.models.ManagedClusterSecurityProfileNodeRestriction() + mc.security_profile.node_restriction = ( + # pylint: disable=no-member + self.models.ManagedClusterSecurityProfileNodeRestriction() + ) # set disabled mc.security_profile.node_restriction.enabled = False @@ -3895,18 +4011,28 @@ def update_vpa(self, mc: ManagedCluster) -> ManagedCluster: if self.context.get_enable_vpa(): if mc.workload_auto_scaler_profile is None: - mc.workload_auto_scaler_profile = self.models.ManagedClusterWorkloadAutoScalerProfile() + mc.workload_auto_scaler_profile = ( + self.models.ManagedClusterWorkloadAutoScalerProfile() # pylint: disable=no-member + ) if mc.workload_auto_scaler_profile.vertical_pod_autoscaler is None: - mc.workload_auto_scaler_profile.vertical_pod_autoscaler = self.models.ManagedClusterWorkloadAutoScalerProfileVerticalPodAutoscaler() + mc.workload_auto_scaler_profile.vertical_pod_autoscaler = ( + # pylint: disable=no-member + self.models.ManagedClusterWorkloadAutoScalerProfileVerticalPodAutoscaler() + ) # set enabled mc.workload_auto_scaler_profile.vertical_pod_autoscaler.enabled = True if self.context.get_disable_vpa(): if mc.workload_auto_scaler_profile is None: - mc.workload_auto_scaler_profile = self.models.ManagedClusterWorkloadAutoScalerProfile() + mc.workload_auto_scaler_profile = ( + self.models.ManagedClusterWorkloadAutoScalerProfile() # pylint: disable=no-member + ) if mc.workload_auto_scaler_profile.vertical_pod_autoscaler is None: - mc.workload_auto_scaler_profile.vertical_pod_autoscaler = self.models.ManagedClusterWorkloadAutoScalerProfileVerticalPodAutoscaler() + mc.workload_auto_scaler_profile.vertical_pod_autoscaler = ( + # pylint: disable=no-member + self.models.ManagedClusterWorkloadAutoScalerProfileVerticalPodAutoscaler() + ) # set disabled mc.workload_auto_scaler_profile.vertical_pod_autoscaler.enabled = False @@ -3924,7 +4050,7 @@ def update_creation_data(self, mc: ManagedCluster) -> ManagedCluster: raise UnknownError( "Please use az aks upgrade --cluster-snapshot-id to upgrade cluster version" ) - creation_data = self.models.CreationData( + creation_data = self.models.CreationData( # pylint: disable=no-member source_resource_id=snapshot_id ) mc.creation_data = creation_data @@ -3942,20 +4068,20 @@ def update_linux_profile(self, mc: ManagedCluster) -> ManagedCluster: if ssh_key_value: if mc.linux_profile is None: - mc.linux_profile = self.models.ContainerServiceLinuxProfile( + mc.linux_profile = self.models.ContainerServiceLinuxProfile( # pylint: disable=no-member admin_username="azureuser", - ssh=self.models.ContainerServiceSshConfiguration( + ssh=self.models.ContainerServiceSshConfiguration( # pylint: disable=no-member public_keys=[ - self.models.ContainerServiceSshPublicKey( + self.models.ContainerServiceSshPublicKey( # pylint: disable=no-member key_data=ssh_key_value ) ] ) ) else: - mc.linux_profile.ssh = self.models.ContainerServiceSshConfiguration( + mc.linux_profile.ssh = self.models.ContainerServiceSshConfiguration( # pylint: disable=no-member public_keys=[ - self.models.ContainerServiceSshPublicKey( + self.models.ContainerServiceSshPublicKey( # pylint: disable=no-member key_data=ssh_key_value ) ] @@ -3971,7 +4097,9 @@ def update_node_resource_group_profile(self, mc: ManagedCluster) -> ManagedClust nrg_lockdown_restriction_level = self.context.get_nrg_lockdown_restriction_level() if nrg_lockdown_restriction_level is not None: if mc.node_resource_group_profile is None: - mc.node_resource_group_profile = self.models.ManagedClusterNodeResourceGroupProfile() + mc.node_resource_group_profile = ( + self.models.ManagedClusterNodeResourceGroupProfile() # pylint: disable=no-member + ) mc.node_resource_group_profile.restriction_level = nrg_lockdown_restriction_level return mc @@ -3984,7 +4112,7 @@ def update_auto_upgrade_profile(self, mc: ManagedCluster) -> ManagedCluster: node_os_upgrade_channel = self.context.get_node_os_upgrade_channel() if node_os_upgrade_channel is not None: if mc.auto_upgrade_profile is None: - mc.auto_upgrade_profile = self.models.ManagedClusterAutoUpgradeProfile() + mc.auto_upgrade_profile = self.models.ManagedClusterAutoUpgradeProfile() # pylint: disable=no-member mc.auto_upgrade_profile.node_os_upgrade_channel = node_os_upgrade_channel return mc @@ -4028,19 +4156,19 @@ def update_sku(self, mc: ManagedCluster) -> ManagedCluster: # Premium without LTS is ok (not vice versa) if self.context.get_tier() == CONST_MANAGED_CLUSTER_SKU_TIER_PREMIUM: - mc.sku = self.models.ManagedClusterSKU( + mc.sku = self.models.ManagedClusterSKU( # pylint: disable=no-member 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( + mc.sku = self.models.ManagedClusterSKU( # pylint: disable=no-member name="Base", 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( + mc.sku = self.models.ManagedClusterSKU( # pylint: disable=no-member name="Base", tier="Free" ) @@ -4053,7 +4181,11 @@ def update_upgrade_settings(self, mc: ManagedCluster) -> ManagedCluster: self._ensure_mc(mc) existing_until = None - if mc.upgrade_settings is not None and mc.upgrade_settings.override_settings is not None and mc.upgrade_settings.override_settings.until is not None: + if ( + mc.upgrade_settings is not None and + mc.upgrade_settings.override_settings is not None and + mc.upgrade_settings.override_settings.until is not None + ): existing_until = mc.upgrade_settings.override_settings.until force_upgrade = self.context.get_force_upgrade() @@ -4061,9 +4193,11 @@ def update_upgrade_settings(self, mc: ManagedCluster) -> ManagedCluster: if force_upgrade is not None or override_until is not None: if mc.upgrade_settings is None: - mc.upgrade_settings = self.models.ClusterUpgradeSettings() + mc.upgrade_settings = self.models.ClusterUpgradeSettings() # pylint: disable=no-member if mc.upgrade_settings.override_settings is None: - mc.upgrade_settings.override_settings = self.models.UpgradeOverrideSettings() + mc.upgrade_settings.override_settings = ( + self.models.UpgradeOverrideSettings() # pylint: disable=no-member + ) # sets force_upgrade if force_upgrade is not None: mc.upgrade_settings.override_settings.force_upgrade = force_upgrade @@ -4071,10 +4205,10 @@ def update_upgrade_settings(self, mc: ManagedCluster) -> ManagedCluster: if override_until is not None: try: mc.upgrade_settings.override_settings.until = parse(override_until) - except Exception: # pylint: disable=broad-except + except Exception as exc: # pylint: disable=broad-except raise InvalidArgumentValueError( f"{override_until} is not a valid datatime format." - ) + ) from exc elif force_upgrade: default_extended_until = datetime.datetime.utcnow() + datetime.timedelta(days=3) if existing_until is None or existing_until.timestamp() < default_extended_until.timestamp(): @@ -4103,18 +4237,18 @@ def update_cost_analysis(self, mc: ManagedCluster) -> ManagedCluster: if self.context.get_enable_cost_analysis(): if mc.metrics_profile is None: - mc.metrics_profile = self.models.ManagedClusterMetricsProfile() + mc.metrics_profile = self.models.ManagedClusterMetricsProfile() # pylint: disable=no-member if mc.metrics_profile.cost_analysis is None: - mc.metrics_profile.cost_analysis = self.models.ManagedClusterCostAnalysis() + mc.metrics_profile.cost_analysis = self.models.ManagedClusterCostAnalysis() # pylint: disable=no-member # set enabled mc.metrics_profile.cost_analysis.enabled = True if self.context.get_disable_cost_analysis(): if mc.metrics_profile is None: - mc.metrics_profile = self.models.ManagedClusterMetricsProfile() + mc.metrics_profile = self.models.ManagedClusterMetricsProfile() # pylint: disable=no-member if mc.metrics_profile.cost_analysis is None: - mc.metrics_profile.cost_analysis = self.models.ManagedClusterCostAnalysis() + mc.metrics_profile.cost_analysis = self.models.ManagedClusterCostAnalysis() # pylint: disable=no-member # set disabled mc.metrics_profile.cost_analysis.enabled = False @@ -4127,7 +4261,9 @@ def update_node_provisioning_mode(self, mc: ManagedCluster) -> ManagedCluster: mode = self.context.get_node_provisioning_mode() if mode is not None: if mc.node_provisioning_profile is None: - mc.node_provisioning_profile = self.models.ManagedClusterNodeProvisioningProfile() + mc.node_provisioning_profile = ( + self.models.ManagedClusterNodeProvisioningProfile() # pylint: disable=no-member + ) # set mode mc.node_provisioning_profile.mode = mode @@ -4145,14 +4281,12 @@ def update_metrics_profile(self, mc: ManagedCluster) -> ManagedCluster: return mc + # pylint: disable=too-many-branches def update_app_routing_profile(self, mc: ManagedCluster) -> ManagedCluster: """Update app routing profile for the ManagedCluster object. :return: the ManagedCluster object """ - from azure.cli.command_modules.keyvault.custom import set_policy - from azext_aks_preview._client_factory import get_keyvault_client - self._ensure_mc(mc) # get parameters from context @@ -4165,23 +4299,41 @@ def update_app_routing_profile(self, mc: ManagedCluster) -> ManagedCluster: update_dns_zone = self.context.get_update_dns_zone() # update ManagedCluster object with app routing settings - mc.ingress_profile = mc.ingress_profile or self.models.ManagedClusterIngressProfile() - mc.ingress_profile.web_app_routing = mc.ingress_profile.web_app_routing or self.models.ManagedClusterIngressProfileWebAppRouting() + mc.ingress_profile = ( + mc.ingress_profile or + self.models.ManagedClusterIngressProfile() # pylint: disable=no-member + ) + mc.ingress_profile.web_app_routing = ( + mc.ingress_profile.web_app_routing or + self.models.ManagedClusterIngressProfileWebAppRouting() # pylint: disable=no-member + ) if enable_app_routing is not None: - if mc.ingress_profile.web_app_routing.enabled == enable_app_routing: - error_message = 'App Routing is already enabled.\n' if enable_app_routing else 'App Routing is already disabled.\n' - raise CLIError(error_message) - mc.ingress_profile.web_app_routing.enabled = enable_app_routing + if mc.ingress_profile.web_app_routing.enabled == enable_app_routing: + error_message = ( + "App Routing is already enabled.\n" + if enable_app_routing + else "App Routing is already disabled.\n" + ) + raise CLIError(error_message) + mc.ingress_profile.web_app_routing.enabled = enable_app_routing # update ManagedCluster object with keyvault-secret-provider settings if enable_keyvault_secret_provider: mc.addon_profiles = mc.addon_profiles or {} if not mc.addon_profiles.get(CONST_AZURE_KEYVAULT_SECRETS_PROVIDER_ADDON_NAME): - mc.addon_profiles[CONST_AZURE_KEYVAULT_SECRETS_PROVIDER_ADDON_NAME] = self.models.ManagedClusterAddonProfile( - enabled=True, config={CONST_SECRET_ROTATION_ENABLED: "false", CONST_ROTATION_POLL_INTERVAL: "2m"}) + mc.addon_profiles[ + CONST_AZURE_KEYVAULT_SECRETS_PROVIDER_ADDON_NAME + ] = self.models.ManagedClusterAddonProfile( # pylint: disable=no-member + enabled=True, + config={ + CONST_SECRET_ROTATION_ENABLED: "false", + CONST_ROTATION_POLL_INTERVAL: "2m", + }, + ) elif not mc.addon_profiles[CONST_AZURE_KEYVAULT_SECRETS_PROVIDER_ADDON_NAME].enabled: mc.addon_profiles[CONST_AZURE_KEYVAULT_SECRETS_PROVIDER_ADDON_NAME].enabled = True # modify DNS zone resource IDs + # pylint: disable=too-many-nested-blocks if dns_zone_resource_ids: if mc.ingress_profile and mc.ingress_profile.web_app_routing and mc.ingress_profile.web_app_routing.enabled: if add_dns_zone: @@ -4191,15 +4343,25 @@ def update_app_routing_profile(self, mc: ManagedCluster) -> ManagedCluster: if attach_zones: try: for dns_zone in dns_zone_resource_ids: - if not add_role_assignment(self.cmd, 'DNS Zone Contributor', mc.ingress_profile.web_app_routing.identity.object_id, False, scope=dns_zone): + if not add_role_assignment( + self.cmd, + "DNS Zone Contributor", + mc.ingress_profile.web_app_routing.identity.object_id, + False, + scope=dns_zone + ): logger.warning( 'Could not create a role assignment for App Routing. ' 'Are you an Owner on this subscription?') except Exception as ex: - raise CLIError(f'Error in granting dns zone permisions to managed identity: {ex}\n') + raise CLIError('Error in granting dns zone permisions to managed identity.\n') from ex elif delete_dns_zone: if mc.ingress_profile.web_app_routing.dns_zone_resource_ids: - dns_zone_resource_ids = [x for x in mc.ingress_profile.web_app_routing.dns_zone_resource_ids if x not in dns_zone_resource_ids] + dns_zone_resource_ids = [ + x + for x in mc.ingress_profile.web_app_routing.dns_zone_resource_ids + if x not in dns_zone_resource_ids + ] mc.ingress_profile.web_app_routing.dns_zone_resource_ids = dns_zone_resource_ids else: raise CLIError('No DNS zone is used by App Routing.\n') @@ -4208,12 +4370,18 @@ def update_app_routing_profile(self, mc: ManagedCluster) -> ManagedCluster: if attach_zones: try: for dns_zone in dns_zone_resource_ids: - if not add_role_assignment(self.cmd, 'DNS Zone Contributor', mc.ingress_profile.web_app_routing.identity.object_id, False, scope=dns_zone): + if not add_role_assignment( + self.cmd, + "DNS Zone Contributor", + mc.ingress_profile.web_app_routing.identity.object_id, + False, + scope=dns_zone, + ): logger.warning( 'Could not create a role assignment for App Routing. ' 'Are you an Owner on this subscription?') except Exception as ex: - raise CLIError(f'Error in granting dns zone permisions to managed identity: {ex}\n') + raise CLIError('Error in granting dns zone permisions to managed identity.\n') from ex else: raise CLIError('App Routing must be enabled to modify DNS zone resource IDs.\n') @@ -4303,8 +4471,12 @@ def check_is_postprocessing_required(self, mc: ManagedCluster) -> bool: """ postprocessing_required = super().check_is_postprocessing_required(mc) if not postprocessing_required: - enable_azure_container_storage = self.context.get_intermediate("enable_azure_container_storage", default_value=False) - disable_azure_container_storage = self.context.get_intermediate("disable_azure_container_storage", default_value=False) + enable_azure_container_storage = self.context.get_intermediate( + "enable_azure_container_storage", default_value=False + ) + disable_azure_container_storage = self.context.get_intermediate( + "disable_azure_container_storage", default_value=False + ) if (enable_azure_container_storage or disable_azure_container_storage): return True