diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 4f835a05dec..6a60837b4f6 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -128,6 +128,8 @@ /src/k8sconfiguration/ @NarayanThiru +/src/k8s-configuration/ @NarayanThiru + /src/log-analytics-solution/ @zhoxing-ms /src/kusto/ @ilayr @orhasban @astauben diff --git a/src/k8s-configuration/HISTORY.rst b/src/k8s-configuration/HISTORY.rst new file mode 100644 index 00000000000..7de17458634 --- /dev/null +++ b/src/k8s-configuration/HISTORY.rst @@ -0,0 +1,10 @@ +.. :changelog: + +Release History +=============== + +1.0.0 +++++++++++++++++++ +* Support api-version 2021-03-01 +* Update helm operator parameter aliases +* Migrate from k8sconfiguration to k8s-configuration \ No newline at end of file diff --git a/src/k8s-configuration/README.rst b/src/k8s-configuration/README.rst new file mode 100644 index 00000000000..09ddc9d9bbb --- /dev/null +++ b/src/k8s-configuration/README.rst @@ -0,0 +1,74 @@ +Microsoft Azure CLI 'k8s-configuration' Extension +========================================== + +This package is for the 'k8s-configuration' extension. +i.e. 'az k8s-configuration' + +### How to use ### +Install this extension using the below CLI command +``` +az extension add --name k8s-configuration +``` + +### Included Features +#### Kubernetes Configuration: +Kubernetes SourceControl Configuration: [more info](https://docs.microsoft.com/en-us/azure/kubernetessconfiguration/)\ +*Examples:* + +##### Create a KubernetesConfiguration +``` +az k8s-configuration create \ + --resource-group groupName \ + --cluster-name clusterName \ + --cluster-type clusterType \ + --name configurationName \ + --operator-instance-name operatorInstanceName \ + --operator-namespace operatorNamespace \ + --repository-url githubRepoUrl \ + --operator-params operatorParameters \ + --enable-helm-operator \ + --helm-operator-version chartVersion \ + --helm-operator-params chartParameters +``` + +##### Get a KubernetesConfiguration +``` +az k8s-configuration show \ + --resource-group groupName \ + --cluster-name clusterName \ + --cluster-type clusterType \ + --name configurationName +``` + +##### Delete a KubernetesConfiguration +``` +az k8s-configuration delete \ + --resource-group groupName \ + --cluster-name clusterName \ + --cluster-type clusterType \ + --name configurationName +``` + +##### Update a KubernetesConfiguration +``` +az k8s-configuration create \ + --resource-group groupName \ + --cluster-name clusterName \ + --cluster-type clusterType \ + --name configurationName \ + --repository-url githubRepoUrl \ + --operator-params operatorParameters \ + --enable-helm-operator \ + --helm-operator-version chartVersion \ + --helm-operator-params chartParameters +``` + +##### List all KubernetesConfigurations of a cluster +``` +az k8s-configuration list \ + --resource-group groupName \ + --cluster-name clusterName \ + --cluster-type clusterType +``` + +If you have issues, please give feedback by opening an issue at https://github.com/Azure/azure-cli-extensions/issues. \ No newline at end of file diff --git a/src/k8s-configuration/azext_k8s_configuration/__init__.py b/src/k8s-configuration/azext_k8s_configuration/__init__.py new file mode 100644 index 00000000000..db560042e65 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/__init__.py @@ -0,0 +1,32 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +from azure.cli.core import AzCommandsLoader + +from azext_k8s_configuration._help import helps # pylint: disable=unused-import + + +class K8sConfigurationCommandsLoader(AzCommandsLoader): + + def __init__(self, cli_ctx=None): + from azure.cli.core.commands import CliCommandType + from azext_k8s_configuration._client_factory import cf_k8s_configuration + k8s_configuration_custom = CliCommandType( + operations_tmpl='azext_k8s_configuration.custom#{}', + client_factory=cf_k8s_configuration) + super(K8sConfigurationCommandsLoader, self).__init__(cli_ctx=cli_ctx, + custom_command_type=k8s_configuration_custom) + + def load_command_table(self, args): + from azext_k8s_configuration.commands import load_command_table + load_command_table(self, args) + return self.command_table + + def load_arguments(self, command): + from azext_k8s_configuration._params import load_arguments + load_arguments(self, command) + + +COMMAND_LOADER_CLS = K8sConfigurationCommandsLoader diff --git a/src/k8s-configuration/azext_k8s_configuration/_client_factory.py b/src/k8s-configuration/azext_k8s_configuration/_client_factory.py new file mode 100644 index 00000000000..d294b6fdfa4 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/_client_factory.py @@ -0,0 +1,15 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + + +def cf_k8s_configuration(cli_ctx, *_): + + from azure.cli.core.commands.client_factory import get_mgmt_service_client + from azext_k8s_configuration.vendored_sdks import SourceControlConfigurationClient + return get_mgmt_service_client(cli_ctx, SourceControlConfigurationClient) + + +def cf_k8s_configuration_operation(cli_ctx, _): + return cf_k8s_configuration(cli_ctx).source_control_configurations diff --git a/src/k8s-configuration/azext_k8s_configuration/_format.py b/src/k8s-configuration/azext_k8s_configuration/_format.py new file mode 100644 index 00000000000..a1ea04822d8 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/_format.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +from collections import OrderedDict + + +def k8s_configuration_list_table_format(results): + return [__get_table_row(result) for result in results] + + +def k8s_configuration_show_table_format(result): + return __get_table_row(result) + + +def __get_table_row(result): + return OrderedDict([ + ('name', result['name']), + ('repositoryUrl', result['repositoryUrl']), + ('operatorName', result['operatorInstanceName']), + ('operatorNamespace', result['operatorNamespace']), + ('scope', result['operatorScope']), + ('provisioningState', result['provisioningState']) + ]) diff --git a/src/k8s-configuration/azext_k8s_configuration/_help.py b/src/k8s-configuration/azext_k8s_configuration/_help.py new file mode 100644 index 00000000000..3fa338c7b28 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/_help.py @@ -0,0 +1,70 @@ +# coding=utf-8 +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +from knack.help_files import helps # pylint: disable=unused-import + + +helps['k8s-configuration'] = """ + type: group + short-summary: Commands to manage Kubernetes configuration. +""" + +helps['k8s-configuration create'] = """ + type: command + short-summary: Create a Kubernetes configuration. + examples: + - name: Create a Kubernetes configuration + text: |- + az k8s-configuration create --resource-group MyResourceGroup --cluster-name MyClusterName \\ + --cluster-type connectedClusters --name MyGitConfig --operator-instance-name OperatorInst01 \\ + --operator-namespace OperatorNamespace01 --operator-type flux --operator-params "'--git-readonly'" \\ + --repository-url git://github.com/fluxHowTo/flux-get-started --enable-helm-operator \\ + --helm-operator-chart-version 1.2.0 --scope namespace --helm-operator-params '--set helm.versions=v3' \\ + --ssh-private-key '' --ssh-private-key-file '' --https-user '' --https-key '' \\ + --ssh-known-hosts '' --ssh-known-hosts-file '' +""" + +helps['k8s-configuration list'] = """ + type: command + short-summary: List Kubernetes configurations. + examples: + - name: List all Kubernetes configurations of a cluster + text: |- + az k8s-configuration list --resource-group MyResourceGroup --cluster-name MyClusterName \\ + --cluster-type connectedClusters +""" + +helps['k8s-configuration delete'] = """ + type: command + short-summary: Delete a Kubernetes configuration. + examples: + - name: Delete a Kubernetes configuration + text: |- + az k8s-configuration delete --resource-group MyResourceGroup --cluster-name MyClusterName \\ + --cluster-type connectedClusters --name MyConfigurationName +""" + +helps['k8s-configuration show'] = """ + type: command + short-summary: Show details of a Kubernetes configuration. + examples: + - name: Show a Kubernetes configuration + text: |- + az k8s-configuration show --resource-group MyResourceGroup --cluster-name MyClusterName \\ + --cluster-type connectedClusters --name MyConfigurationName +""" + +helps['k8s-configuration update'] = """ + type: command + short-summary: Update a Kubernetes configuration. + examples: + - name: Update an existing Kubernetes configuration + text: |- + az k8s-configuration update --resource-group MyResourceGroup --cluster-name MyClusterName \\ + --cluster-type connectedClusters --name MyConfigurationName --enable-helm-operator \\ + --repository-url git://github.com/fluxHowTo/flux-get-started --operator-params "'--git-readonly'" \\ + --helm-operator-chart-version 1.2.0 --helm-operator-params '--set helm.versions=v3' +""" diff --git a/src/k8s-configuration/azext_k8s_configuration/_params.py b/src/k8s-configuration/azext_k8s_configuration/_params.py new file mode 100644 index 00000000000..9198ef3882e --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/_params.py @@ -0,0 +1,88 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- +# pylint: disable=line-too-long + +from knack.arguments import CLIArgumentType + +from azure.cli.core.commands.parameters import ( + get_three_state_flag, + get_enum_type, + tags_type +) + +from azure.cli.core.commands.validators import get_default_location_from_resource_group +from ._validators import validate_configuration_type, validate_operator_namespace, validate_operator_instance_name + + +def load_arguments(self, _): + sourcecontrolconfiguration_type = CLIArgumentType(help='Name of the Kubernetes Configuration') + + with self.argument_context('k8s-configuration') as c: + c.argument('tags', tags_type) + c.argument('location', + validator=get_default_location_from_resource_group) + c.argument('name', sourcecontrolconfiguration_type, + options_list=['--name', '-n']) + c.argument('cluster_name', + options_list=['--cluster-name', '-c'], + help='Name of the Kubernetes cluster') + c.argument('cluster_type', + arg_type=get_enum_type(['connectedClusters', 'managedClusters']), + help='Specify Arc clusters or AKS managed clusters.') + c.argument('repository_url', + options_list=['--repository-url', '-u'], + help='Url of the source control repository') + c.argument('scope', + arg_type=get_enum_type(['namespace', 'cluster']), + help='''Specify scope of the operator to be 'namespace' or 'cluster' ''') + c.argument('configuration_type', + validator=validate_configuration_type, + arg_type=get_enum_type(['sourceControlConfiguration']), + help='Type of the configuration') + c.argument('enable_helm_operator', + arg_group="Helm Operator", + arg_type=get_three_state_flag(), + options_list=['--enable-helm-operator', '--enable-hop'], + help='Enable support for Helm chart deployments') + c.argument('helm_operator_params', + arg_group="Helm Operator", + options_list=['--helm-operator-params', '--hop-params'], + help='Chart values for the Helm Operator (if enabled)') + c.argument('helm_operator_chart_version', + arg_group="Helm Operator", + options_list=['--helm-operator-chart-version', '--hop-chart-version'], + help='Chart version of the Helm Operator (if enabled)') + c.argument('operator_params', + arg_group="Operator", + help='Parameters for the Operator') + c.argument('operator_instance_name', + arg_group="Operator", + help='Instance name of the Operator', + validator=validate_operator_instance_name) + c.argument('operator_namespace', + arg_group="Operator", + help='Namespace in which to install the Operator', + validator=validate_operator_namespace) + c.argument('operator_type', + arg_group="Operator", + help='''Type of the operator. Valid value is 'flux' ''') + c.argument('ssh_private_key', + arg_group="Auth", + help='Specify Base64-encoded private ssh key for private repository sync') + c.argument('ssh_private_key_file', + arg_group="Auth", + help='Specify filepath to private ssh key for private repository sync') + c.argument('https_user', + arg_group="Auth", + help='Specify HTTPS username for private repository sync') + c.argument('https_key', + arg_group="Auth", + help='Specify HTTPS token/password for private repository sync') + c.argument('ssh_known_hosts', + arg_group="Auth", + help='Specify Base64-encoded known_hosts contents containing public SSH keys required to access private Git instances') + c.argument('ssh_known_hosts_file', + arg_group="Auth", + help='Specify filepath to known_hosts contents containing public SSH keys required to access private Git instances') diff --git a/src/k8s-configuration/azext_k8s_configuration/_validators.py b/src/k8s-configuration/azext_k8s_configuration/_validators.py new file mode 100644 index 00000000000..0862de43205 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/_validators.py @@ -0,0 +1,46 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +import re +from azure.cli.core.azclierror import InvalidArgumentValueError + + +# Parameter-Level Validation +def validate_configuration_type(configuration_type): + if configuration_type.lower() != 'sourcecontrolconfiguration': + raise InvalidArgumentValueError( + 'Invalid configuration-type', + 'Try specifying the valid value "sourceControlConfiguration"') + + +def validate_operator_namespace(namespace): + if namespace.operator_namespace: + __validate_k8s_name(namespace.operator_namespace, "--operator-namespace", 23) + + +def validate_operator_instance_name(namespace): + if namespace.operator_instance_name: + __validate_k8s_name(namespace.operator_instance_name, "--operator-instance-name", 23) + + +# Create Parameter Validation +def validate_configuration_name(configuration_name): + __validate_k8s_name(configuration_name, "--name", 63) + + +# Helper +def __validate_k8s_name(param_value, param_name, max_len): + if len(param_value) > max_len: + raise InvalidArgumentValueError( + 'Error! Invalid {0}'.format(param_name), + 'Parameter {0} can be a maximum of {1} characters'.format(param_name, max_len)) + if not re.match(r'^[a-z0-9]([-a-z0-9]*[a-z0-9])?$', param_value): + if param_value[0] == "-" or param_value[-1] == "-": + raise InvalidArgumentValueError( + 'Error! Invalid {0}'.format(param_name), + 'Parameter {0} cannot begin or end with a hyphen'.format(param_name)) + raise InvalidArgumentValueError( + 'Error! Invalid {0}'.format(param_name), + 'Parameter {0} can only contain lowercase alphanumeric characters and hyphens'.format(param_name)) diff --git a/src/k8s-configuration/azext_k8s_configuration/azext_metadata.json b/src/k8s-configuration/azext_k8s_configuration/azext_metadata.json new file mode 100644 index 00000000000..3695b0d7077 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/azext_metadata.json @@ -0,0 +1,3 @@ +{ + "azext.minCliCoreVersion": "2.15.0" +} \ No newline at end of file diff --git a/src/k8s-configuration/azext_k8s_configuration/commands.py b/src/k8s-configuration/azext_k8s_configuration/commands.py new file mode 100644 index 00000000000..541dfe3943b --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/commands.py @@ -0,0 +1,23 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +# pylint: disable=line-too-long +from azure.cli.core.commands import CliCommandType +from azext_k8s_configuration._client_factory import (cf_k8s_configuration, cf_k8s_configuration_operation) +from ._format import k8s_configuration_show_table_format, k8s_configuration_list_table_format + + +def load_command_table(self, _): + + k8s_configuration_sdk = CliCommandType( + operations_tmpl='azext_k8s_configuration.vendored_sdks.operations#SourceControlConfigurationsOperations.{}', + client_factory=cf_k8s_configuration) + + with self.command_group('k8s-configuration', k8s_configuration_sdk, client_factory=cf_k8s_configuration_operation) as g: + g.custom_command('create', 'create_k8s_configuration') + g.custom_command('update', 'update_k8s_configuration') + g.custom_command('delete', 'delete_k8s_configuration', confirmation=True) + g.custom_command('list', 'list_k8s_configuration', table_transformer=k8s_configuration_list_table_format) + g.custom_show_command('show', 'show_k8s_configuration', table_transformer=k8s_configuration_show_table_format) diff --git a/src/k8s-configuration/azext_k8s_configuration/custom.py b/src/k8s-configuration/azext_k8s_configuration/custom.py new file mode 100644 index 00000000000..de6f0dfc5ca --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/custom.py @@ -0,0 +1,351 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +import base64 +import io +from urllib.parse import urlparse +from azure.cli.core.azclierror import InvalidArgumentValueError, ResourceNotFoundError, \ + RequiredArgumentMissingError, MutuallyExclusiveArgumentError, CommandNotFoundError +from knack.log import get_logger +from paramiko.ed25519key import Ed25519Key +from paramiko.hostkeys import HostKeyEntry +from paramiko.ssh_exception import SSHException +from Crypto.PublicKey import RSA, ECC, DSA + +from azext_k8s_configuration.vendored_sdks.models import SourceControlConfiguration +from azext_k8s_configuration.vendored_sdks.models import HelmOperatorProperties +from azext_k8s_configuration.vendored_sdks.models import ErrorResponseException +from ._validators import validate_configuration_name + +logger = get_logger(__name__) + + +def show_k8s_configuration(client, resource_group_name, cluster_name, name, cluster_type): + """Get an existing Kubernetes Source Control Configuration. + + """ + # Determine ClusterRP + cluster_rp = __get_cluster_type(cluster_type) + + try: + config = client.get(resource_group_name, cluster_rp, cluster_type, cluster_name, name) + return __fix_compliance_state(config) + except ErrorResponseException as ex: + # Customize the error message for resources not found + if ex.response.status_code == 404: + # If Cluster not found + if ex.message.__contains__("(ResourceNotFound)"): + message = ex.message + recommendation = 'Verify that the --cluster-type is correct and the Resource ' \ + '{0}/{1}/{2} exists'.format(cluster_rp, cluster_type, cluster_name) + # If Configuration not found + elif ex.message.__contains__("Operation returned an invalid status code 'Not Found'"): + message = '(ConfigurationNotFound) The Resource {0}/{1}/{2}/Microsoft.KubernetesConfiguration/' \ + 'sourcecontrolConfigurations/{3} could not be found!'.format(cluster_rp, cluster_type, + cluster_name, name) + recommendation = 'Verify that the Resource {0}/{1}/{2}/Microsoft.KubernetesConfiguration' \ + '/sourcecontrolConfigurations/{3} exists'.format(cluster_rp, cluster_type, + cluster_name, name) + else: + message = ex.message + recommendation = '' + raise ResourceNotFoundError(message, recommendation) from ex + + +# pylint: disable=too-many-locals +def create_k8s_configuration(client, resource_group_name, cluster_name, name, repository_url, scope, cluster_type, + operator_instance_name=None, operator_namespace='default', + helm_operator_chart_version='1.2.0', operator_type='flux', operator_params='', + ssh_private_key='', ssh_private_key_file='', https_user='', https_key='', + ssh_known_hosts='', ssh_known_hosts_file='', enable_helm_operator=None, + helm_operator_params=''): + """Create a new Kubernetes Source Control Configuration. + + """ + # Validate configuration name + validate_configuration_name(name) + + # Determine ClusterRP + cluster_rp = __get_cluster_type(cluster_type) + + # Determine operatorInstanceName + if operator_instance_name is None: + operator_instance_name = name + + # Create helmOperatorProperties object + helm_operator_properties = None + if enable_helm_operator: + helm_operator_properties = HelmOperatorProperties() + helm_operator_properties.chart_version = helm_operator_chart_version.strip() + helm_operator_properties.chart_values = helm_operator_params.strip() + + protected_settings = validate_and_get_protected_settings(ssh_private_key, + ssh_private_key_file, + https_user, + https_key) + knownhost_data = get_data_from_key_or_file(ssh_known_hosts, ssh_known_hosts_file) + if knownhost_data: + validate_known_hosts(knownhost_data) + + # Flag which parameters have been set and validate these settings against the set repository url + ssh_private_key_set = ssh_private_key != '' or ssh_private_key_file != '' + known_hosts_contents_set = knownhost_data != '' + https_auth_set = https_user != '' and https_key != '' + validate_url_with_params(repository_url, + ssh_private_key_set=ssh_private_key_set, + known_hosts_contents_set=known_hosts_contents_set, + https_auth_set=https_auth_set) + + # Create sourceControlConfiguration object + source_control_configuration = SourceControlConfiguration(repository_url=repository_url, + operator_namespace=operator_namespace, + operator_instance_name=operator_instance_name, + operator_type=operator_type, + operator_params=operator_params, + configuration_protected_settings=protected_settings, + operator_scope=scope, + ssh_known_hosts_contents=knownhost_data, + enable_helm_operator=enable_helm_operator, + helm_operator_properties=helm_operator_properties) + + # Try to create the resource + config = client.create_or_update(resource_group_name, cluster_rp, cluster_type, cluster_name, + name, source_control_configuration) + + return __fix_compliance_state(config) + + +def update_k8s_configuration(client, resource_group_name, cluster_name, name, cluster_type, + repository_url=None, operator_params=None, ssh_known_hosts='', + ssh_known_hosts_file='', enable_helm_operator=None, helm_operator_chart_version=None, + helm_operator_params=None): + """Update an existing Kubernetes Source Control Configuration. + + """ + + # TODO: Remove this after we eventually get PATCH implemented for update and uncomment + raise CommandNotFoundError( + "\"k8s-configuration update\" currently is not available. " + "Use \"k8s-configuration create\" to update a previously created configuration." + ) + + # # Determine ClusterRP + # cluster_rp = __get_cluster_type(cluster_type) + + # source_control_configuration_name = name.strip() + + # config = client.get(resource_group_name, cluster_rp, cluster_type, cluster_name, + # source_control_configuration_name) + # update_yes = False + + # # Set input values, if they are supplied + # if repository_url is not None: + # config.repository_url = repository_url + # update_yes = True + + # if operator_params is not None: + # config.operator_params = operator_params + # update_yes = True + + # knownhost_data = get_data_from_key_or_file(ssh_known_hosts, ssh_known_hosts_file) + # if knownhost_data: + # validate_known_hosts(knownhost_data) + # config.ssh_known_hosts_contents = knownhost_data + # update_yes = True + + # if enable_helm_operator is not None: + # config.enable_helm_operator = enable_helm_operator + # update_yes = True + + # # Get the helm operator properties from the config and set them + # if config.helm_operator_properties is None: + # config.helm_operator_properties = HelmOperatorProperties() + # if helm_operator_chart_version is not None: + # config.helm_operator_properties.chart_version = helm_operator_chart_version.strip() + # update_yes = True + # if helm_operator_params is not None: + # config.helm_operator_properties.chart_values = helm_operator_params.strip() + # update_yes = True + + # if update_yes is False: + # raise RequiredArgumentMissingError( + # 'Invalid update. No values to update!', + # 'Verify that at least one changed parameter is provided in the update command') + + # # Flag which parameters have been set and validate these settings against the set repository url + # known_hosts_contents_set = config.ssh_known_hosts_contents != "" + # validate_url_with_params(config.repository_url, + # ssh_private_key_set=False, + # known_hosts_contents_set=known_hosts_contents_set, + # https_auth_set=False) + + # config = client.create_or_update(resource_group_name, cluster_rp, cluster_type, cluster_name, + # source_control_configuration_name, config) + + # return __fix_compliance_state(config) + + +def list_k8s_configuration(client, resource_group_name, cluster_name, cluster_type): + cluster_rp = __get_cluster_type(cluster_type) + return client.list(resource_group_name, cluster_rp, cluster_type, cluster_name) + + +def delete_k8s_configuration(client, resource_group_name, cluster_name, name, cluster_type): + """Delete an existing Kubernetes Source Control Configuration. + + """ + # Determine ClusterRP + cluster_rp = __get_cluster_type(cluster_type) + + source_control_configuration_name = name + + return client.delete(resource_group_name, cluster_rp, cluster_type, cluster_name, source_control_configuration_name) + + +def validate_and_get_protected_settings(ssh_private_key, ssh_private_key_file, https_user, https_key): + protected_settings = {} + ssh_private_key_data = get_data_from_key_or_file(ssh_private_key, ssh_private_key_file) + + # Add gitops private key data to protected settings if exists + # Dry-run all key types to determine if the private key is in a valid format + invalid_rsa_key, invalid_ecc_key, invalid_dsa_key, invalid_ed25519_key = (False, False, False, False) + if ssh_private_key_data != '': + try: + RSA.import_key(from_base64(ssh_private_key_data)) + except ValueError: + invalid_rsa_key = True + try: + ECC.import_key(from_base64(ssh_private_key_data)) + except ValueError: + invalid_ecc_key = True + try: + DSA.import_key(from_base64(ssh_private_key_data)) + except ValueError: + invalid_dsa_key = True + try: + key_obj = io.StringIO(from_base64(ssh_private_key_data).decode('utf-8')) + Ed25519Key(file_obj=key_obj) + except SSHException: + invalid_ed25519_key = True + + if invalid_rsa_key and invalid_ecc_key and invalid_dsa_key and invalid_ed25519_key: + raise InvalidArgumentValueError( + 'Error! ssh private key provided in invalid format', + 'Verify the key provided is a valid PEM-formatted key of type RSA, ECC, DSA, or Ed25519') + protected_settings["sshPrivateKey"] = ssh_private_key_data + + # Check if both httpsUser and httpsKey exist, then add to protected settings + if https_user != '' and https_key != '': + protected_settings['httpsUser'] = to_base64(https_user) + protected_settings['httpsKey'] = to_base64(https_key) + elif https_user != '': + raise RequiredArgumentMissingError( + 'Error! --https-user used without --https-key', + 'Try providing both --https-user and --https-key together') + elif https_key != '': + raise RequiredArgumentMissingError( + 'Error! --http-key used without --http-user', + 'Try providing both --https-user and --https-key together') + + return protected_settings + + +def __get_cluster_type(cluster_type): + if cluster_type.lower() == 'connectedclusters': + return 'Microsoft.Kubernetes' + # Since cluster_type is an enum of only two values, if not connectedClusters, it will be managedClusters. + return 'Microsoft.ContainerService' + + +def __fix_compliance_state(config): + # If we get Compliant/NonCompliant as compliance_sate, change them before returning + if config.compliance_status.compliance_state.lower() == 'noncompliant': + config.compliance_status.compliance_state = 'Failed' + elif config.compliance_status.compliance_state.lower() == 'compliant': + config.compliance_status.compliance_state = 'Installed' + + return config + + +def validate_url_with_params(repository_url, ssh_private_key_set, known_hosts_contents_set, https_auth_set): + scheme = urlparse(repository_url).scheme + + if scheme in ('http', 'https'): + if ssh_private_key_set: + raise MutuallyExclusiveArgumentError( + 'Error! An ssh private key cannot be used with an http(s) url', + 'Verify the url provided is a valid ssh url and not an http(s) url') + if known_hosts_contents_set: + raise MutuallyExclusiveArgumentError( + 'Error! ssh known_hosts cannot be used with an http(s) url', + 'Verify the url provided is a valid ssh url and not an http(s) url') + if not https_auth_set and scheme == 'https': + logger.warning('Warning! https url is being used without https auth params, ensure the repository ' + 'url provided is not a private repo') + else: + if https_auth_set: + raise MutuallyExclusiveArgumentError( + 'Error! https auth (--https-user and --https-key) cannot be used with a non-http(s) url', + 'Verify the url provided is a valid http(s) url and not an ssh url') + + +def validate_known_hosts(knownhost_data): + try: + knownhost_str = from_base64(knownhost_data).decode('utf-8') + except Exception as ex: + raise InvalidArgumentValueError( + 'Error! ssh known_hosts is not a valid utf-8 base64 encoded string', + 'Verify that the string provided safely decodes into a valid utf-8 format') from ex + lines = knownhost_str.split('\n') + for line in lines: + line = line.strip(' ') + line_len = len(line) + if (line_len == 0) or (line[0] == "#"): + continue + try: + host_key = HostKeyEntry.from_line(line) + if not host_key: + raise Exception('not enough fields found in known_hosts line') + except Exception as ex: + raise InvalidArgumentValueError( + 'Error! ssh known_hosts provided in wrong format', + 'Verify that all lines in the known_hosts contents are provided in a valid sshd(8) format') from ex + + +def get_data_from_key_or_file(key, filepath): + if key != '' and filepath != '': + raise MutuallyExclusiveArgumentError( + 'Error! Both textual key and key filepath cannot be provided', + 'Try providing the file parameter without providing the plaintext parameter') + data = '' + if filepath != '': + data = read_key_file(filepath) + elif key != '': + data = key + return data + + +def read_key_file(path): + try: + with open(path, "r") as myfile: # user passed in filename + data_list = myfile.readlines() # keeps newline characters intact + data_list_len = len(data_list) + if (data_list_len) <= 0: + raise Exception("File provided does not contain any data") + raw_data = ''.join(data_list) + return to_base64(raw_data) + except Exception as ex: + raise InvalidArgumentValueError( + 'Error! Unable to read key file specified with: {0}'.format(ex), + 'Verify that the filepath specified exists and contains valid utf-8 data') from ex + + +def from_base64(base64_str): + return base64.b64decode(base64_str) + + +def to_base64(raw_data): + bytes_data = raw_data.encode('utf-8') + return base64.b64encode(bytes_data).decode('utf-8') diff --git a/src/k8s-configuration/azext_k8s_configuration/tests/__init__.py b/src/k8s-configuration/azext_k8s_configuration/tests/__init__.py new file mode 100644 index 00000000000..99c0f28cd71 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/tests/__init__.py @@ -0,0 +1,5 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# ----------------------------------------------------------------------------- diff --git a/src/k8s-configuration/azext_k8s_configuration/tests/latest/__init__.py b/src/k8s-configuration/azext_k8s_configuration/tests/latest/__init__.py new file mode 100644 index 00000000000..99c0f28cd71 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/tests/latest/__init__.py @@ -0,0 +1,5 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# ----------------------------------------------------------------------------- diff --git a/src/k8s-configuration/azext_k8s_configuration/tests/latest/recordings/test_k8s_configuration_success.yaml b/src/k8s-configuration/azext_k8s_configuration/tests/latest/recordings/test_k8s_configuration_success.yaml new file mode 100644 index 00000000000..df066387443 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/tests/latest/recordings/test_k8s_configuration_success.yaml @@ -0,0 +1,441 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - k8s-configuration show + Connection: + - keep-alive + ParameterSetName: + - -g -c -n --cluster-type + User-Agent: + - python/3.9.0 (Windows-10-10.0.19041-SP0) msrest/0.6.21 msrest_azure/0.6.4 + azure-mgmt-kubernetesconfiguration/0.2.0 Azure-SDK-For-Python AZURECLI/2.19.1 + accept-language: + - en-US + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/cli-test-config10?api-version=2021-03-01 + response: + body: + string: '{"error":{"code":"ResourceNotFound","message":"SourceControlConfiguration + with name ''cli-test-config10'' not found."}}' + headers: + api-supported-versions: + - 2019-11-01-Preview, 2020-07-01-Preview, 2020-10-01-Preview, 2021-03-01 + cache-control: + - no-cache + content-length: + - '117' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 10 Feb 2021 22:59:01 GMT + expires: + - '-1' + pragma: + - no-cache + server: + - openresty/1.15.8.2 + strict-transport-security: + - max-age=31536000; includeSubDomains + x-content-type-options: + - nosniff + status: + code: 404 + message: Not Found +- request: + body: '{"properties": {"repositoryUrl": "git://github.com/anubhav929/flux-get-started", + "operatorNamespace": "cli-test-config10-opns", "operatorInstanceName": "cli-test-config10-opin", + "operatorType": "flux", "operatorParams": "--git-readonly ", "configurationProtectedSettings": + {"sshPrivateKey": "LS0tLS1CRUdJTiBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0KYjNCbGJuTnphQzFyWlhrdGRqRUFBQUFBQkc1dmJtVUFBQUFFYm05dVpRQUFBQUFBQUFBQkFBQUJsd0FBQUFkemMyZ3RjbgpOaEFBQUFBd0VBQVFBQUFZRUFxZlBtNlc3YkVLTmVvN3VCQzhTMXYydUpPS1NZWGNmanlpVEk2djNkZUhRSjJtMGFRajB0CmtwM05qMUZkRUsrMkVXTy9xNGFkWUpaS0ZZSjluWTZyREZOSXBZdmVWaVNUQjhITzI5VVdySTRLVGZMRGhiVmVCV0pjQVcKMkFpZ0ZnTU5qdTZXa0JVL1NWK1FCVHJiRVl6RFhpOTVNR1ZveTVKV3drdkdtakRaOHFSaEFxbU0rdUF4S1I4Z1lyRllPZgpRbC9zM2I5ajJKQ1VtVFlwYkxqMkJPd0JNQ1J3NlFQY0lVcVlaaUl3MUNNaXZKZ2tVQTdwUlRCZHVsYXlXNWQ2MTl4RFNsCmZ6N1JuU0tKM3RwanEwZThBTmtkU1h4SjQrMXhpNm5IM0lVY1ZBM1NzcVhWam80ak5sNU5EWkJlTDNpQ0xXSVZYUkpDemsKNGg3a2pXVkQ3UnNDNGJDOTF6MzlZMDlnK3ZIdjErZFplUmNYZWIvNkFzbTBEeHVhRGo2cVVCVm9JOWkwbzFKbndiMnA0MQpGV2prazljc054a2dnajMzU3ozTWJRTVN0bTFLaWU2bHNRamlMUXdGT3Qwd3lFTnova2RUR25idkVMUTN3aWdUdVFrelFOCnlMR2dmK3FXZnhqL1l1MWt5b0xrQVpqT3JxdEttalVILzk3Y3lncWhBQUFGa08zNi9uWHQrdjUxQUFBQUIzTnphQzF5YzIKRUFBQUdCQUtuejV1bHUyeENqWHFPN2dRdkV0YjlyaVRpa21GM0g0OG9reU9yOTNYaDBDZHB0R2tJOUxaS2R6WTlSWFJDdgp0aEZqdjZ1R25XQ1dTaFdDZloyT3F3eFRTS1dMM2xZa2t3ZkJ6dHZWRnF5T0NrM3l3NFcxWGdWaVhBRnRnSW9CWUREWTd1CmxwQVZQMGxma0FVNjJ4R013MTR2ZVRCbGFNdVNWc0pMeHBvdzJmS2tZUUtwalByZ01Ta2ZJR0t4V0RuMEpmN04yL1k5aVEKbEprMktXeTQ5Z1RzQVRBa2NPa0QzQ0ZLbUdZaU1OUWpJcnlZSkZBTzZVVXdYYnBXc2x1WGV0ZmNRMHBYOCswWjBpaWQ3YQpZNnRIdkFEWkhVbDhTZVB0Y1l1cHg5eUZIRlFOMHJLbDFZNk9JelplVFEyUVhpOTRnaTFpRlYwU1FzNU9JZTVJMWxRKzBiCkF1R3d2ZGM5L1dOUFlQcng3OWZuV1hrWEYzbS8rZ0xKdEE4Ym1nNCtxbEFWYUNQWXRLTlNaOEc5cWVOUlZvNUpQWExEY1oKSUlJOTkwczl6RzBERXJadFNvbnVwYkVJNGkwTUJUcmRNTWhEYy81SFV4cDI3eEMwTjhJb0U3a0pNMERjaXhvSC9xbG44WQovMkx0Wk1xQzVBR1l6cTZyU3BvMUIvL2UzTW9Lb1FBQUFBTUJBQUVBQUFHQkFKSnJUVTlqY0Z4ZlE1UHdZUGRRbS95MG10CjR3QUEwYnY0WlNOcjh0dy9hWWtqeWFybnJPMWtwd3BiNkpySkpKcjZRL3Vjdi9CK3RFejhMRVQ1REViMTBKQzVlRWJ5THMKRTdnbEl5Q0Y3eWp1bnJZVkpwbzFiVEZhVWtYd24wTkdlQ2JkWHNlODdhWDFISmdQemdmZ2dhcTk2aks5ZWtKcXJzQXM4VwpGWjZWNDgrR0N3WU9LU1dpclBmdWx5b3YvQURCOVZJVzdTQ3lWek9uTGRGTWRVZXJBMjI3Y3NUaEtTZnI0MzFDQjU2SE43CmFkdnRmNnR4alV0TXBoTjV5ZVBiRmxVZS9Wb2VQY1hNdXA4OXN3V2gvd3ZScklCbytUYXo2SzQxcGFzOEVObjFyemFxL3kKRHlWelJuSGtlMGhKR2ZZelJhbzlZQm5jeHFMOCtXdDQxZFFzQUdhdlIwd3ZNSit5TFpuR0x5amVXaVZkcExjT0FWSGpIOQpITGMrTDdnaGpIZ1VidDNDWG9Wd0gyWktnelI5cmk3bU93YnorejZsN1pwWjlQalJxeU1HcTloYU5vNHVEdjJqbWhGNlZVClBMU2Q3WTczWCtWTFAvWUZqbTBlUzJUbGFRQ3E2Vms0dzJqSHVWcXorcng4SllYb2tidFZXYnFYcmg3VzF5VGk4MXVRQUEKQU1Ba0JaQzF0SThvd29SNDYvL1h1SWQxQjBGRUhGUXBvSHFuVGNSVlVKS2RXb2xJRU5tYVVtdG1UZFVicVYyNGJMa1RtZQpiWHZQdlF3LzJoVk5VVmhWbDNjays1SUZBS0hYVWJ3ZklSWE8vUVlUbFM0ZVdabkFsN0JQSzJQa080SXkvOG1zQVZKRGl4CmkvVm1oaTBYb05lSmxERU9sdzNaY084aTlRZjVSbTNEWmRHUDRha0JsYmk5ekdBWUpqRGFjM0dWdTMxK2pJVG9hUHplbysKeUFDL2svM0J5Slg4enQ1cDRHVXpsNVFKcEVHMnBpQXdJeElKZS8yK3pBMXU5dmhma0FBQURCQU5NZHdhemx5MXNpd0dXbQpJWSs4VFZMN1EwQ1pFTWxTL0VraE1YM2FNQnZYaURXd2cwVk8zKytXUDhlMWhDSUxvNmdqL0N2dFdLdGEzVlozUWFScHZ5CkhCVEp4Q205NHZQOXFPelhTRGZ0WVRrSHh1SFdQaklhb010N0YyL0srejJiZTdESmhvL0ZwMVY0U2x2R1ljWHdqaWhEaDAKbHF1bUltOEJJei9taHpjZTFKR0VMUUdJeXk4RDI0dTNtY2NhSFoxYWY1V3A5Y1VCZ09POXEwa3B1WVhEdHpPSk9UTVozUQpNUm5xdXVVM1ppRHdmRGltZzdsZktwWGkxZzFxeWZUd0FBQU1FQXpoWEdhTVdBM1pUT1hqWWhPTUhkdTk0R2RNcHNXYWo0CjBsMmZ6YzdFWTlzWEdLZ01XMllvRXk5UVNSTDRPUmNMaUFKTDRLZGdZeGZzeVdma1U1d21TbGZXNjlrb0R2WTE0LzNWbWYKZ0NTUkxvL0RnTUZtOGFNK3pUVzhWYTVpclJXWFpEeHNXb0RiNzdIZ2JZaE90M29iOEFWWUh4akk3N1k3MXlBUzhXS2xRSQpYQi9qZ01vN1BCL3BTMVVYSEhCcndxQkdwM3M5aThab0E0L2hLY0pvaEtWSDZGL0Z2Rk1jWHZTNjZOcGNUWHNWQzBVUzNkCkJVY0taNTVvUUhVcnNQQUFBQUdIQnlZWFJvYVd0eVFFeEJVRlJQVUMxU00wZFVUa2xDVXdFQwotLS0tLUVORCBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0K"}, + "operatorScope": "namespace", "sshKnownHostsContents": "Z2l0b3BzLWJpdGJ1Y2tldC10ZXN0LXNlcnZlci5lYXN0dXMuY2xvdWRhcHAuYXp1cmUuY29tIHNzaC1yc2EgQUFBQUIzTnphQzF5YzJFQUFBQURBUUFCQUFBQkFRQytNT0w3bjk2aGs3emVmMDNwak9vMGF3UENISkZ4NU04TjJ2L2tvODgvc202Y2VzOFljdnYyL0hoUlhRSFZHRUxqZjNuTXVGSVJPMEdMdTFabFNreGRUTUhGcXBxYzFjcUM2R3kveUJXRGM1SWFwWnJBMXFxeSsrZVdpelAzQXdMbWsrMUhXWGdtcHljZUtYNU9vd3VNT3cwd3RYRUdTcDhtVk0wV2VpUzEwWnZ5ZVVKK04zbkNvczMyWDhIeVpnc1pMUS9zSTB4NXN6ODQ2am5JZEFOckZsYU9MUTJ1ejRUa0M2ekNvd3lIdzlLWXJ5V2hJZDAraCt5SXQ5dUtqVHZsWFNpdm1ISjViZzdUWWlkbnFtbjI0UGE4WnFpbTE5UGszUjg0cW9qclVmYm1XT3VwUjdYNXZVVWZqYzhERFRxa3FnRmkxcWdVdE1mWGlMRXErZFVa", + "enableHelmOperator": true, "helmOperatorProperties": {"chartVersion": "1.2.0", + "chartValues": "--set git.ssh.secretName=gitops-privatekey-cli-test-config10-opin + --set tillerNamespace=kube-system"}}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - k8s-configuration create + Connection: + - keep-alive + Content-Length: + - '4614' + Content-Type: + - application/json; charset=utf-8 + ParameterSetName: + - -g -n -c -u --cluster-type --scope --operator-instance-name --operator-namespace + --operator-params --git-readonly --ssh-private-key --ssh-known-hosts --enable-helm-operator + --helm-operator-chart-version --helm-operator-params --set git.ssh.secretName + User-Agent: + - python/3.9.0 (Windows-10-10.0.19041-SP0) msrest/0.6.21 msrest_azure/0.6.4 + azure-mgmt-kubernetesconfiguration/0.2.0 Azure-SDK-For-Python AZURECLI/2.19.1 + accept-language: + - en-US + method: PUT + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/cli-test-config10?api-version=2021-03-01 + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/cli-test-config10","name":"cli-test-config10","type":"Microsoft.KubernetesConfiguration/sourceControlConfigurations","properties":{"operatorNamespace":"cli-test-config10-opns","provisioningState":"Succeeded","complianceStatus":{"complianceState":"Pending","lastConfigApplied":"0001-01-01T00:00:00+00:00","message":"{\"OperatorMessage\":null,\"ClusterState\":null}","messageLevel":"Information"},"enableHelmOperator":true,"helmOperatorProperties":{"chartVersion":"1.2.0","chartValues":"--set + git.ssh.secretName=gitops-privatekey-cli-test-config10-opin --set tillerNamespace=kube-system"},"repositoryUrl":"git://github.com/anubhav929/flux-get-started","operatorInstanceName":"cli-test-config10-opin","operatorType":"Flux","operatorScope":"namespace","operatorParams":"--git-readonly","sshKnownHostsContents":"Z2l0b3BzLWJpdGJ1Y2tldC10ZXN0LXNlcnZlci5lYXN0dXMuY2xvdWRhcHAuYXp1cmUuY29tIHNzaC1yc2EgQUFBQUIzTnphQzF5YzJFQUFBQURBUUFCQUFBQkFRQytNT0w3bjk2aGs3emVmMDNwak9vMGF3UENISkZ4NU04TjJ2L2tvODgvc202Y2VzOFljdnYyL0hoUlhRSFZHRUxqZjNuTXVGSVJPMEdMdTFabFNreGRUTUhGcXBxYzFjcUM2R3kveUJXRGM1SWFwWnJBMXFxeSsrZVdpelAzQXdMbWsrMUhXWGdtcHljZUtYNU9vd3VNT3cwd3RYRUdTcDhtVk0wV2VpUzEwWnZ5ZVVKK04zbkNvczMyWDhIeVpnc1pMUS9zSTB4NXN6ODQ2am5JZEFOckZsYU9MUTJ1ejRUa0M2ekNvd3lIdzlLWXJ5V2hJZDAraCt5SXQ5dUtqVHZsWFNpdm1ISjViZzdUWWlkbnFtbjI0UGE4WnFpbTE5UGszUjg0cW9qclVmYm1XT3VwUjdYNXZVVWZqYzhERFRxa3FnRmkxcWdVdE1mWGlMRXErZFVa","configurationProtectedSettings":{},"repositoryPublicKey":""},"systemData":{"createdBy":null,"createdByType":null,"createdAt":"2021-02-10T22:59:03.2209+00:00","lastModifiedBy":null,"lastModifiedByType":null,"lastModifiedAt":"2021-02-10T22:59:03.2209001+00:00"}}' + headers: + api-supported-versions: + - 2019-11-01-Preview, 2020-07-01-Preview, 2020-10-01-Preview, 2021-03-01 + cache-control: + - no-cache + content-length: + - '1876' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 10 Feb 2021 22:59:02 GMT + expires: + - '-1' + location: + - file:///subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/cli-test-config10 + pragma: + - no-cache + server: + - openresty/1.15.8.2 + strict-transport-security: + - max-age=31536000; includeSubDomains + x-content-type-options: + - nosniff + x-ms-ratelimit-remaining-subscription-writes: + - '1199' + status: + code: 201 + message: Created +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - k8s-configuration show + Connection: + - keep-alive + ParameterSetName: + - -g -c -n --cluster-type + User-Agent: + - python/3.9.0 (Windows-10-10.0.19041-SP0) msrest/0.6.21 msrest_azure/0.6.4 + azure-mgmt-kubernetesconfiguration/0.2.0 Azure-SDK-For-Python AZURECLI/2.19.1 + accept-language: + - en-US + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/cli-test-config10?api-version=2021-03-01 + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/cli-test-config10","name":"cli-test-config10","type":"Microsoft.KubernetesConfiguration/sourceControlConfigurations","properties":{"operatorNamespace":"cli-test-config10-opns","provisioningState":"Succeeded","complianceStatus":{"complianceState":"Pending","lastConfigApplied":"0001-01-01T00:00:00+00:00","message":"{\"OperatorMessage\":null,\"ClusterState\":null}","messageLevel":"Information"},"enableHelmOperator":true,"helmOperatorProperties":{"chartVersion":"1.2.0","chartValues":"--set + git.ssh.secretName=gitops-privatekey-cli-test-config10-opin --set tillerNamespace=kube-system"},"repositoryUrl":"git://github.com/anubhav929/flux-get-started","operatorInstanceName":"cli-test-config10-opin","operatorType":"Flux","operatorScope":"namespace","operatorParams":"--git-readonly","sshKnownHostsContents":"Z2l0b3BzLWJpdGJ1Y2tldC10ZXN0LXNlcnZlci5lYXN0dXMuY2xvdWRhcHAuYXp1cmUuY29tIHNzaC1yc2EgQUFBQUIzTnphQzF5YzJFQUFBQURBUUFCQUFBQkFRQytNT0w3bjk2aGs3emVmMDNwak9vMGF3UENISkZ4NU04TjJ2L2tvODgvc202Y2VzOFljdnYyL0hoUlhRSFZHRUxqZjNuTXVGSVJPMEdMdTFabFNreGRUTUhGcXBxYzFjcUM2R3kveUJXRGM1SWFwWnJBMXFxeSsrZVdpelAzQXdMbWsrMUhXWGdtcHljZUtYNU9vd3VNT3cwd3RYRUdTcDhtVk0wV2VpUzEwWnZ5ZVVKK04zbkNvczMyWDhIeVpnc1pMUS9zSTB4NXN6ODQ2am5JZEFOckZsYU9MUTJ1ejRUa0M2ekNvd3lIdzlLWXJ5V2hJZDAraCt5SXQ5dUtqVHZsWFNpdm1ISjViZzdUWWlkbnFtbjI0UGE4WnFpbTE5UGszUjg0cW9qclVmYm1XT3VwUjdYNXZVVWZqYzhERFRxa3FnRmkxcWdVdE1mWGlMRXErZFVa","configurationProtectedSettings":{},"repositoryPublicKey":""},"systemData":{"createdBy":null,"createdByType":null,"createdAt":"2021-02-10T22:59:03.2209+00:00","lastModifiedBy":null,"lastModifiedByType":null,"lastModifiedAt":"2021-02-10T22:59:03.2209001+00:00"}}' + headers: + api-supported-versions: + - 2019-11-01-Preview, 2020-07-01-Preview, 2020-10-01-Preview, 2021-03-01 + cache-control: + - no-cache + content-length: + - '1876' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 10 Feb 2021 22:59:03 GMT + expires: + - '-1' + pragma: + - no-cache + server: + - openresty/1.15.8.2 + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding,Accept-Encoding + x-content-type-options: + - nosniff + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - k8s-configuration delete + Connection: + - keep-alive + Content-Length: + - '0' + ParameterSetName: + - -g -c -n --cluster-type -y + User-Agent: + - python/3.9.0 (Windows-10-10.0.19041-SP0) msrest/0.6.21 msrest_azure/0.6.4 + azure-mgmt-kubernetesconfiguration/0.2.0 Azure-SDK-For-Python AZURECLI/2.19.1 + accept-language: + - en-US + method: DELETE + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/cli-test-config10?api-version=2021-03-01 + response: + body: + string: '{"version":"1.1","content":null,"statusCode":200,"reasonPhrase":"OK","headers":[],"trailingHeaders":[],"requestMessage":null,"isSuccessStatusCode":true}' + headers: + api-supported-versions: + - 2019-11-01-Preview, 2020-07-01-Preview, 2020-10-01-Preview, 2021-03-01 + cache-control: + - no-cache + content-length: + - '152' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 10 Feb 2021 22:59:05 GMT + expires: + - '-1' + pragma: + - no-cache + server: + - openresty/1.15.8.2 + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-ratelimit-remaining-subscription-deletes: + - '14999' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - k8s-configuration show + Connection: + - keep-alive + ParameterSetName: + - -g -c -n --cluster-type + User-Agent: + - python/3.9.0 (Windows-10-10.0.19041-SP0) msrest/0.6.21 msrest_azure/0.6.4 + azure-mgmt-kubernetesconfiguration/0.2.0 Azure-SDK-For-Python AZURECLI/2.19.1 + accept-language: + - en-US + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/cli-test-config11?api-version=2021-03-01 + response: + body: + string: '{"error":{"code":"ResourceNotFound","message":"SourceControlConfiguration + with name ''cli-test-config11'' not found."}}' + headers: + api-supported-versions: + - 2019-11-01-Preview, 2020-07-01-Preview, 2020-10-01-Preview, 2021-03-01 + cache-control: + - no-cache + content-length: + - '117' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 10 Feb 2021 22:59:05 GMT + expires: + - '-1' + pragma: + - no-cache + server: + - openresty/1.15.8.2 + strict-transport-security: + - max-age=31536000; includeSubDomains + x-content-type-options: + - nosniff + status: + code: 404 + message: Not Found +- request: + body: '{"properties": {"repositoryUrl": "https://github.com/jonathan-innis/helm-operator-get-started-private.git", + "operatorNamespace": "cli-test-config11-opns", "operatorInstanceName": "cli-test-config11-opin", + "operatorType": "flux", "operatorParams": "--git-readonly ", "configurationProtectedSettings": + {"httpsUser": "ZmFrZS11c2VybmFtZQ==", "httpsKey": "ZmFrZXBhc3N3b3JkdGhhdGl3b3VsZHVzZWZvcmdpdGh1Yg=="}, + "operatorScope": "namespace", "sshKnownHostsContents": "", "enableHelmOperator": + true, "helmOperatorProperties": {"chartVersion": "1.2.0", "chartValues": "--set + tillerNamespace=kube-system"}}}' + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - k8s-configuration create + Connection: + - keep-alive + Content-Length: + - '595' + Content-Type: + - application/json; charset=utf-8 + ParameterSetName: + - -g -n -c -u --cluster-type --scope --operator-instance-name --operator-namespace + --operator-params --git-readonly --https-user --https-key --enable-helm-operator + --helm-operator-chart-version --helm-operator-params --set tillerNamespace + User-Agent: + - python/3.9.0 (Windows-10-10.0.19041-SP0) msrest/0.6.21 msrest_azure/0.6.4 + azure-mgmt-kubernetesconfiguration/0.2.0 Azure-SDK-For-Python AZURECLI/2.19.1 + accept-language: + - en-US + method: PUT + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/cli-test-config11?api-version=2021-03-01 + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/cli-test-config11","name":"cli-test-config11","type":"Microsoft.KubernetesConfiguration/sourceControlConfigurations","properties":{"operatorNamespace":"cli-test-config11-opns","provisioningState":"Succeeded","complianceStatus":{"complianceState":"Pending","lastConfigApplied":"0001-01-01T00:00:00+00:00","message":"{\"OperatorMessage\":null,\"ClusterState\":null}","messageLevel":"Information"},"enableHelmOperator":true,"helmOperatorProperties":{"chartVersion":"1.2.0","chartValues":"--set + tillerNamespace=kube-system"},"repositoryUrl":"https://github.com/jonathan-innis/helm-operator-get-started-private.git","operatorInstanceName":"cli-test-config11-opin","operatorType":"Flux","operatorScope":"namespace","operatorParams":"--git-readonly","sshKnownHostsContents":"","configurationProtectedSettings":{},"repositoryPublicKey":""},"systemData":{"createdBy":null,"createdByType":null,"createdAt":"2021-02-10T22:59:07.5893423+00:00","lastModifiedBy":null,"lastModifiedByType":null,"lastModifiedAt":"2021-02-10T22:59:07.5893424+00:00"}}' + headers: + api-supported-versions: + - 2019-11-01-Preview, 2020-07-01-Preview, 2020-10-01-Preview, 2021-03-01 + cache-control: + - no-cache + content-length: + - '1260' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 10 Feb 2021 22:59:07 GMT + expires: + - '-1' + location: + - file:///subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/cli-test-config11 + pragma: + - no-cache + server: + - openresty/1.15.8.2 + strict-transport-security: + - max-age=31536000; includeSubDomains + x-content-type-options: + - nosniff + x-ms-ratelimit-remaining-subscription-writes: + - '1199' + status: + code: 201 + message: Created +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - k8s-configuration show + Connection: + - keep-alive + ParameterSetName: + - -g -c -n --cluster-type + User-Agent: + - python/3.9.0 (Windows-10-10.0.19041-SP0) msrest/0.6.21 msrest_azure/0.6.4 + azure-mgmt-kubernetesconfiguration/0.2.0 Azure-SDK-For-Python AZURECLI/2.19.1 + accept-language: + - en-US + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/cli-test-config11?api-version=2021-03-01 + response: + body: + string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/cli-test-config11","name":"cli-test-config11","type":"Microsoft.KubernetesConfiguration/sourceControlConfigurations","properties":{"operatorNamespace":"cli-test-config11-opns","provisioningState":"Succeeded","complianceStatus":{"complianceState":"Pending","lastConfigApplied":"0001-01-01T00:00:00+00:00","message":"{\"OperatorMessage\":null,\"ClusterState\":null}","messageLevel":"Information"},"enableHelmOperator":true,"helmOperatorProperties":{"chartVersion":"1.2.0","chartValues":"--set + tillerNamespace=kube-system"},"repositoryUrl":"https://github.com/jonathan-innis/helm-operator-get-started-private.git","operatorInstanceName":"cli-test-config11-opin","operatorType":"Flux","operatorScope":"namespace","operatorParams":"--git-readonly","sshKnownHostsContents":"","configurationProtectedSettings":{},"repositoryPublicKey":""},"systemData":{"createdBy":null,"createdByType":null,"createdAt":"2021-02-10T22:59:07.5893423+00:00","lastModifiedBy":null,"lastModifiedByType":null,"lastModifiedAt":"2021-02-10T22:59:07.5893424+00:00"}}' + headers: + api-supported-versions: + - 2019-11-01-Preview, 2020-07-01-Preview, 2020-10-01-Preview, 2021-03-01 + cache-control: + - no-cache + content-length: + - '1260' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 10 Feb 2021 22:59:08 GMT + expires: + - '-1' + pragma: + - no-cache + server: + - openresty/1.15.8.2 + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding,Accept-Encoding + x-content-type-options: + - nosniff + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + CommandName: + - k8s-configuration delete + Connection: + - keep-alive + Content-Length: + - '0' + ParameterSetName: + - -g -c -n --cluster-type -y + User-Agent: + - python/3.9.0 (Windows-10-10.0.19041-SP0) msrest/0.6.21 msrest_azure/0.6.4 + azure-mgmt-kubernetesconfiguration/0.2.0 Azure-SDK-For-Python AZURECLI/2.19.1 + accept-language: + - en-US + method: DELETE + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/nanthirg0923/providers/Microsoft.Kubernetes/connectedClusters/nanthicluster0923/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/cli-test-config11?api-version=2021-03-01 + response: + body: + string: '{"version":"1.1","content":null,"statusCode":200,"reasonPhrase":"OK","headers":[],"trailingHeaders":[],"requestMessage":null,"isSuccessStatusCode":true}' + headers: + api-supported-versions: + - 2019-11-01-Preview, 2020-07-01-Preview, 2020-10-01-Preview, 2021-03-01 + cache-control: + - no-cache + content-length: + - '152' + content-type: + - application/json; charset=utf-8 + date: + - Wed, 10 Feb 2021 22:59:08 GMT + expires: + - '-1' + pragma: + - no-cache + server: + - openresty/1.15.8.2 + strict-transport-security: + - max-age=31536000; includeSubDomains + transfer-encoding: + - chunked + vary: + - Accept-Encoding + x-content-type-options: + - nosniff + x-ms-ratelimit-remaining-subscription-deletes: + - '14999' + status: + code: 200 + message: OK +version: 1 diff --git a/src/k8s-configuration/azext_k8s_configuration/tests/latest/test_kubernetesconfiguration_scenario.py b/src/k8s-configuration/azext_k8s_configuration/tests/latest/test_kubernetesconfiguration_scenario.py new file mode 100644 index 00000000000..11b6a43f512 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/tests/latest/test_kubernetesconfiguration_scenario.py @@ -0,0 +1,138 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +import os + +from azure.cli.testsdk import (ScenarioTest, ResourceGroupPreparer, record_only) +from azure.cli.core.azclierror import InvalidArgumentValueError, ResourceNotFoundError + +TEST_DIR = os.path.abspath(os.path.join(os.path.abspath(__file__), '..')) + + +class K8sConfigurationScenarioTest(ScenarioTest): + @ResourceGroupPreparer(name_prefix='cli_test_k8s_configuration') + @record_only() + def test_k8s_configuration_success(self): + + # -------------------------------------------------------------------- + # SSH SCENARIO TEST + # -------------------------------------------------------------------- + self.kwargs.update({ + 'name': 'cli-test-config10', + 'cluster_name': 'nanthicluster0923', + 'rg': 'nanthirg0923', + 'repo_url': 'git://github.com/anubhav929/flux-get-started', + 'operator_instance_name': 'cli-test-config10-opin', + 'operator_namespace': 'cli-test-config10-opns', + 'cluster_type': 'connectedClusters', + 'scope': 'namespace', + 'ssh_private_key': 'LS0tLS1CRUdJTiBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0KYjNCbGJuTnphQzFyWlhrdGRqRUFBQUFBQkc1dmJtVUFBQUFFYm05dVpRQUFBQUFBQUFBQkFBQUJsd0FBQUFkemMyZ3RjbgpOaEFBQUFBd0VBQVFBQUFZRUFxZlBtNlc3YkVLTmVvN3VCQzhTMXYydUpPS1NZWGNmanlpVEk2djNkZUhRSjJtMGFRajB0CmtwM05qMUZkRUsrMkVXTy9xNGFkWUpaS0ZZSjluWTZyREZOSXBZdmVWaVNUQjhITzI5VVdySTRLVGZMRGhiVmVCV0pjQVcKMkFpZ0ZnTU5qdTZXa0JVL1NWK1FCVHJiRVl6RFhpOTVNR1ZveTVKV3drdkdtakRaOHFSaEFxbU0rdUF4S1I4Z1lyRllPZgpRbC9zM2I5ajJKQ1VtVFlwYkxqMkJPd0JNQ1J3NlFQY0lVcVlaaUl3MUNNaXZKZ2tVQTdwUlRCZHVsYXlXNWQ2MTl4RFNsCmZ6N1JuU0tKM3RwanEwZThBTmtkU1h4SjQrMXhpNm5IM0lVY1ZBM1NzcVhWam80ak5sNU5EWkJlTDNpQ0xXSVZYUkpDemsKNGg3a2pXVkQ3UnNDNGJDOTF6MzlZMDlnK3ZIdjErZFplUmNYZWIvNkFzbTBEeHVhRGo2cVVCVm9JOWkwbzFKbndiMnA0MQpGV2prazljc054a2dnajMzU3ozTWJRTVN0bTFLaWU2bHNRamlMUXdGT3Qwd3lFTnova2RUR25idkVMUTN3aWdUdVFrelFOCnlMR2dmK3FXZnhqL1l1MWt5b0xrQVpqT3JxdEttalVILzk3Y3lncWhBQUFGa08zNi9uWHQrdjUxQUFBQUIzTnphQzF5YzIKRUFBQUdCQUtuejV1bHUyeENqWHFPN2dRdkV0YjlyaVRpa21GM0g0OG9reU9yOTNYaDBDZHB0R2tJOUxaS2R6WTlSWFJDdgp0aEZqdjZ1R25XQ1dTaFdDZloyT3F3eFRTS1dMM2xZa2t3ZkJ6dHZWRnF5T0NrM3l3NFcxWGdWaVhBRnRnSW9CWUREWTd1CmxwQVZQMGxma0FVNjJ4R013MTR2ZVRCbGFNdVNWc0pMeHBvdzJmS2tZUUtwalByZ01Ta2ZJR0t4V0RuMEpmN04yL1k5aVEKbEprMktXeTQ5Z1RzQVRBa2NPa0QzQ0ZLbUdZaU1OUWpJcnlZSkZBTzZVVXdYYnBXc2x1WGV0ZmNRMHBYOCswWjBpaWQ3YQpZNnRIdkFEWkhVbDhTZVB0Y1l1cHg5eUZIRlFOMHJLbDFZNk9JelplVFEyUVhpOTRnaTFpRlYwU1FzNU9JZTVJMWxRKzBiCkF1R3d2ZGM5L1dOUFlQcng3OWZuV1hrWEYzbS8rZ0xKdEE4Ym1nNCtxbEFWYUNQWXRLTlNaOEc5cWVOUlZvNUpQWExEY1oKSUlJOTkwczl6RzBERXJadFNvbnVwYkVJNGkwTUJUcmRNTWhEYy81SFV4cDI3eEMwTjhJb0U3a0pNMERjaXhvSC9xbG44WQovMkx0Wk1xQzVBR1l6cTZyU3BvMUIvL2UzTW9Lb1FBQUFBTUJBQUVBQUFHQkFKSnJUVTlqY0Z4ZlE1UHdZUGRRbS95MG10CjR3QUEwYnY0WlNOcjh0dy9hWWtqeWFybnJPMWtwd3BiNkpySkpKcjZRL3Vjdi9CK3RFejhMRVQ1REViMTBKQzVlRWJ5THMKRTdnbEl5Q0Y3eWp1bnJZVkpwbzFiVEZhVWtYd24wTkdlQ2JkWHNlODdhWDFISmdQemdmZ2dhcTk2aks5ZWtKcXJzQXM4VwpGWjZWNDgrR0N3WU9LU1dpclBmdWx5b3YvQURCOVZJVzdTQ3lWek9uTGRGTWRVZXJBMjI3Y3NUaEtTZnI0MzFDQjU2SE43CmFkdnRmNnR4alV0TXBoTjV5ZVBiRmxVZS9Wb2VQY1hNdXA4OXN3V2gvd3ZScklCbytUYXo2SzQxcGFzOEVObjFyemFxL3kKRHlWelJuSGtlMGhKR2ZZelJhbzlZQm5jeHFMOCtXdDQxZFFzQUdhdlIwd3ZNSit5TFpuR0x5amVXaVZkcExjT0FWSGpIOQpITGMrTDdnaGpIZ1VidDNDWG9Wd0gyWktnelI5cmk3bU93YnorejZsN1pwWjlQalJxeU1HcTloYU5vNHVEdjJqbWhGNlZVClBMU2Q3WTczWCtWTFAvWUZqbTBlUzJUbGFRQ3E2Vms0dzJqSHVWcXorcng4SllYb2tidFZXYnFYcmg3VzF5VGk4MXVRQUEKQU1Ba0JaQzF0SThvd29SNDYvL1h1SWQxQjBGRUhGUXBvSHFuVGNSVlVKS2RXb2xJRU5tYVVtdG1UZFVicVYyNGJMa1RtZQpiWHZQdlF3LzJoVk5VVmhWbDNjays1SUZBS0hYVWJ3ZklSWE8vUVlUbFM0ZVdabkFsN0JQSzJQa080SXkvOG1zQVZKRGl4CmkvVm1oaTBYb05lSmxERU9sdzNaY084aTlRZjVSbTNEWmRHUDRha0JsYmk5ekdBWUpqRGFjM0dWdTMxK2pJVG9hUHplbysKeUFDL2svM0J5Slg4enQ1cDRHVXpsNVFKcEVHMnBpQXdJeElKZS8yK3pBMXU5dmhma0FBQURCQU5NZHdhemx5MXNpd0dXbQpJWSs4VFZMN1EwQ1pFTWxTL0VraE1YM2FNQnZYaURXd2cwVk8zKytXUDhlMWhDSUxvNmdqL0N2dFdLdGEzVlozUWFScHZ5CkhCVEp4Q205NHZQOXFPelhTRGZ0WVRrSHh1SFdQaklhb010N0YyL0srejJiZTdESmhvL0ZwMVY0U2x2R1ljWHdqaWhEaDAKbHF1bUltOEJJei9taHpjZTFKR0VMUUdJeXk4RDI0dTNtY2NhSFoxYWY1V3A5Y1VCZ09POXEwa3B1WVhEdHpPSk9UTVozUQpNUm5xdXVVM1ppRHdmRGltZzdsZktwWGkxZzFxeWZUd0FBQU1FQXpoWEdhTVdBM1pUT1hqWWhPTUhkdTk0R2RNcHNXYWo0CjBsMmZ6YzdFWTlzWEdLZ01XMllvRXk5UVNSTDRPUmNMaUFKTDRLZGdZeGZzeVdma1U1d21TbGZXNjlrb0R2WTE0LzNWbWYKZ0NTUkxvL0RnTUZtOGFNK3pUVzhWYTVpclJXWFpEeHNXb0RiNzdIZ2JZaE90M29iOEFWWUh4akk3N1k3MXlBUzhXS2xRSQpYQi9qZ01vN1BCL3BTMVVYSEhCcndxQkdwM3M5aThab0E0L2hLY0pvaEtWSDZGL0Z2Rk1jWHZTNjZOcGNUWHNWQzBVUzNkCkJVY0taNTVvUUhVcnNQQUFBQUdIQnlZWFJvYVd0eVFFeEJVRlJQVUMxU00wZFVUa2xDVXdFQwotLS0tLUVORCBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0K', + 'ssh_known_hosts': 'Z2l0b3BzLWJpdGJ1Y2tldC10ZXN0LXNlcnZlci5lYXN0dXMuY2xvdWRhcHAuYXp1cmUuY29tIHNzaC1yc2EgQUFBQUIzTnphQzF5YzJFQUFBQURBUUFCQUFBQkFRQytNT0w3bjk2aGs3emVmMDNwak9vMGF3UENISkZ4NU04TjJ2L2tvODgvc202Y2VzOFljdnYyL0hoUlhRSFZHRUxqZjNuTXVGSVJPMEdMdTFabFNreGRUTUhGcXBxYzFjcUM2R3kveUJXRGM1SWFwWnJBMXFxeSsrZVdpelAzQXdMbWsrMUhXWGdtcHljZUtYNU9vd3VNT3cwd3RYRUdTcDhtVk0wV2VpUzEwWnZ5ZVVKK04zbkNvczMyWDhIeVpnc1pMUS9zSTB4NXN6ODQ2am5JZEFOckZsYU9MUTJ1ejRUa0M2ekNvd3lIdzlLWXJ5V2hJZDAraCt5SXQ5dUtqVHZsWFNpdm1ISjViZzdUWWlkbnFtbjI0UGE4WnFpbTE5UGszUjg0cW9qclVmYm1XT3VwUjdYNXZVVWZqYzhERFRxa3FnRmkxcWdVdE1mWGlMRXErZFVa' + }) + + # Check that the configuration does not already exist + with self.assertRaises(ResourceNotFoundError): + self.cmd('k8s-configuration show -g {rg} -c {cluster_name} -n {name} --cluster-type {cluster_type}') + + # Create a configuration + self.cmd(''' k8s-configuration create -g {rg} + -n {name} + -c {cluster_name} + -u {repo_url} + --cluster-type {cluster_type} + --scope {scope} + --operator-instance-name {operator_instance_name} + --operator-namespace {operator_namespace} + --operator-params \"--git-readonly \" + --ssh-private-key {ssh_private_key} + --ssh-known-hosts {ssh_known_hosts} + --enable-helm-operator + --helm-operator-chart-version 1.2.0 + --helm-operator-params \"--set git.ssh.secretName=gitops-privatekey-{operator_instance_name} --set tillerNamespace=kube-system\" ''', + checks=[ + self.check('name', '{name}'), + self.check('resourceGroup', '{rg}'), + self.check('operatorInstanceName', '{operator_instance_name}'), + self.check('operatorNamespace', '{operator_namespace}'), + self.check('provisioningState', 'Succeeded'), + self.check('operatorScope', 'namespace'), + self.check('operatorType', 'Flux'), + self.check('sshKnownHostsContents', '{ssh_known_hosts}') + ]) + + # Get the configuration created + self.cmd('k8s-configuration show -g {rg} -c {cluster_name} -n {name} --cluster-type {cluster_type}', + checks=[ + self.check('name', '{name}'), + self.check('resourceGroup', '{rg}'), + self.check('operatorInstanceName', '{operator_instance_name}'), + self.check('operatorNamespace', '{operator_namespace}'), + self.check('provisioningState', 'Succeeded'), + self.check('operatorScope', 'namespace'), + self.check('operatorType', 'Flux'), + self.check('sshKnownHostsContents', '{ssh_known_hosts}') + ]) + + # Delete the created configuration + self.cmd('k8s-configuration delete -g {rg} -c {cluster_name} -n {name} --cluster-type {cluster_type} -y') + + # -------------------------------------------------------------------- + # HTTPS SCENARIO TEST + # -------------------------------------------------------------------- + self.kwargs.update({ + 'name': 'cli-test-config11', + 'cluster_name': 'nanthicluster0923', + 'rg': 'nanthirg0923', + 'repo_url': 'https://github.com/jonathan-innis/helm-operator-get-started-private.git', + 'operator_instance_name': 'cli-test-config11-opin', + 'operator_namespace': 'cli-test-config11-opns', + 'cluster_type': 'connectedClusters', + 'scope': 'namespace', + 'https_user': 'fake-username', + 'https_key': 'fakepasswordthatiwoulduseforgithub' + }) + + # Check that the configuration does not already exist + with self.assertRaises(ResourceNotFoundError): + self.cmd('k8s-configuration show -g {rg} -c {cluster_name} -n {name} --cluster-type {cluster_type}') + + self.cmd(''' k8s-configuration create -g {rg} + -n {name} + -c {cluster_name} + -u {repo_url} + --cluster-type {cluster_type} + --scope {scope} + --operator-instance-name {operator_instance_name} + --operator-namespace {operator_namespace} + --operator-params \"--git-readonly \" + --https-user {https_user} + --https-key {https_key} + --enable-helm-operator + --helm-operator-chart-version 1.2.0 + --helm-operator-params \"--set tillerNamespace=kube-system\" ''', + checks=[ + self.check('name', '{name}'), + self.check('resourceGroup', '{rg}'), + self.check('operatorInstanceName', '{operator_instance_name}'), + self.check('operatorNamespace', '{operator_namespace}'), + self.check('provisioningState', 'Succeeded'), + self.check('operatorScope', 'namespace'), + self.check('operatorType', 'Flux') + ]) + + # Get the configuration created + self.cmd('k8s-configuration show -g {rg} -c {cluster_name} -n {name} --cluster-type {cluster_type}', + checks=[ + self.check('name', '{name}'), + self.check('resourceGroup', '{rg}'), + self.check('operatorInstanceName', '{operator_instance_name}'), + self.check('operatorNamespace', '{operator_namespace}'), + self.check('provisioningState', 'Succeeded'), + self.check('operatorScope', 'namespace'), + self.check('operatorType', 'Flux'), + ]) + + # Delete the created configuration + self.cmd('k8s-configuration delete -g {rg} -c {cluster_name} -n {name} --cluster-type {cluster_type} -y') diff --git a/src/k8s-configuration/azext_k8s_configuration/tests/latest/test_validators.py b/src/k8s-configuration/azext_k8s_configuration/tests/latest/test_validators.py new file mode 100644 index 00000000000..ce3db8b84f4 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/tests/latest/test_validators.py @@ -0,0 +1,176 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +import unittest +import base64 +from azure.cli.core.azclierror import InvalidArgumentValueError, MutuallyExclusiveArgumentError +from azext_k8s_configuration.custom import validate_and_get_protected_settings, validate_url_with_params, validate_known_hosts +import azext_k8s_configuration._validators as validators +from Crypto.PublicKey import RSA, ECC, DSA +from paramiko.ed25519key import Ed25519Key + + +class TestValidateKeyTypes(unittest.TestCase): + def test_bad_private_key(self): + private_key_encoded = base64.b64encode("this is not a valid private key".encode('utf-8')).decode('utf-8') + err = "Error! ssh private key provided in invalid format" + with self.assertRaises(InvalidArgumentValueError) as cm: + validate_and_get_protected_settings(private_key_encoded, '', '', '') + self.assertEqual(str(cm.exception), err) + + def test_rsa_private_key(self): + rsa_key = "LS0tLS1CRUdJTiBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0KYjNCbGJuTnphQzFyWlhrdGRqRUFBQUFBQkc1dmJtVUFBQUFFYm05dVpRQUFBQUFBQUFBQkFBQUJsd0FBQUFkemMyZ3RjbgpOaEFBQUFBd0VBQVFBQUFZRUF1bVA5M09qRHdjdlEyZHZhRlJNNWYrMEhVSnFvOFJnbmdwaGN3NFZidnd1TVNoQTZFc2FyCjFsam1CNUNnT1NGNHJqNDIvcmdxMW1hWndoSUgvckdPSElNa0lIcjFrZmNKMnBrR3ZhK1NxVm4wWUhzMjBpUW02ay92ZXQKdXdVQ2J1QjlxSU5zL2h2b0ppQ21JMUVpVWZ4VGoxRFJCUG15OXR3Qm52bW5FS1kxZ2NhT2YrS2Y1aGhCc09pd00yZnBRTwp0aTlIcHVzM1JhNXpFeElWbjJzVitpRjVvV3ZZM1JQTTlKNXFPMXRObUtOWll6TjgzbDYxMlBzRmR1Vm1QM2NUUlJtK2pzCjdzZW5jY0U0RitzU0hQMlJpMk5DU0JvZ2RJOFR5VTlzeTM3Szl3bFJ5NGZkWWI1K1o3YUZjMjhTNDdDWlo5dTRFVXdWUEYKbjU4dTUzajU0empwdXNpei9ZWmx3MG5NeEQ5SXI0aHlJZ2s0NlUzVmdHR0NPUytZVTVZT2JURGhPRG5udk5VRkg2NVhCagpEM3l6WVJuRDA3b2swQ1JUR3RCOWMzTjBFNDBjUnlPeVpEQ0l5a0FPdHZXYnBUZzdnaXA2UDc4K2pLVlFnanFwRTVQdi9ICnl1dlB6cUJoUkpWcG5VR1dvWnFlcWJhd2N5RWZwdHFLaTNtWUdVMHBBQUFGa0U5cUs3SlBhaXV5QUFBQUIzTnphQzF5YzIKRUFBQUdCQUxwai9kem93OEhMME5uYjJoVVRPWC90QjFDYXFQRVlKNEtZWE1PRlc3OExqRW9RT2hMR3E5Wlk1Z2VRb0RraAplSzQrTnY2NEt0Wm1tY0lTQi82eGpoeURKQ0I2OVpIM0NkcVpCcjJ2a3FsWjlHQjdOdElrSnVwUDczcmJzRkFtN2dmYWlECmJQNGI2Q1lncGlOUklsSDhVNDlRMFFUNXN2YmNBWjc1cHhDbU5ZSEdqbi9pbitZWVFiRG9zRE5uNlVEcll2UjZick4wV3UKY3hNU0ZaOXJGZm9oZWFGcjJOMFR6UFNlYWp0YlRaaWpXV016Zk41ZXRkajdCWGJsWmo5M0UwVVp2bzdPN0hwM0hCT0JmcgpFaHo5a1l0alFrZ2FJSFNQRThsUGJNdCt5dmNKVWN1SDNXRytmbWUyaFhOdkV1T3dtV2ZidUJGTUZUeForZkx1ZDQrZU00CjZicklzLzJHWmNOSnpNUS9TSytJY2lJSk9PbE4xWUJoZ2prdm1GT1dEbTB3NFRnNTU3elZCUit1VndZdzk4czJFWnc5TzYKSk5Ba1V4clFmWE56ZEJPTkhFY2pzbVF3aU1wQURyYjFtNlU0TzRJcWVqKy9Qb3lsVUlJNnFST1Q3L3g4cnJ6ODZnWVVTVgphWjFCbHFHYW5xbTJzSE1oSDZiYWlvdDVtQmxOS1FBQUFBTUJBQUVBQUFHQkFMaElmSXFacUZKSFRXcllyN24rays4alR3ClFtcGJvWmc1YmZSWGdhdGljaEo4ZGlXOGlNblFFRVRBcFd0OU5FZ0tqbDRrSGRuSnoyUERkZzFIN0ExaHppbkNsdzZMTTAKYUkyMGxyR2NrWWpXNDRNd3ozYmRQNHlURTllSXRiM0pmN1pNSGpqek4rSy96bWN0eWdMeXFZSzVXYTljM1JnMXdIRWFNNAplakUvNDg4M25WUmJvSFJDcjFCVi8wQVVFTTZhNisrRHpVZW9WdWdWL3RsV3RVMlJuQlZ4eCtJS0FVSDZRTHJFU2JkUkRoCkVGUEFhRWtEb3crd3dDcFpqTXBhMHdRZXBDSkhwWkJLN1pBU25EU3R3Y2RKRE4yeHZzdVNOOGg0bkN0MlZWd0xRenJKeVAKU2VjcWM3M1hIc3E3VWx6ZU5veHlTVW9KZ2JjNTZoRzhWYS9ITlhsOUtkdkFlWUVzS1l1OW5NRUprVSt3VHo1KzUvM2wwVQpxSkErb0pTVTducjYydlVKQnljbXg0SFdBcjJ6QkR2QnFBUWMzRG9LWHczeVM1Z0c5Zkc0c25OUUkxOHVRSjdOSjdndHZHClpKRU56bTNJMmFTMzl5dndWZnFIMXpXVERxU2VNeWhYeWFnTkFEcGtCVEJIMVJQR2NtTFplclFmWWx1djVVUmFNTXdRQUEKQU1BdE9oNHFwUUhidm5tQ1RVakx4dXRrWnRaRlhNa0hmSTk5NS9Nd2RvWVY1eWRKV0pUVGsyKzB1QVBIcTZEejk2b3dWbQpjUkF2WDBDOVU5d3ZRMkpnR0Y1MDZzcmgzZkVpUzM2d1ArOFd0RjZ6ODd0enJwQnpQVHIxOGRONURCOEx5L3dXRk5BVTdqClBUbXM0dHlUY1VsRXR3eEt4TXJTNC9ROUZwMWozL3JNdnNZdGVaSVgycmN4YUhkWWJDVGJtTUpZS3lVTWVXTk56NXpub1EKcFcyd2NDSmpJc1MvS1F2WmR4cHZwNWd0RXE1WlEva3FvLzJVRWd1NHhwdDNWeUNma0FBQURCQVBOSHVEU1R0ZEpJWjdzcwpaQkVwcUE4TE54b1dMQ2RURnlpRERiUnpYOWVPTldkRFQ3NklaRE9HejczNXJhZUFSM2FiY0FhaUM0dDQwTFJTNGEyN29sCm9wK1dSak9wcjVNYUtOUnk4MCt6VWw3WUlSMjErKzVnMFVnNkRnQlBEdmFJSHFSTnRsZ2gyVXdTL0cva1lOaUlEY0JiS1EKOUcvdTI4ekRIRUtNL21YYS8wYnFtSm16ZUYvY1BLdHdScFE3clFoRnAwUkdFcnZtc0l4dDl6K0ZZZUdncjFBYUVTV0ZlTApmUmZsa0lnOVBWOEl0b09GN25qK2VtMkxkNTNCS1hSUUFBQU1FQXhDTFBueHFFVEsyMW5QOXFxQVYzMEZUUkhGNW9kRHg4ClpiYnZIbjgwdEgxQjYwZjRtTGJFRm56REZFR0NwS2Rwb3dyUXR6WUhnQzNBaGNJUE9BbXFXaDg0UEFPbisreHhFanNaQkwKRWhVWmNFUndkYTMzTnJDNTVEMzZxbDBMZEsrSGRuZUFzVGZhazh0bWVlOTJWb0RxdWovNGFSMjBmUTBJUFVzMU8rWHNRNQpGWVFYQzZndExHZGRzRVFoSDF6MTh6RGtWa1UwdEhlZkJaL2pFZXBiOEZScXoxR1hpT0hGK2xBZVE2b3crS0xlcWtCcXQ4CkZxMHhGdG90SlF4VnFWQUFBQUYycHZhVzV1YVhOQVJFVlRTMVJQVUMxUVRWVkdVRFpOQVFJRAotLS0tLUVORCBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0K" + protected_settings = validate_and_get_protected_settings(rsa_key, '', '', '') + self.assertEqual('sshPrivateKey' in protected_settings, True) + self.assertEqual(protected_settings.get('sshPrivateKey'), rsa_key) + + def test_dsa_private_key(self): + key = DSA.generate(2048) + private_key_encoded = base64.b64encode(key.export_key()).decode('utf-8') + protected_settings = validate_and_get_protected_settings(private_key_encoded, '', '', '') + self.assertEqual('sshPrivateKey' in protected_settings, True) + self.assertEqual(protected_settings.get('sshPrivateKey'), private_key_encoded) + + def test_ecdsa_private_key(self): + ecdsa_key = "LS0tLS1CRUdJTiBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0KYjNCbGJuTnphQzFyWlhrdGRqRUFBQUFBQkc1dmJtVUFBQUFFYm05dVpRQUFBQUFBQUFBQkFBQUFhQUFBQUJObFkyUnpZUwoxemFHRXlMVzVwYzNSd01qVTJBQUFBQ0c1cGMzUndNalUyQUFBQVFRUjBRc1BjWmJKeWZPaXE2a1M1d0VaeE5DbmR2YVJHCm1ETEUvVVBjakpDTDZQTVIyZmdPS2NnWlhzTEZkTUFzSnExS2d6TmNDN0ZXNGE0L0wrYTFWWUxDQUFBQXNIZ1RqTFY0RTQKeTFBQUFBRTJWalpITmhMWE5vWVRJdGJtbHpkSEF5TlRZQUFBQUlibWx6ZEhBeU5UWUFBQUJCQkhSQ3c5eGxzbko4NktycQpSTG5BUm5FMEtkMjlwRWFZTXNUOVE5eU1rSXZvOHhIWitBNHB5Qmxld3NWMHdDd21yVXFETTF3THNWYmhyajh2NXJWVmdzCklBQUFBZ0h1U3laU0NUZzJZbVNpOG9aY2c0cnVpODh0T1NUSm1aRVhkR09hdExySHNBQUFBWGFtOXBibTVwYzBCRVJWTkwKVkU5UUxWQk5WVVpRTmswQgotLS0tLUVORCBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0K" + protected_settings = validate_and_get_protected_settings(ecdsa_key, '', '', '') + self.assertEqual('sshPrivateKey' in protected_settings, True) + self.assertEqual(protected_settings.get('sshPrivateKey'), ecdsa_key) + + def test_ed25519_private_key(self): + ed25519_key = "LS0tLS1CRUdJTiBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0KYjNCbGJuTnphQzFyWlhrdGRqRUFBQUFBQkc1dmJtVUFBQUFFYm05dVpRQUFBQUFBQUFBQkFBQUFNd0FBQUF0emMyZ3RaVwpReU5UVXhPUUFBQUNCNjF0RzkrNGFmOTZsWGoyUStjWjJMT2JpV1liMlRtWVR6N3NSV0JDM1hVZ0FBQUtCRzFWRWZSdFZSCkh3QUFBQXR6YzJndFpXUXlOVFV4T1FBQUFDQjYxdEc5KzRhZjk2bFhqMlErY1oyTE9iaVdZYjJUbVlUejdzUldCQzNYVWcKQUFBRURRTStLcCtOSWpJVUhSUklqRFE5VDZ0U0V0SG9Ic0w1QjlwbHpCNlZ2MnluclcwYjM3aHAvM3FWZVBaRDV4bllzNQp1SlpodlpPWmhQUHV4RllFTGRkU0FBQUFGMnB2YVc1dWFYTkFSRVZUUzFSUFVDMVFUVlZHVURaTkFRSURCQVVHCi0tLS0tRU5EIE9QRU5TU0ggUFJJVkFURSBLRVktLS0tLQo=" + protected_settings = validate_and_get_protected_settings(ed25519_key, '', '', '') + self.assertEqual('sshPrivateKey' in protected_settings, True) + self.assertEqual(protected_settings.get('sshPrivateKey'), ed25519_key) + + +class TestValidateK8sNaming(unittest.TestCase): + def test_long_operator_namespace(self): + operator_namespace = "thisisaverylongnamethatistoolongtobeused" + namespace = OperatorNamespace(operator_namespace) + err = 'Error! Invalid --operator-namespace' + with self.assertRaises(InvalidArgumentValueError) as cm: + validators.validate_operator_namespace(namespace) + self.assertEqual(str(cm.exception), err) + + def test_long_operator_instance_name(self): + operator_instance_name = "thisisaverylongnamethatistoolongtobeused" + namespace = OperatorInstanceName(operator_instance_name) + err = 'Error! Invalid --operator-instance-name' + with self.assertRaises(InvalidArgumentValueError) as cm: + validators.validate_operator_instance_name(namespace) + self.assertEqual(str(cm.exception), err) + + def test_caps_operator_namespace(self): + operator_namespace = 'Myoperatornamespace' + namespace = OperatorNamespace(operator_namespace) + err = 'Error! Invalid --operator-namespace' + with self.assertRaises(InvalidArgumentValueError) as cm: + validators.validate_operator_namespace(namespace) + self.assertEqual(str(cm.exception), err) + + def test_caps_operator_instance_name(self): + operator_instance_name = 'Myoperatorname' + namespace = OperatorInstanceName(operator_instance_name) + err = 'Error! Invalid --operator-instance-name' + with self.assertRaises(InvalidArgumentValueError) as cm: + validators.validate_operator_instance_name(namespace) + self.assertEqual(str(cm.exception), err) + + def test_long_config_name(self): + config_name = "thisisaverylongnamethatistoolongtobeusedthisisaverylongnamethatistoolongtobeused" + err = 'Error! Invalid --name' + with self.assertRaises(InvalidArgumentValueError) as cm: + validators.validate_configuration_name(config_name) + self.assertEqual(str(cm.exception), err) + + def test_valid_config_name(self): + config_name = "this-is-a-valid-config" + validators.validate_configuration_name(config_name) + + def test_caps_config_name(self): + config_name = "ThisIsaCapsConfigName" + err = 'Error! Invalid --name' + with self.assertRaises(InvalidArgumentValueError) as cm: + validators.validate_configuration_name(config_name) + self.assertEqual(str(cm.exception), err) + + def test_dot_config_name(self): + config_name = "a234567890b234567890c234567890d234567890e234567890f234567890.23" + err = 'Error! Invalid --name' + with self.assertRaises(InvalidArgumentValueError) as cm: + validators.validate_configuration_name(config_name) + self.assertEqual(str(cm.exception), err) + + def test_end_hyphen_config_name(self): + config_name = "a234567890b234567890c234567890d234567890e234567890f23456789023-" + err = 'Error! Invalid --name' + with self.assertRaises(InvalidArgumentValueError) as cm: + validators.validate_configuration_name(config_name) + self.assertEqual(str(cm.exception), err) + + +class TestValidateURLWithParams(unittest.TestCase): + def test_ssh_private_key_with_ssh_url(self): + validate_url_with_params('git@github.com:jonathan-innis/helm-operator-get-started-private.git', True, False, False) + + def test_ssh_known_hosts_with_ssh_url(self): + validate_url_with_params('git@github.com:jonathan-innis/helm-operator-get-started-private.git', False, True, False) + + def test_https_auth_with_https_url(self): + validate_url_with_params('https://github.com/jonathan-innis/helm-operator-get-started-private.git', False, False, True) + + def test_ssh_private_key_with_https_url(self): + err = 'Error! An ssh private key cannot be used with an http(s) url' + with self.assertRaises(MutuallyExclusiveArgumentError) as cm: + validate_url_with_params('https://github.com/jonathan-innis/helm-operator-get-started-private.git', True, False, False) + self.assertEqual(str(cm.exception), err) + + def test_ssh_known_hosts_with_https_url(self): + err = 'Error! ssh known_hosts cannot be used with an http(s) url' + with self.assertRaises(MutuallyExclusiveArgumentError) as cm: + validate_url_with_params('https://github.com/jonathan-innis/helm-operator-get-started-private.git', False, True, False) + self.assertEqual(str(cm.exception), err) + + def test_https_auth_with_ssh_url(self): + err = 'Error! https auth (--https-user and --https-key) cannot be used with a non-http(s) url' + with self.assertRaises(MutuallyExclusiveArgumentError) as cm: + validate_url_with_params('git@github.com:jonathan-innis/helm-operator-get-started-private.git', False, False, True) + self.assertEqual(str(cm.exception), err) + + +class TestValidateKnownHosts(unittest.TestCase): + def test_valid_known_hosts(self): + known_hosts_raw = "ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H" + known_hosts_encoded = base64.b64encode(known_hosts_raw.encode('utf-8')).decode('utf-8') + validate_known_hosts(known_hosts_encoded) + + def test_valid_known_hosts_with_comment(self): + known_hosts_raw = "ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H ThisIsAValidComment" + known_hosts_encoded = base64.b64encode(known_hosts_raw.encode('utf-8')).decode('utf-8') + validate_known_hosts(known_hosts_encoded) + + def test_valid_known_hosts_with_comment_own_line(self): + known_hosts_raw = "#this is a comment on its own line\nssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H" + known_hosts_encoded = base64.b64encode(known_hosts_raw.encode('utf-8')).decode('utf-8') + validate_known_hosts(known_hosts_encoded) + + def test_invalid_known_hosts(self): + known_hosts_raw = "thisisabadknownhostsfilethatisaninvalidformat" + known_hosts_encoded = base64.b64encode(known_hosts_raw.encode('utf-8')).decode('utf-8') + err = 'Error! ssh known_hosts provided in wrong format' + with self.assertRaises(InvalidArgumentValueError) as cm: + validate_known_hosts(known_hosts_encoded) + self.assertEqual(str(cm.exception), err) + + +class OperatorNamespace: + def __init__(self, operator_namespace): + self.operator_namespace = operator_namespace + + +class OperatorInstanceName: + def __init__(self, operator_instance_name): + self.operator_instance_name = operator_instance_name diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/__init__.py new file mode 100644 index 00000000000..874177b4d34 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/__init__.py @@ -0,0 +1,19 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +from ._configuration import SourceControlConfigurationClientConfiguration +from ._source_control_configuration_client import SourceControlConfigurationClient +__all__ = ['SourceControlConfigurationClient', 'SourceControlConfigurationClientConfiguration'] + +from .version import VERSION + +__version__ = VERSION + diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/_configuration.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/_configuration.py new file mode 100644 index 00000000000..5043ed69594 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/_configuration.py @@ -0,0 +1,49 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- +from msrestazure import AzureConfiguration + +from .version import VERSION + + +class SourceControlConfigurationClientConfiguration(AzureConfiguration): + """Configuration for SourceControlConfigurationClient + Note that all parameters used to create this instance are saved as instance + attributes. + + :param credentials: Credentials needed for the client to connect to Azure. + :type credentials: :mod:`A msrestazure Credentials + object` + :param subscription_id: The Azure subscription ID. This is a + GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000) + :type subscription_id: str + :param str base_url: Service URL + """ + + def __init__( + self, credentials, subscription_id, base_url=None): + + if credentials is None: + raise ValueError("Parameter 'credentials' must not be None.") + if subscription_id is None: + raise ValueError("Parameter 'subscription_id' must not be None.") + if not base_url: + base_url = 'https://management.azure.com' + + super(SourceControlConfigurationClientConfiguration, self).__init__(base_url) + + # Starting Autorest.Python 4.0.64, make connection pool activated by default + self.keep_alive = True + + self.add_user_agent('azure-mgmt-kubernetesconfiguration/{}'.format(VERSION)) + self.add_user_agent('Azure-SDK-For-Python') + + self.credentials = credentials + self.subscription_id = subscription_id diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/_source_control_configuration_client.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/_source_control_configuration_client.py new file mode 100644 index 00000000000..b27243fc208 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/_source_control_configuration_client.py @@ -0,0 +1,55 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +from msrest.service_client import SDKClient +from msrest import Serializer, Deserializer + +from ._configuration import SourceControlConfigurationClientConfiguration +from .operations import SourceControlConfigurationsOperations +from .operations import Operations +from . import models + + +class SourceControlConfigurationClient(SDKClient): + """Use these APIs to create Source Control Configuration resources through ARM, for Kubernetes Clusters. + + :ivar config: Configuration for client. + :vartype config: SourceControlConfigurationClientConfiguration + + :ivar source_control_configurations: SourceControlConfigurations operations + :vartype source_control_configurations: azure.mgmt.kubernetesconfiguration.operations.SourceControlConfigurationsOperations + :ivar operations: Operations operations + :vartype operations: azure.mgmt.kubernetesconfiguration.operations.Operations + + :param credentials: Credentials needed for the client to connect to Azure. + :type credentials: :mod:`A msrestazure Credentials + object` + :param subscription_id: The Azure subscription ID. This is a + GUID-formatted string (e.g. 00000000-0000-0000-0000-000000000000) + :type subscription_id: str + :param str base_url: Service URL + """ + + def __init__( + self, credentials, subscription_id, base_url=None): + + self.config = SourceControlConfigurationClientConfiguration(credentials, subscription_id, base_url) + super(SourceControlConfigurationClient, self).__init__(self.config.credentials, self.config) + + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + self.api_version = '2021-03-01' + self._serialize = Serializer(client_models) + self._deserialize = Deserializer(client_models) + + self.source_control_configurations = SourceControlConfigurationsOperations( + self._client, self.config, self._serialize, self._deserialize) + self.operations = Operations( + self._client, self.config, self._serialize, self._deserialize) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/__init__.py new file mode 100644 index 00000000000..86f85f9bcb5 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/__init__.py @@ -0,0 +1,73 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +try: + from ._models_py3 import AzureEntityResource + from ._models_py3 import ComplianceStatus + from ._models_py3 import ErrorDefinition + from ._models_py3 import ErrorResponse, ErrorResponseException + from ._models_py3 import HelmOperatorProperties + from ._models_py3 import ProxyResource + from ._models_py3 import Resource + from ._models_py3 import ResourceProviderOperation + from ._models_py3 import ResourceProviderOperationDisplay + from ._models_py3 import Result + from ._models_py3 import SourceControlConfiguration + from ._models_py3 import SystemData + from ._models_py3 import TrackedResource +except (SyntaxError, ImportError): + from ._models import AzureEntityResource + from ._models import ComplianceStatus + from ._models import ErrorDefinition + from ._models import ErrorResponse, ErrorResponseException + from ._models import HelmOperatorProperties + from ._models import ProxyResource + from ._models import Resource + from ._models import ResourceProviderOperation + from ._models import ResourceProviderOperationDisplay + from ._models import Result + from ._models import SourceControlConfiguration + from ._models import SystemData + from ._models import TrackedResource +from ._paged_models import ResourceProviderOperationPaged +from ._paged_models import SourceControlConfigurationPaged +from ._source_control_configuration_client_enums import ( + ComplianceStateType, + MessageLevelType, + OperatorType, + OperatorScopeType, + ProvisioningStateType, + CreatedByType, +) + +__all__ = [ + 'AzureEntityResource', + 'ComplianceStatus', + 'ErrorDefinition', + 'ErrorResponse', 'ErrorResponseException', + 'HelmOperatorProperties', + 'ProxyResource', + 'Resource', + 'ResourceProviderOperation', + 'ResourceProviderOperationDisplay', + 'Result', + 'SourceControlConfiguration', + 'SystemData', + 'TrackedResource', + 'SourceControlConfigurationPaged', + 'ResourceProviderOperationPaged', + 'ComplianceStateType', + 'MessageLevelType', + 'OperatorType', + 'OperatorScopeType', + 'ProvisioningStateType', + 'CreatedByType', +] diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_models.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_models.py new file mode 100644 index 00000000000..676504953e7 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_models.py @@ -0,0 +1,527 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +from msrest.serialization import Model +from msrest.exceptions import HttpOperationError + + +class Resource(Model): + """Resource. + + Common fields that are returned in the response for all Azure Resource + Manager resources. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName} + :vartype id: str + :ivar name: The name of the resource + :vartype name: str + :ivar type: The type of the resource. E.g. + "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts" + :vartype type: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__(self, **kwargs): + super(Resource, self).__init__(**kwargs) + self.id = None + self.name = None + self.type = None + + +class AzureEntityResource(Resource): + """Entity Resource. + + The resource model definition for an Azure Resource Manager resource with + an etag. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName} + :vartype id: str + :ivar name: The name of the resource + :vartype name: str + :ivar type: The type of the resource. E.g. + "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts" + :vartype type: str + :ivar etag: Resource Etag. + :vartype etag: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'etag': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'etag': {'key': 'etag', 'type': 'str'}, + } + + def __init__(self, **kwargs): + super(AzureEntityResource, self).__init__(**kwargs) + self.etag = None + + +class CloudError(Model): + """CloudError. + """ + + _attribute_map = { + } + + +class ComplianceStatus(Model): + """Compliance Status details. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar compliance_state: The compliance state of the configuration. + Possible values include: 'Pending', 'Compliant', 'Noncompliant', + 'Installed', 'Failed' + :vartype compliance_state: str or + ~azure.mgmt.kubernetesconfiguration.models.ComplianceStateType + :param last_config_applied: Datetime the configuration was last applied. + :type last_config_applied: datetime + :param message: Message from when the configuration was applied. + :type message: str + :param message_level: Level of the message. Possible values include: + 'Error', 'Warning', 'Information' + :type message_level: str or + ~azure.mgmt.kubernetesconfiguration.models.MessageLevelType + """ + + _validation = { + 'compliance_state': {'readonly': True}, + } + + _attribute_map = { + 'compliance_state': {'key': 'complianceState', 'type': 'str'}, + 'last_config_applied': {'key': 'lastConfigApplied', 'type': 'iso-8601'}, + 'message': {'key': 'message', 'type': 'str'}, + 'message_level': {'key': 'messageLevel', 'type': 'str'}, + } + + def __init__(self, **kwargs): + super(ComplianceStatus, self).__init__(**kwargs) + self.compliance_state = None + self.last_config_applied = kwargs.get('last_config_applied', None) + self.message = kwargs.get('message', None) + self.message_level = kwargs.get('message_level', None) + + +class ErrorDefinition(Model): + """Error definition. + + All required parameters must be populated in order to send to Azure. + + :param code: Required. Service specific error code which serves as the + substatus for the HTTP error code. + :type code: str + :param message: Required. Description of the error. + :type message: str + """ + + _validation = { + 'code': {'required': True}, + 'message': {'required': True}, + } + + _attribute_map = { + 'code': {'key': 'code', 'type': 'str'}, + 'message': {'key': 'message', 'type': 'str'}, + } + + def __init__(self, **kwargs): + super(ErrorDefinition, self).__init__(**kwargs) + self.code = kwargs.get('code', None) + self.message = kwargs.get('message', None) + + +class ErrorResponse(Model): + """Error response. + + :param error: Error definition. + :type error: ~azure.mgmt.kubernetesconfiguration.models.ErrorDefinition + """ + + _attribute_map = { + 'error': {'key': 'error', 'type': 'ErrorDefinition'}, + } + + def __init__(self, **kwargs): + super(ErrorResponse, self).__init__(**kwargs) + self.error = kwargs.get('error', None) + + +class ErrorResponseException(HttpOperationError): + """Server responsed with exception of type: 'ErrorResponse'. + + :param deserialize: A deserializer + :param response: Server response to be deserialized. + """ + + def __init__(self, deserialize, response, *args): + + super(ErrorResponseException, self).__init__(deserialize, response, 'ErrorResponse', *args) + + +class HelmOperatorProperties(Model): + """Properties for Helm operator. + + :param chart_version: Version of the operator Helm chart. + :type chart_version: str + :param chart_values: Values override for the operator Helm chart. + :type chart_values: str + """ + + _attribute_map = { + 'chart_version': {'key': 'chartVersion', 'type': 'str'}, + 'chart_values': {'key': 'chartValues', 'type': 'str'}, + } + + def __init__(self, **kwargs): + super(HelmOperatorProperties, self).__init__(**kwargs) + self.chart_version = kwargs.get('chart_version', None) + self.chart_values = kwargs.get('chart_values', None) + + +class ProxyResource(Resource): + """Proxy Resource. + + The resource model definition for a Azure Resource Manager proxy resource. + It will not have tags and a location. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName} + :vartype id: str + :ivar name: The name of the resource + :vartype name: str + :ivar type: The type of the resource. E.g. + "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts" + :vartype type: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__(self, **kwargs): + super(ProxyResource, self).__init__(**kwargs) + + +class ResourceProviderOperation(Model): + """Supported operation of this resource provider. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :param name: Operation name, in format of + {provider}/{resource}/{operation} + :type name: str + :param display: Display metadata associated with the operation. + :type display: + ~azure.mgmt.kubernetesconfiguration.models.ResourceProviderOperationDisplay + :ivar is_data_action: The flag that indicates whether the operation + applies to data plane. + :vartype is_data_action: bool + """ + + _validation = { + 'is_data_action': {'readonly': True}, + } + + _attribute_map = { + 'name': {'key': 'name', 'type': 'str'}, + 'display': {'key': 'display', 'type': 'ResourceProviderOperationDisplay'}, + 'is_data_action': {'key': 'isDataAction', 'type': 'bool'}, + } + + def __init__(self, **kwargs): + super(ResourceProviderOperation, self).__init__(**kwargs) + self.name = kwargs.get('name', None) + self.display = kwargs.get('display', None) + self.is_data_action = None + + +class ResourceProviderOperationDisplay(Model): + """Display metadata associated with the operation. + + :param provider: Resource provider: Microsoft KubernetesConfiguration. + :type provider: str + :param resource: Resource on which the operation is performed. + :type resource: str + :param operation: Type of operation: get, read, delete, etc. + :type operation: str + :param description: Description of this operation. + :type description: str + """ + + _attribute_map = { + 'provider': {'key': 'provider', 'type': 'str'}, + 'resource': {'key': 'resource', 'type': 'str'}, + 'operation': {'key': 'operation', 'type': 'str'}, + 'description': {'key': 'description', 'type': 'str'}, + } + + def __init__(self, **kwargs): + super(ResourceProviderOperationDisplay, self).__init__(**kwargs) + self.provider = kwargs.get('provider', None) + self.resource = kwargs.get('resource', None) + self.operation = kwargs.get('operation', None) + self.description = kwargs.get('description', None) + + +class Result(Model): + """Sample result definition. + + :param sample_property: Sample property of type string + :type sample_property: str + """ + + _attribute_map = { + 'sample_property': {'key': 'sampleProperty', 'type': 'str'}, + } + + def __init__(self, **kwargs): + super(Result, self).__init__(**kwargs) + self.sample_property = kwargs.get('sample_property', None) + + +class SourceControlConfiguration(ProxyResource): + """The SourceControl Configuration object returned in Get & Put response. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName} + :vartype id: str + :ivar name: The name of the resource + :vartype name: str + :ivar type: The type of the resource. E.g. + "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts" + :vartype type: str + :param repository_url: Url of the SourceControl Repository. + :type repository_url: str + :param operator_namespace: The namespace to which this operator is + installed to. Maximum of 253 lower case alphanumeric characters, hyphen + and period only. Default value: "default" . + :type operator_namespace: str + :param operator_instance_name: Instance name of the operator - identifying + the specific configuration. + :type operator_instance_name: str + :param operator_type: Type of the operator. Possible values include: + 'Flux' + :type operator_type: str or + ~azure.mgmt.kubernetesconfiguration.models.OperatorType + :param operator_params: Any Parameters for the Operator instance in string + format. + :type operator_params: str + :param configuration_protected_settings: Name-value pairs of protected + configuration settings for the configuration + :type configuration_protected_settings: dict[str, str] + :param operator_scope: Scope at which the operator will be installed. + Possible values include: 'cluster', 'namespace'. Default value: "cluster" + . + :type operator_scope: str or + ~azure.mgmt.kubernetesconfiguration.models.OperatorScopeType + :ivar repository_public_key: Public Key associated with this SourceControl + configuration (either generated within the cluster or provided by the + user). + :vartype repository_public_key: str + :param ssh_known_hosts_contents: Base64-encoded known_hosts contents + containing public SSH keys required to access private Git instances + :type ssh_known_hosts_contents: str + :param enable_helm_operator: Option to enable Helm Operator for this git + configuration. + :type enable_helm_operator: bool + :param helm_operator_properties: Properties for Helm operator. + :type helm_operator_properties: + ~azure.mgmt.kubernetesconfiguration.models.HelmOperatorProperties + :ivar provisioning_state: The provisioning state of the resource provider. + Possible values include: 'Accepted', 'Deleting', 'Running', 'Succeeded', + 'Failed' + :vartype provisioning_state: str or + ~azure.mgmt.kubernetesconfiguration.models.ProvisioningStateType + :ivar compliance_status: Compliance Status of the Configuration + :vartype compliance_status: + ~azure.mgmt.kubernetesconfiguration.models.ComplianceStatus + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources + :type system_data: ~azure.mgmt.kubernetesconfiguration.models.SystemData + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'repository_public_key': {'readonly': True}, + 'provisioning_state': {'readonly': True}, + 'compliance_status': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'repository_url': {'key': 'properties.repositoryUrl', 'type': 'str'}, + 'operator_namespace': {'key': 'properties.operatorNamespace', 'type': 'str'}, + 'operator_instance_name': {'key': 'properties.operatorInstanceName', 'type': 'str'}, + 'operator_type': {'key': 'properties.operatorType', 'type': 'str'}, + 'operator_params': {'key': 'properties.operatorParams', 'type': 'str'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + 'operator_scope': {'key': 'properties.operatorScope', 'type': 'str'}, + 'repository_public_key': {'key': 'properties.repositoryPublicKey', 'type': 'str'}, + 'ssh_known_hosts_contents': {'key': 'properties.sshKnownHostsContents', 'type': 'str'}, + 'enable_helm_operator': {'key': 'properties.enableHelmOperator', 'type': 'bool'}, + 'helm_operator_properties': {'key': 'properties.helmOperatorProperties', 'type': 'HelmOperatorProperties'}, + 'provisioning_state': {'key': 'properties.provisioningState', 'type': 'str'}, + 'compliance_status': {'key': 'properties.complianceStatus', 'type': 'ComplianceStatus'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + } + + def __init__(self, **kwargs): + super(SourceControlConfiguration, self).__init__(**kwargs) + self.repository_url = kwargs.get('repository_url', None) + self.operator_namespace = kwargs.get('operator_namespace', "default") + self.operator_instance_name = kwargs.get('operator_instance_name', None) + self.operator_type = kwargs.get('operator_type', None) + self.operator_params = kwargs.get('operator_params', None) + self.configuration_protected_settings = kwargs.get('configuration_protected_settings', None) + self.operator_scope = kwargs.get('operator_scope', "cluster") + self.repository_public_key = None + self.ssh_known_hosts_contents = kwargs.get('ssh_known_hosts_contents', None) + self.enable_helm_operator = kwargs.get('enable_helm_operator', None) + self.helm_operator_properties = kwargs.get('helm_operator_properties', None) + self.provisioning_state = None + self.compliance_status = None + self.system_data = kwargs.get('system_data', None) + + +class SystemData(Model): + """Metadata pertaining to creation and last modification of the resource. + + :param created_by: The identity that created the resource. + :type created_by: str + :param created_by_type: The type of identity that created the resource. + Possible values include: 'User', 'Application', 'ManagedIdentity', 'Key' + :type created_by_type: str or + ~azure.mgmt.kubernetesconfiguration.models.CreatedByType + :param created_at: The timestamp of resource creation (UTC). + :type created_at: datetime + :param last_modified_by: The identity that last modified the resource. + :type last_modified_by: str + :param last_modified_by_type: The type of identity that last modified the + resource. Possible values include: 'User', 'Application', + 'ManagedIdentity', 'Key' + :type last_modified_by_type: str or + ~azure.mgmt.kubernetesconfiguration.models.CreatedByType + :param last_modified_at: The type of identity that last modified the + resource. + :type last_modified_at: datetime + """ + + _attribute_map = { + 'created_by': {'key': 'createdBy', 'type': 'str'}, + 'created_by_type': {'key': 'createdByType', 'type': 'str'}, + 'created_at': {'key': 'createdAt', 'type': 'iso-8601'}, + 'last_modified_by': {'key': 'lastModifiedBy', 'type': 'str'}, + 'last_modified_by_type': {'key': 'lastModifiedByType', 'type': 'str'}, + 'last_modified_at': {'key': 'lastModifiedAt', 'type': 'iso-8601'}, + } + + def __init__(self, **kwargs): + super(SystemData, self).__init__(**kwargs) + self.created_by = kwargs.get('created_by', None) + self.created_by_type = kwargs.get('created_by_type', None) + self.created_at = kwargs.get('created_at', None) + self.last_modified_by = kwargs.get('last_modified_by', None) + self.last_modified_by_type = kwargs.get('last_modified_by_type', None) + self.last_modified_at = kwargs.get('last_modified_at', None) + + +class TrackedResource(Resource): + """Tracked Resource. + + The resource model definition for an Azure Resource Manager tracked top + level resource which has 'tags' and a 'location'. + + Variables are only populated by the server, and will be ignored when + sending a request. + + All required parameters must be populated in order to send to Azure. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName} + :vartype id: str + :ivar name: The name of the resource + :vartype name: str + :ivar type: The type of the resource. E.g. + "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts" + :vartype type: str + :param tags: Resource tags. + :type tags: dict[str, str] + :param location: Required. The geo-location where the resource lives + :type location: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'location': {'required': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'tags': {'key': 'tags', 'type': '{str}'}, + 'location': {'key': 'location', 'type': 'str'}, + } + + def __init__(self, **kwargs): + super(TrackedResource, self).__init__(**kwargs) + self.tags = kwargs.get('tags', None) + self.location = kwargs.get('location', None) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_models_py3.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_models_py3.py new file mode 100644 index 00000000000..b77227e4d97 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_models_py3.py @@ -0,0 +1,527 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +from msrest.serialization import Model +from msrest.exceptions import HttpOperationError + + +class Resource(Model): + """Resource. + + Common fields that are returned in the response for all Azure Resource + Manager resources. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName} + :vartype id: str + :ivar name: The name of the resource + :vartype name: str + :ivar type: The type of the resource. E.g. + "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts" + :vartype type: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__(self, **kwargs) -> None: + super(Resource, self).__init__(**kwargs) + self.id = None + self.name = None + self.type = None + + +class AzureEntityResource(Resource): + """Entity Resource. + + The resource model definition for an Azure Resource Manager resource with + an etag. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName} + :vartype id: str + :ivar name: The name of the resource + :vartype name: str + :ivar type: The type of the resource. E.g. + "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts" + :vartype type: str + :ivar etag: Resource Etag. + :vartype etag: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'etag': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'etag': {'key': 'etag', 'type': 'str'}, + } + + def __init__(self, **kwargs) -> None: + super(AzureEntityResource, self).__init__(**kwargs) + self.etag = None + + +class CloudError(Model): + """CloudError. + """ + + _attribute_map = { + } + + +class ComplianceStatus(Model): + """Compliance Status details. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar compliance_state: The compliance state of the configuration. + Possible values include: 'Pending', 'Compliant', 'Noncompliant', + 'Installed', 'Failed' + :vartype compliance_state: str or + ~azure.mgmt.kubernetesconfiguration.models.ComplianceStateType + :param last_config_applied: Datetime the configuration was last applied. + :type last_config_applied: datetime + :param message: Message from when the configuration was applied. + :type message: str + :param message_level: Level of the message. Possible values include: + 'Error', 'Warning', 'Information' + :type message_level: str or + ~azure.mgmt.kubernetesconfiguration.models.MessageLevelType + """ + + _validation = { + 'compliance_state': {'readonly': True}, + } + + _attribute_map = { + 'compliance_state': {'key': 'complianceState', 'type': 'str'}, + 'last_config_applied': {'key': 'lastConfigApplied', 'type': 'iso-8601'}, + 'message': {'key': 'message', 'type': 'str'}, + 'message_level': {'key': 'messageLevel', 'type': 'str'}, + } + + def __init__(self, *, last_config_applied=None, message: str=None, message_level=None, **kwargs) -> None: + super(ComplianceStatus, self).__init__(**kwargs) + self.compliance_state = None + self.last_config_applied = last_config_applied + self.message = message + self.message_level = message_level + + +class ErrorDefinition(Model): + """Error definition. + + All required parameters must be populated in order to send to Azure. + + :param code: Required. Service specific error code which serves as the + substatus for the HTTP error code. + :type code: str + :param message: Required. Description of the error. + :type message: str + """ + + _validation = { + 'code': {'required': True}, + 'message': {'required': True}, + } + + _attribute_map = { + 'code': {'key': 'code', 'type': 'str'}, + 'message': {'key': 'message', 'type': 'str'}, + } + + def __init__(self, *, code: str, message: str, **kwargs) -> None: + super(ErrorDefinition, self).__init__(**kwargs) + self.code = code + self.message = message + + +class ErrorResponse(Model): + """Error response. + + :param error: Error definition. + :type error: ~azure.mgmt.kubernetesconfiguration.models.ErrorDefinition + """ + + _attribute_map = { + 'error': {'key': 'error', 'type': 'ErrorDefinition'}, + } + + def __init__(self, *, error=None, **kwargs) -> None: + super(ErrorResponse, self).__init__(**kwargs) + self.error = error + + +class ErrorResponseException(HttpOperationError): + """Server responsed with exception of type: 'ErrorResponse'. + + :param deserialize: A deserializer + :param response: Server response to be deserialized. + """ + + def __init__(self, deserialize, response, *args): + + super(ErrorResponseException, self).__init__(deserialize, response, 'ErrorResponse', *args) + + +class HelmOperatorProperties(Model): + """Properties for Helm operator. + + :param chart_version: Version of the operator Helm chart. + :type chart_version: str + :param chart_values: Values override for the operator Helm chart. + :type chart_values: str + """ + + _attribute_map = { + 'chart_version': {'key': 'chartVersion', 'type': 'str'}, + 'chart_values': {'key': 'chartValues', 'type': 'str'}, + } + + def __init__(self, *, chart_version: str=None, chart_values: str=None, **kwargs) -> None: + super(HelmOperatorProperties, self).__init__(**kwargs) + self.chart_version = chart_version + self.chart_values = chart_values + + +class ProxyResource(Resource): + """Proxy Resource. + + The resource model definition for a Azure Resource Manager proxy resource. + It will not have tags and a location. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName} + :vartype id: str + :ivar name: The name of the resource + :vartype name: str + :ivar type: The type of the resource. E.g. + "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts" + :vartype type: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + } + + def __init__(self, **kwargs) -> None: + super(ProxyResource, self).__init__(**kwargs) + + +class ResourceProviderOperation(Model): + """Supported operation of this resource provider. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :param name: Operation name, in format of + {provider}/{resource}/{operation} + :type name: str + :param display: Display metadata associated with the operation. + :type display: + ~azure.mgmt.kubernetesconfiguration.models.ResourceProviderOperationDisplay + :ivar is_data_action: The flag that indicates whether the operation + applies to data plane. + :vartype is_data_action: bool + """ + + _validation = { + 'is_data_action': {'readonly': True}, + } + + _attribute_map = { + 'name': {'key': 'name', 'type': 'str'}, + 'display': {'key': 'display', 'type': 'ResourceProviderOperationDisplay'}, + 'is_data_action': {'key': 'isDataAction', 'type': 'bool'}, + } + + def __init__(self, *, name: str=None, display=None, **kwargs) -> None: + super(ResourceProviderOperation, self).__init__(**kwargs) + self.name = name + self.display = display + self.is_data_action = None + + +class ResourceProviderOperationDisplay(Model): + """Display metadata associated with the operation. + + :param provider: Resource provider: Microsoft KubernetesConfiguration. + :type provider: str + :param resource: Resource on which the operation is performed. + :type resource: str + :param operation: Type of operation: get, read, delete, etc. + :type operation: str + :param description: Description of this operation. + :type description: str + """ + + _attribute_map = { + 'provider': {'key': 'provider', 'type': 'str'}, + 'resource': {'key': 'resource', 'type': 'str'}, + 'operation': {'key': 'operation', 'type': 'str'}, + 'description': {'key': 'description', 'type': 'str'}, + } + + def __init__(self, *, provider: str=None, resource: str=None, operation: str=None, description: str=None, **kwargs) -> None: + super(ResourceProviderOperationDisplay, self).__init__(**kwargs) + self.provider = provider + self.resource = resource + self.operation = operation + self.description = description + + +class Result(Model): + """Sample result definition. + + :param sample_property: Sample property of type string + :type sample_property: str + """ + + _attribute_map = { + 'sample_property': {'key': 'sampleProperty', 'type': 'str'}, + } + + def __init__(self, *, sample_property: str=None, **kwargs) -> None: + super(Result, self).__init__(**kwargs) + self.sample_property = sample_property + + +class SourceControlConfiguration(ProxyResource): + """The SourceControl Configuration object returned in Get & Put response. + + Variables are only populated by the server, and will be ignored when + sending a request. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName} + :vartype id: str + :ivar name: The name of the resource + :vartype name: str + :ivar type: The type of the resource. E.g. + "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts" + :vartype type: str + :param repository_url: Url of the SourceControl Repository. + :type repository_url: str + :param operator_namespace: The namespace to which this operator is + installed to. Maximum of 253 lower case alphanumeric characters, hyphen + and period only. Default value: "default" . + :type operator_namespace: str + :param operator_instance_name: Instance name of the operator - identifying + the specific configuration. + :type operator_instance_name: str + :param operator_type: Type of the operator. Possible values include: + 'Flux' + :type operator_type: str or + ~azure.mgmt.kubernetesconfiguration.models.OperatorType + :param operator_params: Any Parameters for the Operator instance in string + format. + :type operator_params: str + :param configuration_protected_settings: Name-value pairs of protected + configuration settings for the configuration + :type configuration_protected_settings: dict[str, str] + :param operator_scope: Scope at which the operator will be installed. + Possible values include: 'cluster', 'namespace'. Default value: "cluster" + . + :type operator_scope: str or + ~azure.mgmt.kubernetesconfiguration.models.OperatorScopeType + :ivar repository_public_key: Public Key associated with this SourceControl + configuration (either generated within the cluster or provided by the + user). + :vartype repository_public_key: str + :param ssh_known_hosts_contents: Base64-encoded known_hosts contents + containing public SSH keys required to access private Git instances + :type ssh_known_hosts_contents: str + :param enable_helm_operator: Option to enable Helm Operator for this git + configuration. + :type enable_helm_operator: bool + :param helm_operator_properties: Properties for Helm operator. + :type helm_operator_properties: + ~azure.mgmt.kubernetesconfiguration.models.HelmOperatorProperties + :ivar provisioning_state: The provisioning state of the resource provider. + Possible values include: 'Accepted', 'Deleting', 'Running', 'Succeeded', + 'Failed' + :vartype provisioning_state: str or + ~azure.mgmt.kubernetesconfiguration.models.ProvisioningStateType + :ivar compliance_status: Compliance Status of the Configuration + :vartype compliance_status: + ~azure.mgmt.kubernetesconfiguration.models.ComplianceStatus + :param system_data: Top level metadata + https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/common-api-contracts.md#system-metadata-for-all-azure-resources + :type system_data: ~azure.mgmt.kubernetesconfiguration.models.SystemData + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'repository_public_key': {'readonly': True}, + 'provisioning_state': {'readonly': True}, + 'compliance_status': {'readonly': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'repository_url': {'key': 'properties.repositoryUrl', 'type': 'str'}, + 'operator_namespace': {'key': 'properties.operatorNamespace', 'type': 'str'}, + 'operator_instance_name': {'key': 'properties.operatorInstanceName', 'type': 'str'}, + 'operator_type': {'key': 'properties.operatorType', 'type': 'str'}, + 'operator_params': {'key': 'properties.operatorParams', 'type': 'str'}, + 'configuration_protected_settings': {'key': 'properties.configurationProtectedSettings', 'type': '{str}'}, + 'operator_scope': {'key': 'properties.operatorScope', 'type': 'str'}, + 'repository_public_key': {'key': 'properties.repositoryPublicKey', 'type': 'str'}, + 'ssh_known_hosts_contents': {'key': 'properties.sshKnownHostsContents', 'type': 'str'}, + 'enable_helm_operator': {'key': 'properties.enableHelmOperator', 'type': 'bool'}, + 'helm_operator_properties': {'key': 'properties.helmOperatorProperties', 'type': 'HelmOperatorProperties'}, + 'provisioning_state': {'key': 'properties.provisioningState', 'type': 'str'}, + 'compliance_status': {'key': 'properties.complianceStatus', 'type': 'ComplianceStatus'}, + 'system_data': {'key': 'systemData', 'type': 'SystemData'}, + } + + def __init__(self, *, repository_url: str=None, operator_namespace: str="default", operator_instance_name: str=None, operator_type=None, operator_params: str=None, configuration_protected_settings=None, operator_scope="cluster", ssh_known_hosts_contents: str=None, enable_helm_operator: bool=None, helm_operator_properties=None, system_data=None, **kwargs) -> None: + super(SourceControlConfiguration, self).__init__(**kwargs) + self.repository_url = repository_url + self.operator_namespace = operator_namespace + self.operator_instance_name = operator_instance_name + self.operator_type = operator_type + self.operator_params = operator_params + self.configuration_protected_settings = configuration_protected_settings + self.operator_scope = operator_scope + self.repository_public_key = None + self.ssh_known_hosts_contents = ssh_known_hosts_contents + self.enable_helm_operator = enable_helm_operator + self.helm_operator_properties = helm_operator_properties + self.provisioning_state = None + self.compliance_status = None + self.system_data = system_data + + +class SystemData(Model): + """Metadata pertaining to creation and last modification of the resource. + + :param created_by: The identity that created the resource. + :type created_by: str + :param created_by_type: The type of identity that created the resource. + Possible values include: 'User', 'Application', 'ManagedIdentity', 'Key' + :type created_by_type: str or + ~azure.mgmt.kubernetesconfiguration.models.CreatedByType + :param created_at: The timestamp of resource creation (UTC). + :type created_at: datetime + :param last_modified_by: The identity that last modified the resource. + :type last_modified_by: str + :param last_modified_by_type: The type of identity that last modified the + resource. Possible values include: 'User', 'Application', + 'ManagedIdentity', 'Key' + :type last_modified_by_type: str or + ~azure.mgmt.kubernetesconfiguration.models.CreatedByType + :param last_modified_at: The type of identity that last modified the + resource. + :type last_modified_at: datetime + """ + + _attribute_map = { + 'created_by': {'key': 'createdBy', 'type': 'str'}, + 'created_by_type': {'key': 'createdByType', 'type': 'str'}, + 'created_at': {'key': 'createdAt', 'type': 'iso-8601'}, + 'last_modified_by': {'key': 'lastModifiedBy', 'type': 'str'}, + 'last_modified_by_type': {'key': 'lastModifiedByType', 'type': 'str'}, + 'last_modified_at': {'key': 'lastModifiedAt', 'type': 'iso-8601'}, + } + + def __init__(self, *, created_by: str=None, created_by_type=None, created_at=None, last_modified_by: str=None, last_modified_by_type=None, last_modified_at=None, **kwargs) -> None: + super(SystemData, self).__init__(**kwargs) + self.created_by = created_by + self.created_by_type = created_by_type + self.created_at = created_at + self.last_modified_by = last_modified_by + self.last_modified_by_type = last_modified_by_type + self.last_modified_at = last_modified_at + + +class TrackedResource(Resource): + """Tracked Resource. + + The resource model definition for an Azure Resource Manager tracked top + level resource which has 'tags' and a 'location'. + + Variables are only populated by the server, and will be ignored when + sending a request. + + All required parameters must be populated in order to send to Azure. + + :ivar id: Fully qualified resource ID for the resource. Ex - + /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName} + :vartype id: str + :ivar name: The name of the resource + :vartype name: str + :ivar type: The type of the resource. E.g. + "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts" + :vartype type: str + :param tags: Resource tags. + :type tags: dict[str, str] + :param location: Required. The geo-location where the resource lives + :type location: str + """ + + _validation = { + 'id': {'readonly': True}, + 'name': {'readonly': True}, + 'type': {'readonly': True}, + 'location': {'required': True}, + } + + _attribute_map = { + 'id': {'key': 'id', 'type': 'str'}, + 'name': {'key': 'name', 'type': 'str'}, + 'type': {'key': 'type', 'type': 'str'}, + 'tags': {'key': 'tags', 'type': '{str}'}, + 'location': {'key': 'location', 'type': 'str'}, + } + + def __init__(self, *, location: str, tags=None, **kwargs) -> None: + super(TrackedResource, self).__init__(**kwargs) + self.tags = tags + self.location = location diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_paged_models.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_paged_models.py new file mode 100644 index 00000000000..da03391d8d6 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_paged_models.py @@ -0,0 +1,40 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +from msrest.paging import Paged + + +class SourceControlConfigurationPaged(Paged): + """ + A paging container for iterating over a list of :class:`SourceControlConfiguration ` object + """ + + _attribute_map = { + 'next_link': {'key': 'nextLink', 'type': 'str'}, + 'current_page': {'key': 'value', 'type': '[SourceControlConfiguration]'} + } + + def __init__(self, *args, **kwargs): + + super(SourceControlConfigurationPaged, self).__init__(*args, **kwargs) +class ResourceProviderOperationPaged(Paged): + """ + A paging container for iterating over a list of :class:`ResourceProviderOperation ` object + """ + + _attribute_map = { + 'next_link': {'key': 'nextLink', 'type': 'str'}, + 'current_page': {'key': 'value', 'type': '[ResourceProviderOperation]'} + } + + def __init__(self, *args, **kwargs): + + super(ResourceProviderOperationPaged, self).__init__(*args, **kwargs) diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_source_control_configuration_client_enums.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_source_control_configuration_client_enums.py new file mode 100644 index 00000000000..6708ac68cde --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/models/_source_control_configuration_client_enums.py @@ -0,0 +1,56 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +from enum import Enum + + +class ComplianceStateType(str, Enum): + + pending = "Pending" + compliant = "Compliant" + noncompliant = "Noncompliant" + installed = "Installed" + failed = "Failed" + + +class MessageLevelType(str, Enum): + + error = "Error" + warning = "Warning" + information = "Information" + + +class OperatorType(str, Enum): + + flux = "Flux" + + +class OperatorScopeType(str, Enum): + + cluster = "cluster" + namespace = "namespace" + + +class ProvisioningStateType(str, Enum): + + accepted = "Accepted" + deleting = "Deleting" + running = "Running" + succeeded = "Succeeded" + failed = "Failed" + + +class CreatedByType(str, Enum): + + user = "User" + application = "Application" + managed_identity = "ManagedIdentity" + key = "Key" diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/operations/__init__.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/operations/__init__.py new file mode 100644 index 00000000000..b6c0858d9a7 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/operations/__init__.py @@ -0,0 +1,18 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +from ._source_control_configurations_operations import SourceControlConfigurationsOperations +from ._operations import Operations + +__all__ = [ + 'SourceControlConfigurationsOperations', + 'Operations', +] diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/operations/_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/operations/_operations.py new file mode 100644 index 00000000000..5308b8f8270 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/operations/_operations.py @@ -0,0 +1,101 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +import uuid +from msrest.pipeline import ClientRawResponse + +from .. import models + + +class Operations(object): + """Operations operations. + + You should not instantiate directly this class, but create a Client instance that will create it for you and attach it as attribute. + + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + :ivar api_version: The API version to be used with the HTTP request. Constant value: "2021-03-01". + """ + + models = models + + def __init__(self, client, config, serializer, deserializer): + + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self.api_version = "2021-03-01" + + self.config = config + + def list( + self, custom_headers=None, raw=False, **operation_config): + """List all the available operations the KubernetesConfiguration resource + provider supports. + + :param dict custom_headers: headers that will be added to the request + :param bool raw: returns the direct response alongside the + deserialized response + :param operation_config: :ref:`Operation configuration + overrides`. + :return: An iterator like instance of ResourceProviderOperation + :rtype: + ~azure.mgmt.kubernetesconfiguration.models.ResourceProviderOperationPaged[~azure.mgmt.kubernetesconfiguration.models.ResourceProviderOperation] + :raises: + :class:`ErrorResponseException` + """ + def prepare_request(next_link=None): + if not next_link: + # Construct URL + url = self.list.metadata['url'] + + # Construct parameters + query_parameters = {} + query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str') + + else: + url = next_link + query_parameters = {} + + # Construct headers + header_parameters = {} + header_parameters['Accept'] = 'application/json' + if self.config.generate_client_request_id: + header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) + if custom_headers: + header_parameters.update(custom_headers) + if self.config.accept_language is not None: + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') + + # Construct and send request + request = self._client.get(url, query_parameters, header_parameters) + return request + + def internal_paging(next_link=None): + request = prepare_request(next_link) + + response = self._client.send(request, stream=False, **operation_config) + + if response.status_code not in [200]: + raise models.ErrorResponseException(self._deserialize, response) + + return response + + # Deserialize response + header_dict = None + if raw: + header_dict = {} + deserialized = models.ResourceProviderOperationPaged(internal_paging, self._deserialize.dependencies, header_dict) + + return deserialized + list.metadata = {'url': '/providers/Microsoft.KubernetesConfiguration/operations'} diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/operations/_source_control_configurations_operations.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/operations/_source_control_configurations_operations.py new file mode 100644 index 00000000000..4b4a8599262 --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/operations/_source_control_configurations_operations.py @@ -0,0 +1,386 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +import uuid +from msrest.pipeline import ClientRawResponse +from msrest.polling import LROPoller, NoPolling +from msrestazure.polling.arm_polling import ARMPolling + +from .. import models + + +class SourceControlConfigurationsOperations(object): + """SourceControlConfigurationsOperations operations. + + You should not instantiate directly this class, but create a Client instance that will create it for you and attach it as attribute. + + :param client: Client for service requests. + :param config: Configuration of service client. + :param serializer: An object model serializer. + :param deserializer: An object model deserializer. + :ivar api_version: The API version to be used with the HTTP request. Constant value: "2021-03-01". + """ + + models = models + + def __init__(self, client, config, serializer, deserializer): + + self._client = client + self._serialize = serializer + self._deserialize = deserializer + self.api_version = "2021-03-01" + + self.config = config + + def get( + self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, source_control_configuration_name, custom_headers=None, raw=False, **operation_config): + """Gets details of the Source Control Configuration. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either + Microsoft.ContainerService (for AKS clusters) or Microsoft.Kubernetes + (for OnPrem K8S clusters). Possible values include: + 'Microsoft.ContainerService', 'Microsoft.Kubernetes' + :type cluster_rp: str + :param cluster_resource_name: The Kubernetes cluster resource name - + either managedClusters (for AKS clusters) or connectedClusters (for + OnPrem K8S clusters). Possible values include: 'managedClusters', + 'connectedClusters' + :type cluster_resource_name: str + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control + Configuration. + :type source_control_configuration_name: str + :param dict custom_headers: headers that will be added to the request + :param bool raw: returns the direct response alongside the + deserialized response + :param operation_config: :ref:`Operation configuration + overrides`. + :return: SourceControlConfiguration or ClientRawResponse if raw=true + :rtype: + ~azure.mgmt.kubernetesconfiguration.models.SourceControlConfiguration + or ~msrest.pipeline.ClientRawResponse + :raises: + :class:`ErrorResponseException` + """ + # Construct URL + url = self.get.metadata['url'] + path_format_arguments = { + 'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str') + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} + query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str') + + # Construct headers + header_parameters = {} + header_parameters['Accept'] = 'application/json' + if self.config.generate_client_request_id: + header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) + if custom_headers: + header_parameters.update(custom_headers) + if self.config.accept_language is not None: + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') + + # Construct and send request + request = self._client.get(url, query_parameters, header_parameters) + response = self._client.send(request, stream=False, **operation_config) + + if response.status_code not in [200]: + raise models.ErrorResponseException(self._deserialize, response) + + deserialized = None + if response.status_code == 200: + deserialized = self._deserialize('SourceControlConfiguration', response) + + if raw: + client_raw_response = ClientRawResponse(deserialized, response) + return client_raw_response + + return deserialized + get.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} + + def create_or_update( + self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, source_control_configuration_name, source_control_configuration, custom_headers=None, raw=False, **operation_config): + """Create a new Kubernetes Source Control Configuration. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either + Microsoft.ContainerService (for AKS clusters) or Microsoft.Kubernetes + (for OnPrem K8S clusters). Possible values include: + 'Microsoft.ContainerService', 'Microsoft.Kubernetes' + :type cluster_rp: str + :param cluster_resource_name: The Kubernetes cluster resource name - + either managedClusters (for AKS clusters) or connectedClusters (for + OnPrem K8S clusters). Possible values include: 'managedClusters', + 'connectedClusters' + :type cluster_resource_name: str + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control + Configuration. + :type source_control_configuration_name: str + :param source_control_configuration: Properties necessary to Create + KubernetesConfiguration. + :type source_control_configuration: + ~azure.mgmt.kubernetesconfiguration.models.SourceControlConfiguration + :param dict custom_headers: headers that will be added to the request + :param bool raw: returns the direct response alongside the + deserialized response + :param operation_config: :ref:`Operation configuration + overrides`. + :return: SourceControlConfiguration or ClientRawResponse if raw=true + :rtype: + ~azure.mgmt.kubernetesconfiguration.models.SourceControlConfiguration + or ~msrest.pipeline.ClientRawResponse + :raises: + :class:`ErrorResponseException` + """ + # Construct URL + url = self.create_or_update.metadata['url'] + path_format_arguments = { + 'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str') + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} + query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str') + + # Construct headers + header_parameters = {} + header_parameters['Accept'] = 'application/json' + header_parameters['Content-Type'] = 'application/json; charset=utf-8' + if self.config.generate_client_request_id: + header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) + if custom_headers: + header_parameters.update(custom_headers) + if self.config.accept_language is not None: + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') + + # Construct body + body_content = self._serialize.body(source_control_configuration, 'SourceControlConfiguration') + + # Construct and send request + request = self._client.put(url, query_parameters, header_parameters, body_content) + response = self._client.send(request, stream=False, **operation_config) + + if response.status_code not in [200, 201]: + raise models.ErrorResponseException(self._deserialize, response) + + deserialized = None + if response.status_code == 200: + deserialized = self._deserialize('SourceControlConfiguration', response) + if response.status_code == 201: + deserialized = self._deserialize('SourceControlConfiguration', response) + + if raw: + client_raw_response = ClientRawResponse(deserialized, response) + return client_raw_response + + return deserialized + create_or_update.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} + + + def _delete_initial( + self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, source_control_configuration_name, custom_headers=None, raw=False, **operation_config): + # Construct URL + url = self.delete.metadata['url'] + path_format_arguments = { + 'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str'), + 'sourceControlConfigurationName': self._serialize.url("source_control_configuration_name", source_control_configuration_name, 'str') + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} + query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str') + + # Construct headers + header_parameters = {} + if self.config.generate_client_request_id: + header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) + if custom_headers: + header_parameters.update(custom_headers) + if self.config.accept_language is not None: + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') + + # Construct and send request + request = self._client.delete(url, query_parameters, header_parameters) + response = self._client.send(request, stream=False, **operation_config) + + if response.status_code not in [200, 204]: + raise models.ErrorResponseException(self._deserialize, response) + + if raw: + client_raw_response = ClientRawResponse(None, response) + return client_raw_response + + def delete( + self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, source_control_configuration_name, custom_headers=None, raw=False, polling=True, **operation_config): + """This will delete the YAML file used to set up the Source control + configuration, thus stopping future sync from the source repo. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either + Microsoft.ContainerService (for AKS clusters) or Microsoft.Kubernetes + (for OnPrem K8S clusters). Possible values include: + 'Microsoft.ContainerService', 'Microsoft.Kubernetes' + :type cluster_rp: str + :param cluster_resource_name: The Kubernetes cluster resource name - + either managedClusters (for AKS clusters) or connectedClusters (for + OnPrem K8S clusters). Possible values include: 'managedClusters', + 'connectedClusters' + :type cluster_resource_name: str + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param source_control_configuration_name: Name of the Source Control + Configuration. + :type source_control_configuration_name: str + :param dict custom_headers: headers that will be added to the request + :param bool raw: The poller return type is ClientRawResponse, the + direct response alongside the deserialized response + :param polling: True for ARMPolling, False for no polling, or a + polling object for personal polling strategy + :return: An instance of LROPoller that returns None or + ClientRawResponse if raw==True + :rtype: ~msrestazure.azure_operation.AzureOperationPoller[None] or + ~msrestazure.azure_operation.AzureOperationPoller[~msrest.pipeline.ClientRawResponse[None]] + :raises: + :class:`ErrorResponseException` + """ + raw_result = self._delete_initial( + resource_group_name=resource_group_name, + cluster_rp=cluster_rp, + cluster_resource_name=cluster_resource_name, + cluster_name=cluster_name, + source_control_configuration_name=source_control_configuration_name, + custom_headers=custom_headers, + raw=True, + **operation_config + ) + + def get_long_running_output(response): + if raw: + client_raw_response = ClientRawResponse(None, response) + return client_raw_response + + lro_delay = operation_config.get( + 'long_running_operation_timeout', + self.config.long_running_operation_timeout) + if polling is True: polling_method = ARMPolling(lro_delay, **operation_config) + elif polling is False: polling_method = NoPolling() + else: polling_method = polling + return LROPoller(self._client, raw_result, get_long_running_output, polling_method) + delete.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations/{sourceControlConfigurationName}'} + + def list( + self, resource_group_name, cluster_rp, cluster_resource_name, cluster_name, custom_headers=None, raw=False, **operation_config): + """List all Source Control Configurations. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param cluster_rp: The Kubernetes cluster RP - either + Microsoft.ContainerService (for AKS clusters) or Microsoft.Kubernetes + (for OnPrem K8S clusters). Possible values include: + 'Microsoft.ContainerService', 'Microsoft.Kubernetes' + :type cluster_rp: str + :param cluster_resource_name: The Kubernetes cluster resource name - + either managedClusters (for AKS clusters) or connectedClusters (for + OnPrem K8S clusters). Possible values include: 'managedClusters', + 'connectedClusters' + :type cluster_resource_name: str + :param cluster_name: The name of the kubernetes cluster. + :type cluster_name: str + :param dict custom_headers: headers that will be added to the request + :param bool raw: returns the direct response alongside the + deserialized response + :param operation_config: :ref:`Operation configuration + overrides`. + :return: An iterator like instance of SourceControlConfiguration + :rtype: + ~azure.mgmt.kubernetesconfiguration.models.SourceControlConfigurationPaged[~azure.mgmt.kubernetesconfiguration.models.SourceControlConfiguration] + :raises: + :class:`ErrorResponseException` + """ + def prepare_request(next_link=None): + if not next_link: + # Construct URL + url = self.list.metadata['url'] + path_format_arguments = { + 'subscriptionId': self._serialize.url("self.config.subscription_id", self.config.subscription_id, 'str'), + 'resourceGroupName': self._serialize.url("resource_group_name", resource_group_name, 'str'), + 'clusterRp': self._serialize.url("cluster_rp", cluster_rp, 'str'), + 'clusterResourceName': self._serialize.url("cluster_resource_name", cluster_resource_name, 'str'), + 'clusterName': self._serialize.url("cluster_name", cluster_name, 'str') + } + url = self._client.format_url(url, **path_format_arguments) + + # Construct parameters + query_parameters = {} + query_parameters['api-version'] = self._serialize.query("self.api_version", self.api_version, 'str') + + else: + url = next_link + query_parameters = {} + + # Construct headers + header_parameters = {} + header_parameters['Accept'] = 'application/json' + if self.config.generate_client_request_id: + header_parameters['x-ms-client-request-id'] = str(uuid.uuid1()) + if custom_headers: + header_parameters.update(custom_headers) + if self.config.accept_language is not None: + header_parameters['accept-language'] = self._serialize.header("self.config.accept_language", self.config.accept_language, 'str') + + # Construct and send request + request = self._client.get(url, query_parameters, header_parameters) + return request + + def internal_paging(next_link=None): + request = prepare_request(next_link) + + response = self._client.send(request, stream=False, **operation_config) + + if response.status_code not in [200]: + raise models.ErrorResponseException(self._deserialize, response) + + return response + + # Deserialize response + header_dict = None + if raw: + header_dict = {} + deserialized = models.SourceControlConfigurationPaged(internal_paging, self._deserialize.dependencies, header_dict) + + return deserialized + list.metadata = {'url': '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/sourceControlConfigurations'} diff --git a/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/version.py b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/version.py new file mode 100644 index 00000000000..9bd1dfac7ec --- /dev/null +++ b/src/k8s-configuration/azext_k8s_configuration/vendored_sdks/version.py @@ -0,0 +1,13 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- + +VERSION = "0.2.0" + diff --git a/src/k8s-configuration/setup.cfg b/src/k8s-configuration/setup.cfg new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/k8s-configuration/setup.py b/src/k8s-configuration/setup.py new file mode 100644 index 00000000000..d6aa1b2377d --- /dev/null +++ b/src/k8s-configuration/setup.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python + +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + + +from codecs import open +from setuptools import setup, find_packages +try: + from azure_bdist_wheel import cmdclass +except ImportError: + from distutils import log as logger + logger.warn("Wheel is not available, disabling bdist_wheel hook") + +# TODO: Confirm this is the right version number you want and it matches your +# HISTORY.rst entry. +VERSION = '1.0.0' + +# The full list of classifiers is available at +# https://pypi.python.org/pypi?%3Aaction=list_classifiers +CLASSIFIERS = [ + 'Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'Intended Audience :: System Administrators', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'License :: OSI Approved :: MIT License', +] + +# TODO: Add any additional SDK dependencies here +DEPENDENCIES = ["pycryptodome~=3.9.8"] + +with open('README.rst', 'r', encoding='utf-8') as f: + README = f.read() +with open('HISTORY.rst', 'r', encoding='utf-8') as f: + HISTORY = f.read() + +setup( + name='k8s-configuration', + version=VERSION, + description='Microsoft Azure Command-Line Tools K8s-configuration Extension', + # TODO: Update author and email, if applicable + author='Microsoft Corporation', + author_email='azpycli@microsoft.com', + url='https://github.com/Azure/azure-cli-extensions/tree/master/src/k8s-configuration', + long_description=README + '\n\n' + HISTORY, + license='MIT', + classifiers=CLASSIFIERS, + packages=find_packages(), + install_requires=DEPENDENCIES, + package_data={'azext_k8s_configuration': ['azext_metadata.json']}, +) diff --git a/src/k8sconfiguration/HISTORY.rst b/src/k8sconfiguration/HISTORY.rst index e6feb7422f2..eb0e0e9040f 100644 --- a/src/k8sconfiguration/HISTORY.rst +++ b/src/k8sconfiguration/HISTORY.rst @@ -3,6 +3,10 @@ Release History =============== +0.2.4 +++++++++++++++++++ +* Deprecate k8sconfiguration + 0.2.3 ++++++++++++++++++ * Add parameter regex validation, improve table formatting diff --git a/src/k8sconfiguration/azext_k8sconfiguration/commands.py b/src/k8sconfiguration/azext_k8sconfiguration/commands.py index 897101c907a..7a435147b14 100644 --- a/src/k8sconfiguration/azext_k8sconfiguration/commands.py +++ b/src/k8sconfiguration/azext_k8sconfiguration/commands.py @@ -15,9 +15,10 @@ def load_command_table(self, _): operations_tmpl='azext_k8sconfiguration.vendored_sdks.operations#SourceControlConfigurationsOperations.{}', client_factory=cf_k8sconfiguration) - with self.command_group('k8sconfiguration', k8sconfiguration_sdk, client_factory=cf_k8sconfiguration_operation, - is_preview=True) \ - as g: + with self.command_group('k8sconfiguration', k8sconfiguration_sdk, + client_factory=cf_k8sconfiguration_operation, + is_preview=True, + deprecate_info=self.deprecate(redirect='k8s-configuration', hide=True)) as g: g.custom_command('create', 'create_k8sconfiguration') g.custom_command('update', 'update_k8sconfiguration') g.custom_command('delete', 'delete_k8sconfiguration', confirmation=True) diff --git a/src/k8sconfiguration/azext_k8sconfiguration/custom.py b/src/k8sconfiguration/azext_k8sconfiguration/custom.py index 9e3fe590122..772ab707297 100644 --- a/src/k8sconfiguration/azext_k8sconfiguration/custom.py +++ b/src/k8sconfiguration/azext_k8sconfiguration/custom.py @@ -7,7 +7,7 @@ import io from urllib.parse import urlparse from azure.cli.core.azclierror import InvalidArgumentValueError, ResourceNotFoundError, \ - RequiredArgumentMissingError, MutuallyExclusiveArgumentError + RequiredArgumentMissingError, MutuallyExclusiveArgumentError, CommandNotFoundError from knack.log import get_logger from paramiko.ed25519key import Ed25519Key from paramiko.hostkeys import HostKeyEntry @@ -118,56 +118,63 @@ def update_k8sconfiguration(client, resource_group_name, cluster_name, name, clu """Update an existing Kubernetes Source Control Configuration. """ - # Determine ClusterRP - cluster_rp = __get_cluster_type(cluster_type) - source_control_configuration_name = name.strip() + # TODO: Remove this after we eventually get PATCH implemented for update and uncomment + raise CommandNotFoundError( + "\"k8sconfiguration update\" currently is not available. " + "Use \"k8sconfiguration create\" to update a previously created configuration." + ) - config = client.get(resource_group_name, cluster_rp, cluster_type, cluster_name, - source_control_configuration_name).as_dict() + # # Determine ClusterRP + # cluster_rp = __get_cluster_type(cluster_type) - update_yes = False + # source_control_configuration_name = name.strip() - # Set input values, if they are supplied - if repository_url is not None: - config['repository_url'] = repository_url - update_yes = True + # config = client.get(resource_group_name, cluster_rp, cluster_type, cluster_name, + # source_control_configuration_name).as_dict() - if operator_params is not None: - config['operator_params'] = operator_params - update_yes = True + # update_yes = False - knownhost_data = get_data_from_key_or_file(ssh_known_hosts, ssh_known_hosts_file) - if knownhost_data != '': - validate_known_hosts(knownhost_data) - config['ssh_known_hosts_contents'] = knownhost_data - update_yes = True + # # Set input values, if they are supplied + # if repository_url is not None: + # config['repository_url'] = repository_url + # update_yes = True - if enable_helm_operator is not None: - config['enable_helm_operator'] = enable_helm_operator - update_yes = True + # if operator_params is not None: + # config['operator_params'] = operator_params + # update_yes = True - if helm_operator_version is not None: - config['helm_operator_version'] = helm_operator_version - update_yes = True + # knownhost_data = get_data_from_key_or_file(ssh_known_hosts, ssh_known_hosts_file) + # if knownhost_data != '': + # validate_known_hosts(knownhost_data) + # config['ssh_known_hosts_contents'] = knownhost_data + # update_yes = True - if helm_operator_params is not None: - config['helm_operator_params'] = helm_operator_params - update_yes = True + # if enable_helm_operator is not None: + # config['enable_helm_operator'] = enable_helm_operator + # update_yes = True - if update_yes is False: - raise RequiredArgumentMissingError( - 'Invalid update. No values to update!', - 'Verify that at least one changed parameter is provided in the update command') + # if helm_operator_version is not None: + # config['helm_operator_version'] = helm_operator_version + # update_yes = True - # Flag which parameters have been set and validate these settings against the set repository url - ssh_known_hosts_set = 'ssh_known_hosts_contents' in config - validate_url_with_params(config['repository_url'], False, ssh_known_hosts_set, False) + # if helm_operator_params is not None: + # config['helm_operator_params'] = helm_operator_params + # update_yes = True - config = client.create_or_update(resource_group_name, cluster_rp, cluster_type, cluster_name, - source_control_configuration_name, config) + # if update_yes is False: + # raise RequiredArgumentMissingError( + # 'Invalid update. No values to update!', + # 'Verify that at least one changed parameter is provided in the update command') - return __fix_compliance_state(config) + # # Flag which parameters have been set and validate these settings against the set repository url + # ssh_known_hosts_set = 'ssh_known_hosts_contents' in config + # validate_url_with_params(config['repository_url'], False, ssh_known_hosts_set, False) + + # config = client.create_or_update(resource_group_name, cluster_rp, cluster_type, cluster_name, + # source_control_configuration_name, config) + + # return __fix_compliance_state(config) def list_k8sconfiguration(client, resource_group_name, cluster_name, cluster_type): diff --git a/src/k8sconfiguration/setup.cfg b/src/k8sconfiguration/setup.cfg index 3c6e79cf31d..e69de29bb2d 100644 --- a/src/k8sconfiguration/setup.cfg +++ b/src/k8sconfiguration/setup.cfg @@ -1,2 +0,0 @@ -[bdist_wheel] -universal=1 diff --git a/src/k8sconfiguration/setup.py b/src/k8sconfiguration/setup.py index b160fe9fc33..ab68926b518 100644 --- a/src/k8sconfiguration/setup.py +++ b/src/k8sconfiguration/setup.py @@ -16,7 +16,7 @@ # TODO: Confirm this is the right version number you want and it matches your # HISTORY.rst entry. -VERSION = '0.2.3' +VERSION = '0.2.4' # The full list of classifiers is available at # https://pypi.python.org/pypi?%3Aaction=list_classifiers @@ -33,7 +33,7 @@ ] # TODO: Add any additional SDK dependencies here -DEPENDENCIES = ["pycryptodome~=3.9.8", "paramiko~=2.6.0"] +DEPENDENCIES = ["pycryptodome~=3.9.8"] with open('README.rst', 'r', encoding='utf-8') as f: README = f.read()