Hello community, here is the log from the commit of package azure-cli-acs for openSUSE:Factory checked in at 2018-05-13 16:01:01 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/azure-cli-acs (Old) and /work/SRC/openSUSE:Factory/.azure-cli-acs.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "azure-cli-acs" Sun May 13 16:01:01 2018 rev:3 rq:600030 version:2.0.31 Changes: -------- --- /work/SRC/openSUSE:Factory/azure-cli-acs/azure-cli-acs.changes 2018-02-14 09:29:35.603890581 +0100 +++ /work/SRC/openSUSE:Factory/.azure-cli-acs.new/azure-cli-acs.changes 2018-05-13 16:01:04.647060819 +0200 @@ -1,0 +2,8 @@ +Tue Apr 17 13:32:03 UTC 2018 - adrian.glaub...@suse.com + +- New upstream release + + Version 2.0.31 +- Move LICENSE.txt from %doc to %license section +- Update Requires from setup.py + +------------------------------------------------------------------- Old: ---- azure-cli-acs-2.0.25.tar.gz New: ---- azure-cli-acs-2.0.31.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ azure-cli-acs.spec ++++++ --- /var/tmp/diff_new_pack.HImciI/_old 2018-05-13 16:01:05.379034114 +0200 +++ /var/tmp/diff_new_pack.HImciI/_new 2018-05-13 16:01:05.383033968 +0200 @@ -17,7 +17,7 @@ Name: azure-cli-acs -Version: 2.0.25 +Version: 2.0.31 Release: 0 Summary: Microsoft Azure CLI 'acs' Command Module License: MIT @@ -35,14 +35,15 @@ Requires: azure-cli-core Requires: azure-cli-nspkg Requires: python3-PyYAML -Requires: python3-azure-graphrbac >= 0.31.0 -Requires: python3-azure-mgmt-authorization >= 0.30.0 -Requires: python3-azure-mgmt-compute >= 3.1.0rc3 -Requires: python3-azure-mgmt-containerservice >= 3.0.0 +Requires: python3-azure-graphrbac >= 0.40.0 +Requires: python3-azure-mgmt-authorization >= 0.40.0 +Requires: python3-azure-mgmt-compute >= 4.0.0rc1 +Requires: python3-azure-mgmt-containerservice >= 3.0.1 Requires: python3-azure-nspkg Requires: python3-paramiko Requires: python3-scp Requires: python3-six +Requires: python3-sshtunnel Conflicts: azure-cli < 2.0.0 BuildArch: noarch @@ -71,7 +72,8 @@ %files %defattr(-,root,root,-) -%doc HISTORY.rst LICENSE.txt README.rst +%doc HISTORY.rst README.rst +%license LICENSE.txt %{python3_sitelib}/azure/cli/command_modules/acs %{python3_sitelib}/azure_cli_acs-*.egg-info ++++++ azure-cli-acs-2.0.25.tar.gz -> azure-cli-acs-2.0.31.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-acs-2.0.25/HISTORY.rst new/azure-cli-acs-2.0.31/HISTORY.rst --- old/azure-cli-acs-2.0.25/HISTORY.rst 2018-01-26 17:12:23.000000000 +0100 +++ new/azure-cli-acs-2.0.31/HISTORY.rst 2018-04-06 19:33:13.000000000 +0200 @@ -3,6 +3,45 @@ Release History =============== +2.0.31 +++++++ + +* `sdist` is now compatible with wheel 0.31.0 + +2.0.30 +++++++ +* Minor fixes +* aks created spn will be valid for 5 years + +2.0.29 +++++++ +* fix a certificate verification error for `az aks install-cli` in Cloud Shell / PS + +2.0.28 +++++++ +* Support Autorest 3.0 based SDKs +* warn the user that `az aks browse` won't work in Azure Cloud Shell +* add `aks upgrade-connector` command to upgrade an existing connector +* `kubectl` config files are more readable block-style YAML + +2.0.27 +++++++ +* use the virtual-kubelet-for-aks helm chart for `aks install-connector` by default +* fix the service principal insufficient permission to create ACI container group issue +* add --aci-container-group, --location, --image-tag optional parameters for `aks install-connector` +* remove deprecation notice from `aks get-versions` + +2.0.26 +++++++ +* rename `aks get-versions` to `aks get-upgrades` in the interest of accuracy +* reimplement `aks get-versions` to show Kubernetes versions available for `aks create` +* `aks create` defaults to letting the server choose the version of Kubernetes +* update help messages referring to the service principal generated by AKS +* `aks create` VM node size default changed from "Standard_D1_v2" to "Standard_DS1_v2" +* improve reliability when locating the dashboard pod for `az aks browse` +* `aks get-credentials` handles UnicodeDecodeError when loading Kubernetes configuration files +* add a message to `az aks install-cli` to help get `kubectl.exe` in the search PATH + 2.0.25 ++++++ * clarify `--disable-browser` argument diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-acs-2.0.25/PKG-INFO new/azure-cli-acs-2.0.31/PKG-INFO --- old/azure-cli-acs-2.0.25/PKG-INFO 2018-01-26 17:12:48.000000000 +0100 +++ new/azure-cli-acs-2.0.31/PKG-INFO 2018-04-06 19:33:32.000000000 +0200 @@ -1,11 +1,12 @@ Metadata-Version: 1.1 Name: azure-cli-acs -Version: 2.0.25 +Version: 2.0.31 Summary: Microsoft Azure Command-Line Tools ACS Command Module Home-page: https://github.com/Azure/azure-cli Author: Microsoft Corporation Author-email: azpy...@microsoft.com License: MIT +Description-Content-Type: UNKNOWN Description: Microsoft Azure CLI 'acs' Command Module ======================================== @@ -18,6 +19,45 @@ Release History =============== + 2.0.31 + ++++++ + + * `sdist` is now compatible with wheel 0.31.0 + + 2.0.30 + ++++++ + * Minor fixes + * aks created spn will be valid for 5 years + + 2.0.29 + ++++++ + * fix a certificate verification error for `az aks install-cli` in Cloud Shell / PS + + 2.0.28 + ++++++ + * Support Autorest 3.0 based SDKs + * warn the user that `az aks browse` won't work in Azure Cloud Shell + * add `aks upgrade-connector` command to upgrade an existing connector + * `kubectl` config files are more readable block-style YAML + + 2.0.27 + ++++++ + * use the virtual-kubelet-for-aks helm chart for `aks install-connector` by default + * fix the service principal insufficient permission to create ACI container group issue + * add --aci-container-group, --location, --image-tag optional parameters for `aks install-connector` + * remove deprecation notice from `aks get-versions` + + 2.0.26 + ++++++ + * rename `aks get-versions` to `aks get-upgrades` in the interest of accuracy + * reimplement `aks get-versions` to show Kubernetes versions available for `aks create` + * `aks create` defaults to letting the server choose the version of Kubernetes + * update help messages referring to the service principal generated by AKS + * `aks create` VM node size default changed from "Standard_D1_v2" to "Standard_DS1_v2" + * improve reliability when locating the dashboard pod for `az aks browse` + * `aks get-credentials` handles UnicodeDecodeError when loading Kubernetes configuration files + * add a message to `az aks install-cli` to help get `kubectl.exe` in the search PATH + 2.0.25 ++++++ * clarify `--disable-browser` argument diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-acs-2.0.25/azure/cli/command_modules/acs/_client_factory.py new/azure-cli-acs-2.0.31/azure/cli/command_modules/acs/_client_factory.py --- old/azure-cli-acs-2.0.25/azure/cli/command_modules/acs/_client_factory.py 2018-01-26 17:12:23.000000000 +0100 +++ new/azure-cli-acs-2.0.31/azure/cli/command_modules/acs/_client_factory.py 2018-04-06 19:33:13.000000000 +0200 @@ -3,13 +3,11 @@ # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- -from azure.cli.core.commands.client_factory import configure_common_settings from azure.cli.core.commands.client_factory import get_mgmt_service_client +from azure.cli.core.profiles import ResourceType def cf_compute_service(cli_ctx, *_): - from azure.cli.core.profiles import ResourceType - return get_mgmt_service_client(cli_ctx, ResourceType.MGMT_COMPUTE) @@ -21,6 +19,10 @@ return get_container_service_client(cli_ctx).managed_clusters +def cf_resource_groups(cli_ctx, *_): + return get_mgmt_service_client(cli_ctx, ResourceType.MGMT_RESOURCE_RESOURCES).resource_groups + + def get_auth_management_client(cli_ctx, scope=None, **_): import re from azure.mgmt.authorization import AuthorizationManagementClient @@ -41,6 +43,7 @@ def get_graph_rbac_management_client(cli_ctx, **_): + from azure.cli.core.commands.client_factory import configure_common_settings from azure.cli.core._profile import Profile from azure.graphrbac import GraphRbacManagementClient diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-acs-2.0.25/azure/cli/command_modules/acs/_completers.py new/azure-cli-acs-2.0.31/azure/cli/command_modules/acs/_completers.py --- old/azure-cli-acs-2.0.25/azure/cli/command_modules/acs/_completers.py 2018-01-26 17:12:23.000000000 +0100 +++ new/azure-cli-acs-2.0.31/azure/cli/command_modules/acs/_completers.py 2018-04-06 19:33:13.000000000 +0200 @@ -5,22 +5,80 @@ from azure.cli.core.commands.parameters import get_one_of_subscription_locations from azure.cli.core.decorators import Completer -from azure.mgmt.containerservice.models import ContainerServiceVMSizeTypes -from ._client_factory import cf_compute_service + +@Completer +def get_k8s_upgrades_completion_list(cmd, prefix, namespace, **kwargs): # pylint: disable=unused-argument + """Return Kubernetes versions available for upgrading an existing cluster.""" + resource_group = getattr(namespace, 'resource_group_name', None) + name = getattr(namespace, 'name', None) + return get_k8s_upgrades(cmd.cli_ctx, resource_group, name) if resource_group and name else None + + +def get_k8s_upgrades(cli_ctx, resource_group, name): + from ._client_factory import cf_managed_clusters + + results = cf_managed_clusters(cli_ctx).get_upgrade_profile(resource_group, name).as_dict() + return results['control_plane_profile']['upgrades'] + + +@Completer +def get_k8s_versions_completion_list(cmd, prefix, namespace, **kwargs): # pylint: disable=unused-argument + """Return Kubernetes versions available for provisioning a new cluster.""" + location = _get_location(cmd.cli_ctx, namespace) + return get_k8s_versions(cmd.cli_ctx, location) if location else None + + +def get_k8s_versions(cli_ctx, location): + """Return a list of Kubernetes versions available for a new cluster.""" + from ._client_factory import cf_container_services + from jmespath import search + + results = cf_container_services(cli_ctx).list_orchestrators(location, resource_type='managedClusters').as_dict() + # Flatten all the "orchestrator_version" fields into one array + return search('orchestrators[*].orchestrator_version', results) @Completer def get_vm_size_completion_list(cmd, prefix, namespace, **kwargs): # pylint: disable=unused-argument """Return the intersection of the VM sizes allowed by the ACS SDK with those returned by the Compute Service.""" - try: - location = namespace.location - except AttributeError: - # TODO: try the resource group's default location before falling back to this - location = get_one_of_subscription_locations(cmd.cli_ctx) + from azure.mgmt.containerservice.models import ContainerServiceVMSizeTypes + + location = _get_location(cmd.cli_ctx, namespace) result = get_vm_sizes(cmd.cli_ctx, location) - return sorted(set(r.name for r in result) & set(c.value for c in ContainerServiceVMSizeTypes)) + return set(r.name for r in result) & set(c.value for c in ContainerServiceVMSizeTypes) def get_vm_sizes(cli_ctx, location): - return list(cf_compute_service(cli_ctx).virtual_machine_sizes.list(location)) + from ._client_factory import cf_compute_service + + return cf_compute_service(cli_ctx).virtual_machine_sizes.list(location) + + +def _get_location(cli_ctx, namespace): + """ + Return an Azure location by using an explicit `--location` argument, then by `--resource-group`, and + finally by the subscription if neither argument was provided. + """ + location = None + if getattr(namespace, 'location', None): + location = namespace.location + elif getattr(namespace, 'resource_group_name', None): + location = _get_location_from_resource_group(cli_ctx, namespace.resource_group_name) + if not location: + location = get_one_of_subscription_locations(cli_ctx) + return location + + +def _get_location_from_resource_group(cli_ctx, resource_group_name): + from ._client_factory import cf_resource_groups + from msrestazure.azure_exceptions import CloudError + + try: + rg = cf_resource_groups(cli_ctx).get(resource_group_name) + return rg.location + except CloudError as err: + # Print a warning if the user hit [TAB] but the `--resource-group` argument was incorrect. + # For example: "Warning: Resource group 'bogus' could not be found." + from argcomplete import warn + warn('Warning: {}'.format(err.message)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-acs-2.0.25/azure/cli/command_modules/acs/_format.py new/azure-cli-acs-2.0.31/azure/cli/command_modules/acs/_format.py --- old/azure-cli-acs-2.0.25/azure/cli/command_modules/acs/_format.py 2018-01-26 17:12:23.000000000 +0100 +++ new/azure-cli-acs-2.0.31/azure/cli/command_modules/acs/_format.py 2018-04-06 19:33:13.000000000 +0200 @@ -17,38 +17,66 @@ def _aks_table_format(result): - # put results in an ordered dict so the headers are predictable - table_row = OrderedDict() - for k in ['name', 'location', 'resourceGroup', 'kubernetesVersion', 'provisioningState', 'fqdn']: - table_row[k] = result.get(k) - return table_row - - -def aks_get_versions_table_format(result): - """Format get-versions upgrade results as a summary for display with "-o table".""" - master = result.get('controlPlaneProfile', {}) - result['masterVersion'] = master.get('kubernetesVersion', 'unknown') - master_upgrades = master.get('upgrades', []) - result['masterUpgrades'] = ', '.join(master_upgrades) if master_upgrades else 'None available' - - agents = result.get('agentPoolProfiles', []) - versions, upgrades = [], [] - for agent in agents: - version = agent.get('kubernetesVersion', 'unknown') - agent_upgrades = agent.get('upgrades', []) - upgrade = ', '.join(agent_upgrades) if agent_upgrades else 'None available' - name = agent.get('name') - if name: # multiple agent pools, presumably - version = "{}: {}".format(name, version) - upgrade = "{}: {}".format(name, upgrades) - versions.append(version) - upgrades.append(upgrade) - - result['nodePoolVersion'] = ', '.join(versions) - result['nodePoolUpgrades'] = ', '.join(upgrades) - - # put results in an ordered dict so the headers are predictable - table_row = OrderedDict() - for k in ['name', 'resourceGroup', 'masterVersion', 'masterUpgrades', 'nodePoolVersion', 'nodePoolUpgrades']: - table_row[k] = result.get(k) - return [table_row] + from jmespath import compile as compile_jmes, Options + + parsed = compile_jmes("""{ + name: name, + location: location, + resourceGroup: resourceGroup, + kubernetesVersion: kubernetesVersion, + provisioningState: provisioningState, + fqdn: fqdn + }""") + # use ordered dicts so headers are predictable + return parsed.search(result, Options(dict_cls=OrderedDict)) + + +def aks_upgrades_table_format(result): + """Format get-upgrades results as a summary for display with "-o table".""" + from jmespath import compile as compile_jmes, Options + + # This expression assumes there is one node pool, and that the master and nodes upgrade in lockstep. + parsed = compile_jmes("""{ + name: name, + resourceGroup: resourceGroup, + masterVersion: controlPlaneProfile.kubernetesVersion || `unknown`, + nodePoolVersion: agentPoolProfiles[0].kubernetesVersion || `unknown`, + upgrades: controlPlaneProfile.upgrades || [`None available`] | sort_versions(@) | join(`, `, @) + }""") + # use ordered dicts so headers are predictable + return parsed.search(result, Options(dict_cls=OrderedDict, custom_functions=_custom_functions())) + + +def aks_versions_table_format(result): + """Format get-versions results as a summary for display with "-o table".""" + from jmespath import compile as compile_jmes, Options + + parsed = compile_jmes("""orchestrators[].{ + kubernetesVersion: orchestratorVersion, + upgrades: upgrades[].orchestratorVersion || [`None available`] | sort_versions(@) | join(`, `, @) + }""") + # use ordered dicts so headers are predictable + results = parsed.search(result, Options(dict_cls=OrderedDict, custom_functions=_custom_functions())) + return sorted(results, key=lambda x: version_to_tuple(x.get('kubernetesVersion')), reverse=True) + + +def version_to_tuple(v): + """Quick-and-dirty sort function to handle simple semantic versions like 1.7.12 or 1.8.7.""" + return tuple(map(int, (v.split('.')))) + + +def _custom_functions(): + + from jmespath import functions + + class CustomFunctions(functions.Functions): # pylint: disable=too-few-public-methods + + @functions.signature({'types': ['array']}) + def _func_sort_versions(self, s): # pylint: disable=no-self-use + """Custom JMESPath `sort_versions` function that sorts an array of strings as software versions.""" + try: + return sorted(s, key=version_to_tuple) + except (TypeError, ValueError): # if it wasn't sortable, return the input so the pipeline continues + return s + + return CustomFunctions() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-acs-2.0.25/azure/cli/command_modules/acs/_help.py new/azure-cli-acs-2.0.31/azure/cli/command_modules/acs/_help.py --- old/azure-cli-acs-2.0.25/azure/cli/command_modules/acs/_help.py 2018-01-26 17:12:23.000000000 +0100 +++ new/azure-cli-acs-2.0.31/azure/cli/command_modules/acs/_help.py 2018-04-06 19:33:13.000000000 +0200 @@ -7,7 +7,8 @@ from knack.help_files import helps -SERVICE_PRINCIPAL_CACHE = os.path.join('$HOME', '.azure', 'acsServicePrincipal.json') +ACS_SERVICE_PRINCIPAL_CACHE = os.path.join('$HOME', '.azure', 'acsServicePrincipal.json') +AKS_SERVICE_PRINCIPAL_CACHE = os.path.join('$HOME', '.azure', 'aksServicePrincipal.json') # ACS command help @@ -64,7 +65,7 @@ }}]' - name: Create a DCOS cluster with agent-profiles specified from a file. text: az acs create -g MyResourceGroup -n MyContainerService --agent-profiles MyAgentProfiles.json -""".format(sp_cache=SERVICE_PRINCIPAL_CACHE) +""".format(sp_cache=ACS_SERVICE_PRINCIPAL_CACHE) helps['acs dcos'] = """ type: group @@ -144,7 +145,7 @@ - name: --service-principal type: string short-summary: Service principal used for authentication to Azure APIs. - long-summary: If not specified, a new service principal with the contributor role is created and cached at + long-summary: If not specified, a new service principal is created and cached at {sp_cache} to be used by subsequent `az aks` commands. - name: --client-secret type: string @@ -166,7 +167,9 @@ short-summary: Size in GB of the OS disk for each node in the node pool. - name: --kubernetes-version -k type: string - short-summary: Version of Kubernetes to use for creating the cluster, such as "1.7.7" or "1.8.2". + short-summary: Version of Kubernetes to use for creating the cluster, such as "1.7.12" or "1.8.7". + populator-commands: + - "`az aks get-versions`" - name: --ssh-key-value type: string short-summary: Public key path or key contents to install on node VMs for SSH access. For example, @@ -178,10 +181,10 @@ - name: Create a Kubernetes cluster with an existing SSH public key. text: az aks create -g MyResourceGroup -n MyManagedCluster --ssh-key-value /path/to/publickey - name: Create a Kubernetes cluster with a specific version. - text: az aks create -g MyResourceGroup -n MyManagedCluster --kubernetes-version 1.8.1 + text: az aks create -g MyResourceGroup -n MyManagedCluster --kubernetes-version 1.8.7 - name: Create a Kubernetes cluster with a larger node pool. text: az aks create -g MyResourceGroup -n MyManagedCluster --node-count 7 -""".format(sp_cache=SERVICE_PRINCIPAL_CACHE) +""".format(sp_cache=AKS_SERVICE_PRINCIPAL_CACHE) helps['aks delete'] = """ type: command @@ -200,9 +203,14 @@ short-summary: Kubernetes configuration file to update. Use "-" to print YAML to stdout instead. """ +helps['aks get-upgrades'] = """ + type: command + short-summary: Get the upgrade versions available for a managed Kubernetes cluster. +""" + helps['aks get-versions'] = """ type: command - short-summary: Get versions available to upgrade a managed Kubernetes cluster. + short-summary: Get the versions available for creating a managed Kubernetes cluster. """ helps['aks install-cli'] = """ @@ -212,7 +220,7 @@ helps['aks install-connector'] = """ type: command - short-summary: Install the Azure Container Instances (ACI) Connector on a managed Kubernetes cluster. + short-summary: Install the ACI Connector on a managed Kubernetes cluster. parameters: - name: --chart-url type: string @@ -226,34 +234,46 @@ - name: --service-principal type: string short-summary: Service principal used for authentication to Azure APIs. - long-summary: If not specified, a new service principal with the contributor role is created and cached at - {sp_cache} to be used by subsequent `az aks` commands. + long-summary: If not specified, use the AKS service principal defined in the file + /etc/kubernetes/azure.json on the node which runs the virtual kubelet pod. - name: --client-secret type: string short-summary: Secret associated with the service principal. This argument is required if `--service-principal` is specified. + - name: --image-tag + type: string + short-summary: The image tag of the virtual kubelet. Use 'latest' if it is not specified + - name: --aci-resource-group + type: string + short-summary: The resource group to create the ACI container groups. Use the MC_* + resource group if it is not specified. + - name: --location + type: string + short-summary: The location to create the ACI container groups. Use the location of the MC_* + resource group if it is not specified. examples: - name: Install the ACI Connector for Linux to a managed Kubernetes cluster. text: |- az aks install-connector --name MyManagedCluster --resource-group MyResourceGroup \\ - --connector-name MyConnector + --connector-name aci-connector - name: Install the ACI Connector for Windows to a managed Kubernetes cluster. text: |- az aks install-connector --name MyManagedCluster --resource-group MyResourceGroup \\ - --connector-name MyConnector --os-type Windows + --connector-name aci-connector --os-type Windows - name: Install the ACI Connector for both Windows and Linux to a managed Kubernetes cluster. text: |- az aks install-connector --name MyManagedCluster --resource-group MyResourceGroup \\ - --connector-name MyConnector --os-type Both - - name: Install the ACI Connector using a specific service principal. + --connector-name aci-connector --os-type Both + - name: Install the ACI Connector using a specific service principal in a specific resource group. text: |- az aks install-connector --name MyManagedCluster --resource-group MyResourceGroup \\ - --connector-name MyConnector --service-principal <SPN_ID> --client-secret <SPN_SECRET> - - name: Install the ACI Connector from a custom Helm chart. + --connector-name aci-connector --service-principal <SPN_ID> --client-secret <SPN_SECRET> \\ + --aci-resource-group <ACI resource group> + - name: Install the ACI Connector from a custom Helm chart with custom tag. text: |- az aks install-connector --name MyManagedCluster --resource-group MyResourceGroup \\ - --connector-name MyConnector --chart-url <CustomURL> -""".format(sp_cache=SERVICE_PRINCIPAL_CACHE) + --connector-name aci-connector --chart-url <CustomURL> --image-tag <VirtualKubeletImageTag> +""".format(sp_cache=AKS_SERVICE_PRINCIPAL_CACHE) helps['aks list'] = """ type: command @@ -301,9 +321,66 @@ parameters: - name: --kubernetes-version -k type: string - short-summary: Version of Kubernetes to upgrade the cluster to, such as "1.7.7" or "1.8.2". + short-summary: Version of Kubernetes to upgrade the cluster to, such as "1.7.12" or "1.8.7". populator-commands: - - "`az aks get-versions`" + - "`az aks get-upgrades`" +""" + +helps['aks upgrade-connector'] = """ + type: command + short-summary: Upgrade the ACI Connector on a managed Kubernetes cluster. + parameters: + - name: --chart-url + type: string + short-summary: URL of a Helm chart that installs ACI Connector. + - name: --connector-name + type: string + short-summary: Name of the ACI Connector. + - name: --os-type + type: string + short-summary: Install support for deploying ACIs of this operating system type. + - name: --service-principal + type: string + short-summary: Service principal used for authentication to Azure APIs. + long-summary: If not specified, use the AKS service principal defined in the file + /etc/kubernetes/azure.json on the node which runs the virtual kubelet pod. + - name: --client-secret + type: string + short-summary: Secret associated with the service principal. This argument is required if + `--service-principal` is specified. + - name: --image-tag + type: string + short-summary: The image tag of the virtual kubelet. Use 'latest' if it is not specified + - name: --aci-resource-group + type: string + short-summary: The resource group to create the ACI container groups. Use the MC_* + resource group if it is not specified. + - name: --location + type: string + short-summary: The location to create the ACI container groups. Use the location of the MC_* + resource group if it is not specified. + examples: + - name: Upgrade the ACI Connector for Linux to a managed Kubernetes cluster. + text: |- + az aks upgrade-connector --name MyManagedCluster --resource-group MyResourceGroup \\ + --connector-name aci-connector + - name: Upgrade the ACI Connector for Windows to a managed Kubernetes cluster. + text: |- + az aks upgrade-connector --name MyManagedCluster --resource-group MyResourceGroup \\ + --connector-name aci-connector --os-type Windows + - name: Upgrade the ACI Connector for both Windows and Linux to a managed Kubernetes cluster. + text: |- + az aks upgrade-connector --name MyManagedCluster --resource-group MyResourceGroup \\ + --connector-name aci-connector --os-type Both + - name: Upgrade the ACI Connector to use a specific service principal in a specific resource group. + text: |- + az aks upgrade-connector --name MyManagedCluster --resource-group MyResourceGroup \\ + --connector-name aci-connector --service-principal <SPN_ID> --client-secret <SPN_SECRET> \\ + --aci-resource-group <ACI resource group> + - name: Upgrade the ACI Connector from a custom Helm chart with custom tag. + text: |- + az aks upgrade-connector --name MyManagedCluster --resource-group MyResourceGroup \\ + --connector-name aci-connector --chart-url <CustomURL> --image-tag <VirtualKubeletImageTag> """ helps['aks wait'] = """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-acs-2.0.25/azure/cli/command_modules/acs/_params.py new/azure-cli-acs-2.0.31/azure/cli/command_modules/acs/_params.py --- old/azure-cli-acs-2.0.25/azure/cli/command_modules/acs/_params.py 2018-01-26 17:12:23.000000000 +0100 +++ new/azure-cli-acs-2.0.31/azure/cli/command_modules/acs/_params.py 2018-04-06 19:33:13.000000000 +0200 @@ -13,7 +13,8 @@ file_type, get_enum_type, get_resource_name_completion_list, name_type, tags_type) from azure.cli.core.commands.validators import validate_file_or_dict -from ._completers import get_vm_size_completion_list +from ._completers import ( + get_vm_size_completion_list, get_k8s_versions_completion_list, get_k8s_upgrades_completion_list) from ._validators import ( validate_create_parameters, validate_k8s_client_version, validate_k8s_version, validate_linux_host_name, validate_list_of_integers, validate_ssh_key, validate_connector_name) @@ -21,7 +22,7 @@ aci_connector_os_type = ['Windows', 'Linux', 'Both'] -aci_connector_chart_url = 'https://github.com/virtual-kubelet/virtual-kubelet/raw/master/charts/virtual-kubelet-0.1.0.tgz' +aci_connector_chart_url = 'https://github.com/virtual-kubelet/virtual-kubelet/raw/master/charts/virtual-kubelet-for-aks-0.1.3.tgz' orchestrator_types = ["Custom", "DCOS", "Kubernetes", "Swarm", "DockerCE"] @@ -149,6 +150,7 @@ with self.argument_context('aks create') as c: c.argument('name', validator=validate_linux_host_name) + c.argument('kubernetes_version', completer=get_k8s_versions_completion_list) c.argument('admin_username', options_list=['--admin-username', '-u'], default='azureuser') c.argument('dns_name_prefix', options_list=['--dns-name-prefix', '-p']) c.argument('generate_ssh_keys', action='store_true', validator=validate_create_parameters) @@ -166,10 +168,12 @@ c.argument('install_location', default=_get_default_install_location('kubectl')) with self.argument_context('aks install-connector') as c: + c.argument('aci_resource_group', help='The resource group to create the ACI container groups') c.argument('chart_url', default=aci_connector_chart_url, help='URL to the chart') - c.argument('client_secret', - help='Client secret to use with the service principal for making calls to Azure APIs') + c.argument('client_secret', help='Client secret to use with the service principal for making calls to Azure APIs') c.argument('connector_name', help='The name for the ACI Connector', validator=validate_connector_name) + c.argument('image_tag', help='The image tag of the virtual kubelet') + c.argument('location', help='The location to create the ACI container groups') c.argument('os_type', get_enum_type(aci_connector_os_type), help='The OS type of the connector') c.argument('service_principal', help='Service principal for making calls into Azure APIs. If not set, auto generate a new service principal of Contributor role, and save it locally for reusing') @@ -180,6 +184,19 @@ help='Mention if you want to drain/uncordon your aci-connector to move your applications') c.argument('os_type', get_enum_type(aci_connector_os_type), help='The OS type of the connector') + with self.argument_context('aks upgrade') as c: + c.argument('kubernetes_version', completer=get_k8s_upgrades_completion_list) + + with self.argument_context('aks upgrade-connector') as c: + c.argument('aci_resource_group') + c.argument('chart_url', default=aci_connector_chart_url) + c.argument('client_secret') + c.argument('connector_name', validator=validate_connector_name) + c.argument('image_tag') + c.argument('location') + c.argument('os_type', get_enum_type(aci_connector_os_type)) + c.argument('service_principal') + def _get_default_install_location(exe_name): system = platform.system() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-acs-2.0.25/azure/cli/command_modules/acs/_validators.py new/azure-cli-acs-2.0.31/azure/cli/command_modules/acs/_validators.py --- old/azure-cli-acs-2.0.25/azure/cli/command_modules/acs/_validators.py 2018-01-26 17:12:23.000000000 +0100 +++ new/azure-cli-acs-2.0.31/azure/cli/command_modules/acs/_validators.py 2018-04-06 19:33:13.000000000 +0200 @@ -59,7 +59,7 @@ def validate_list_of_integers(string): - # extract comma separated list of integers + # extract comma-separated list of integers return list(map(int, string.split(','))) @@ -71,14 +71,16 @@ def validate_k8s_version(namespace): - """Validates a string as a possible Kubernetes version.""" - k8s_release_regex = re.compile(r'^[v|V]?(\d+\.\d+\.\d+.*)$') - found = k8s_release_regex.findall(namespace.kubernetes_version) - if found: - namespace.kubernetes_version = found[0] - else: - raise CLIError('--kubernetes-version should be the full version number, ' - 'such as "1.7.7" or "1.8.1"') + """Validates a string as a possible Kubernetes version. An empty string is also valid, which tells the server + to use its default version.""" + if namespace.kubernetes_version: + k8s_release_regex = re.compile(r'^[v|V]?(\d+\.\d+\.\d+.*)$') + found = k8s_release_regex.findall(namespace.kubernetes_version) + if found: + namespace.kubernetes_version = found[0] + else: + raise CLIError('--kubernetes-version should be the full version number, ' + 'such as "1.7.12" or "1.8.7"') def validate_k8s_client_version(namespace): @@ -89,7 +91,7 @@ namespace.client_version = found[0] else: raise CLIError('--client-version should be the full version number ' - '(such as "1.7.7" or "1.8.1") or "latest"') + '(such as "1.7.12" or "1.8.7") or "latest"') def validate_linux_host_name(namespace): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-acs-2.0.25/azure/cli/command_modules/acs/commands.py new/azure-cli-acs-2.0.31/azure/cli/command_modules/acs/commands.py --- old/azure-cli-acs-2.0.25/azure/cli/command_modules/acs/commands.py 2018-01-26 17:12:23.000000000 +0100 +++ new/azure-cli-acs-2.0.31/azure/cli/command_modules/acs/commands.py 2018-04-06 19:33:13.000000000 +0200 @@ -9,9 +9,10 @@ from ._client_factory import cf_container_services from ._client_factory import cf_managed_clusters -from ._format import aks_get_versions_table_format from ._format import aks_list_table_format from ._format import aks_show_table_format +from ._format import aks_upgrades_table_format +from ._format import aks_versions_table_format def load_command_table(self, _): @@ -31,7 +32,7 @@ # ACS base commands with self.command_group('acs', container_services_sdk, client_factory=cf_container_services) as g: g.custom_command('browse', 'acs_browse') - g.custom_command('create', 'acs_create', no_wait_param='no_wait', + g.custom_command('create', 'acs_create', supports_no_wait=True, table_transformer=deployment_validate_table_format) g.command('delete', 'delete', confirmation=True) g.custom_command('list', 'list_container_services') @@ -54,17 +55,21 @@ # AKS commands with self.command_group('aks', managed_clusters_sdk, client_factory=cf_managed_clusters) as g: g.custom_command('browse', 'aks_browse') - g.custom_command('create', 'aks_create', no_wait_param='no_wait') - g.command('delete', 'delete', no_wait_param='raw', confirmation=True) + g.custom_command('create', 'aks_create', supports_no_wait=True) + g.command('delete', 'delete', supports_no_wait=True, confirmation=True) g.custom_command('get-credentials', 'aks_get_credentials') - g.command('get-versions', 'get_upgrade_profile', table_transformer=aks_get_versions_table_format) + g.command('get-upgrades', 'get_upgrade_profile', table_transformer=aks_upgrades_table_format) g.custom_command('install-cli', 'k8s_install_cli', client_factory=None) g.custom_command('install-connector', 'k8s_install_connector') g.custom_command('list', 'aks_list', table_transformer=aks_list_table_format) g.custom_command('remove-connector', 'k8s_uninstall_connector') - g.custom_command('scale', 'aks_scale', no_wait_param='no_wait') + g.custom_command('scale', 'aks_scale', supports_no_wait=True) g.custom_command('show', 'aks_show', table_transformer=aks_show_table_format) - g.custom_command('upgrade', 'aks_upgrade', no_wait_param='no_wait', + g.custom_command('upgrade', 'aks_upgrade', supports_no_wait=True, confirmation='Kubernetes may be unavailable during cluster upgrades.\n' + 'Are you sure you want to perform this operation?') + g.custom_command('upgrade-connector', 'k8s_upgrade_connector') g.generic_wait_command('wait') + + with self.command_group('aks', container_services_sdk, client_factory=cf_container_services) as g: + g.custom_command('get-versions', 'aks_get_versions', table_transformer=aks_versions_table_format) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-acs-2.0.25/azure/cli/command_modules/acs/custom.py new/azure-cli-acs-2.0.31/azure/cli/command_modules/acs/custom.py --- old/azure-cli-acs-2.0.25/azure/cli/command_modules/acs/custom.py 2018-01-26 17:12:23.000000000 +0100 +++ new/azure-cli-acs-2.0.31/azure/cli/command_modules/acs/custom.py 2018-04-06 19:33:13.000000000 +0200 @@ -24,15 +24,14 @@ import time import uuid import webbrowser -import yaml -import dateutil.parser -from dateutil.relativedelta import relativedelta from six.moves.urllib.request import urlopen # pylint: disable=import-error from six.moves.urllib.error import URLError # pylint: disable=import-error +import yaml +import dateutil.parser +from dateutil.relativedelta import relativedelta from knack.log import get_logger from knack.util import CLIError - from msrestazure.azure_exceptions import CloudError from azure.cli.command_modules.acs import acs_client, proxy @@ -41,14 +40,13 @@ from azure.cli.core._profile import Profile from azure.cli.core.commands.client_factory import get_mgmt_service_client from azure.cli.core.keys import is_valid_ssh_rsa_public_key -from azure.cli.core.profiles import ResourceType -from azure.cli.core.util import shell_safe_json_parse, truncate_text +from azure.cli.core.util import in_cloud_console, shell_safe_json_parse, truncate_text, sdk_no_wait from azure.graphrbac.models import (ApplicationCreateParameters, PasswordCredential, KeyCredential, ServicePrincipalCreateParameters, GetObjectsParameters) -from azure.mgmt.authorization.models import RoleAssignmentProperties +from azure.mgmt.authorization.models import RoleAssignmentCreateParameters from azure.mgmt.containerservice.models import ContainerServiceAgentPoolProfile from azure.mgmt.containerservice.models import ContainerServiceLinuxProfile from azure.mgmt.containerservice.models import ContainerServiceOrchestratorTypes @@ -58,9 +56,10 @@ from azure.mgmt.containerservice.models import ContainerServiceStorageProfileTypes from azure.mgmt.containerservice.models import ManagedCluster +from ._client_factory import cf_container_services +from ._client_factory import cf_resource_groups from ._client_factory import get_auth_management_client from ._client_factory import get_graph_rbac_management_client -from ._client_factory import cf_container_services logger = get_logger(__name__) @@ -84,10 +83,6 @@ return None -def _resource_client_factory(cli_ctx): - return get_mgmt_service_client(cli_ctx, ResourceType.MGMT_RESOURCE_RESOURCES) - - def wait_then_open(url): """ Waits for a bit then opens a URL. Useful for waiting for a proxy to come up, and then open the URL. @@ -238,8 +233,11 @@ def _ssl_context(): - if sys.version_info < (3, 4): - return ssl.SSLContext(ssl.PROTOCOL_TLSv1) + if sys.version_info < (3, 4) or (in_cloud_console() and platform.system() == 'Windows'): + try: + return ssl.SSLContext(ssl.PROTOCOL_TLS) # added in python 2.7.13 and 3.6 + except AttributeError: + return ssl.SSLContext(ssl.PROTOCOL_TLSv1) return ssl.create_default_context() @@ -311,66 +309,98 @@ os.stat(install_location).st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) except IOError as ex: raise CLIError('Connection error while attempting to download client ({})'.format(ex)) + logger.warning('Please ensure that %s is in your search PATH, so the `%s` command can be found.', + os.path.dirname(install_location), os.path.basename(install_location)) def k8s_install_connector(cmd, client, name, resource_group_name, connector_name, location=None, service_principal=None, client_secret=None, - chart_url=None, os_type='Linux'): + chart_url=None, os_type='Linux', image_tag=None, aci_resource_group=None): + _k8s_install_or_upgrade_connector("install", cmd, client, name, resource_group_name, connector_name, + location, service_principal, client_secret, chart_url, os_type, + image_tag, aci_resource_group) + + +def k8s_upgrade_connector(cmd, client, name, resource_group_name, connector_name, + location=None, service_principal=None, client_secret=None, + chart_url=None, os_type='Linux', image_tag=None, aci_resource_group=None): + _k8s_install_or_upgrade_connector("upgrade", cmd, client, name, resource_group_name, connector_name, + location, service_principal, client_secret, chart_url, os_type, + image_tag, aci_resource_group) + + +def _k8s_install_or_upgrade_connector(helm_cmd, cmd, client, name, resource_group_name, connector_name, + location, service_principal, client_secret, chart_url, os_type, + image_tag, aci_resource_group): from subprocess import PIPE, Popen helm_not_installed = 'Helm not detected, please verify if it is installed.' node_prefix = 'virtual-kubelet-' + connector_name.lower() url_chart = chart_url + if image_tag is None: + image_tag = 'latest' # Check if Helm is installed locally try: Popen(["helm"], stdout=PIPE, stderr=PIPE) except OSError: raise CLIError(helm_not_installed) + # If SPN is specified, the secret should also be specified + if service_principal is not None and client_secret is None: + raise CLIError('--client-secret must be specified when --service-principal is specified') # Validate if the RG exists - groups = _resource_client_factory(cmd.cli_ctx).resource_groups + groups = cf_resource_groups(cmd.cli_ctx) + if aci_resource_group is None: + aci_resource_group = resource_group_name # Just do the get, we don't need the result, it will error out if the group doesn't exist. - rgkaci = groups.get(resource_group_name) + rgkaci = groups.get(aci_resource_group) # Auto assign the location if location is None: location = rgkaci.location # pylint:disable=no-member + # Validate the location upon the ACI avaiable regions + _validate_aci_location(location) # Get the credentials from a AKS instance _, browse_path = tempfile.mkstemp() aks_get_credentials(cmd, client, resource_group_name, name, admin=False, path=browse_path) subscription_id = _get_subscription_id(cmd.cli_ctx) - dns_name_prefix = _get_default_dns_prefix(connector_name, resource_group_name, subscription_id) - # Ensure that the SPN exists - principal_obj = _ensure_aks_service_principal(cmd.cli_ctx, service_principal, client_secret, subscription_id, - dns_name_prefix, location, connector_name) - client_secret = principal_obj.get('client_secret') - service_principal = principal_obj.get('service_principal') # Get the TenantID profile = Profile(cli_ctx=cmd.cli_ctx) _, _, tenant_id = profile.get_login_credentials() # Check if we want the linux connector if os_type.lower() in ['linux', 'both']: - _helm_install_aci_connector(url_chart, connector_name, service_principal, client_secret, - subscription_id, tenant_id, rgkaci.name, location, - node_prefix + '-linux', 'Linux') + _helm_install_or_upgrade_aci_connector(helm_cmd, image_tag, url_chart, connector_name, service_principal, + client_secret, subscription_id, tenant_id, rgkaci.name, location, + node_prefix + '-linux', 'Linux') # Check if we want the windows connector if os_type.lower() in ['windows', 'both']: - _helm_install_aci_connector(url_chart, connector_name, service_principal, client_secret, - subscription_id, tenant_id, rgkaci.name, location, - node_prefix + '-win', 'Windows') + _helm_install_or_upgrade_aci_connector(helm_cmd, image_tag, url_chart, connector_name, service_principal, + client_secret, subscription_id, tenant_id, rgkaci.name, location, + node_prefix + '-win', 'Windows') -def _helm_install_aci_connector(url_chart, connector_name, service_principal, client_secret, - subscription_id, tenant_id, aci_resource_group, aci_region, - node_name, os_type): - image_tag = 'latest' +def _helm_install_or_upgrade_aci_connector(helm_cmd, image_tag, url_chart, connector_name, service_principal, + client_secret, subscription_id, tenant_id, aci_resource_group, + aci_region, node_name, os_type): node_taint = 'azure.com/aci' helm_release_name = connector_name.lower() + "-" + os_type.lower() logger.warning("Deploying the ACI connector for '%s' using Helm", os_type) try: - subprocess.call(["helm", "install", url_chart, "--name", helm_release_name, "--set", "env.azureClientId=" + - service_principal + ",env.azureClientKey=" + client_secret + ",env.azureSubscriptionId=" + - subscription_id + ",env.azureTenantId=" + tenant_id + ",env.aciResourceGroup=" + - aci_resource_group + ",env.aciRegion=" + aci_region + ",image.tag=" + image_tag + - ",env.nodeName=" + node_name + ",env.nodeTaint=" + node_taint + ",env.nodeOsType=" + os_type]) + values = ('env.nodeName={},env.nodeTaint={},env.nodeOsType={},image.tag={},' + + 'env.aciResourceGroup={},env.aciRegion={}').format( + node_name, node_taint, os_type, image_tag, aci_resource_group, aci_region) + + if service_principal: + values += ",env.azureClientId=" + service_principal + if client_secret: + values += ",env.azureClientKey=" + client_secret + if subscription_id: + values += ",env.azureSubscriptionId=" + subscription_id + if tenant_id: + values += ",env.azureTenantId=" + tenant_id + + if helm_cmd == "install": + subprocess.call(["helm", "install", url_chart, "--name", helm_release_name, "--set", values]) + elif helm_cmd == "upgrade": + subprocess.call(["helm", "upgrade", helm_release_name, url_chart, "--set", values]) except subprocess.CalledProcessError as err: raise CLIError('Could not deploy the ACI connector Chart: {}'.format(err)) @@ -409,7 +439,7 @@ try: drain_node = subprocess.check_output( - ['kubectl', 'drain', node_name, '--force'], + ['kubectl', 'drain', node_name, '--force', '--delete-local-data'], universal_newlines=True) if not drain_node: @@ -419,6 +449,14 @@ raise CLIError('Could not find the node, make sure you' + ' are using the correct --os-type option: {}'.format(err)) + try: + subprocess.check_output( + ['kubectl', 'delete', 'node', node_name], + universal_newlines=True) + except subprocess.CalledProcessError as err: + raise CLIError('Could not delete the node, make sure you' + + ' are using the correct --os-type option: {}'.format(err)) + logger.warning("Undeploying the '%s' using Helm", helm_release_name) try: subprocess.call(['helm', 'del', helm_release_name, '--purge']) @@ -431,7 +469,11 @@ hook = cli_ctx.get_progress_controller(True) hook.add(messsage='Creating service principal', value=0, total_val=1.0) logger.info('Creating service principal') - result = create_application(rbac_client.applications, name, url, [url], password=client_secret) + # always create application with 5 years expiration + start_date = datetime.datetime.utcnow() + end_date = start_date + relativedelta(years=5) + result = create_application(rbac_client.applications, name, url, [url], password=client_secret, + start_date=start_date, end_date=end_date) service_principal = result.app_id # pylint: disable=no-member for x in range(0, 10): hook.add(message='Creating service principal', value=0.1 * x, total_val=1.0) @@ -708,7 +750,7 @@ if not dns_name_prefix: dns_name_prefix = _get_default_dns_prefix(name, resource_group_name, subscription_id) - groups = _resource_client_factory(cmd.cli_ctx).resource_groups + groups = cf_resource_groups(cmd.cli_ctx) # Just do the get, we don't need the result, it will error out if the group doesn't exist. rg = groups.get(resource_group_name) if location is None: @@ -864,7 +906,7 @@ logger.info(json.dumps(template, indent=2)) logger.info('==== END TEMPLATE ====') return smc.validate(resource_group_name, deployment_name, properties) - return smc.create_or_update(resource_group_name, deployment_name, properties, raw=no_wait) + return sdk_no_wait(no_wait, smc.create_or_update, resource_group_name, deployment_name, properties) def k8s_get_credentials(cmd, client, name, resource_group_name, @@ -924,28 +966,22 @@ existing[key].append(i) -def merge_kubernetes_configurations(existing_file, addition_file): +def load_kubernetes_configuration(filename): try: - with open(existing_file) as stream: - existing = yaml.safe_load(stream) + with open(filename) as stream: + return yaml.safe_load(stream) except (IOError, OSError) as ex: if getattr(ex, 'errno', 0) == errno.ENOENT: - raise CLIError('{} does not exist'.format(existing_file)) + raise CLIError('{} does not exist'.format(filename)) else: raise - except yaml.parser.ParserError as ex: - raise CLIError('Error parsing {} ({})'.format(existing_file, str(ex))) + except (yaml.parser.ParserError, UnicodeDecodeError) as ex: + raise CLIError('Error parsing {} ({})'.format(filename, str(ex))) - try: - with open(addition_file) as stream: - addition = yaml.safe_load(stream) - except (IOError, OSError) as ex: - if getattr(ex, 'errno', 0) == errno.ENOENT: - raise CLIError('{} does not exist'.format(existing_file)) - else: - raise - except yaml.parser.ParserError as ex: - raise CLIError('Error parsing {} ({})'.format(addition_file, str(ex))) + +def merge_kubernetes_configurations(existing_file, addition_file): + existing = load_kubernetes_configuration(existing_file) + addition = load_kubernetes_configuration(addition_file) if addition is None: raise CLIError('failed to load additional configuration from {}'.format(addition_file)) @@ -959,7 +995,7 @@ existing['current-context'] = addition['current-context'] with open(existing_file, 'w+') as stream: - yaml.dump(existing, stream, default_flow_style=True) + yaml.dump(existing, stream, default_flow_style=False) current_context = addition.get('current-context', 'UNKNOWN') msg = 'Merged "{}" as current context in {}'.format(current_context, existing_file) @@ -1110,9 +1146,11 @@ password_creds = None key_creds = None if password: - password_creds = [PasswordCredential(start_date, end_date, str(uuid.uuid4()), password)] + password_creds = [PasswordCredential(start_date=start_date, end_date=end_date, + key_id=str(uuid.uuid4()), value=password)] elif key_value: - key_creds = [KeyCredential(start_date, end_date, key_value, str(uuid.uuid4()), key_usage, key_type)] + key_creds = [KeyCredential(start_date=start_date, end_date=end_date, value=key_value, + key_id=str(uuid.uuid4()), usage=key_usage, type=key_type)] return (password_creds, key_creds) @@ -1151,10 +1189,10 @@ role_id = _resolve_role_id(role, scope, definitions_client) object_id = _resolve_object_id(cli_ctx, assignee) if resolve_assignee else assignee - properties = RoleAssignmentProperties(role_id, object_id) + parameters = RoleAssignmentCreateParameters(role_definition_id=role_id, principal_id=object_id) assignment_name = uuid.uuid4() custom_headers = None - return assignments_client.create(scope, assignment_name, properties, custom_headers=custom_headers) + return assignments_client.create(scope, assignment_name, parameters, custom_headers=custom_headers) def _build_role_scope(resource_group_name, scope, subscription_id): @@ -1220,6 +1258,9 @@ def aks_browse(cmd, client, resource_group_name, name, disable_browser=False): + if in_cloud_console(): + raise CLIError('This command requires a web browser, which is not supported in Azure Cloud Shell.') + if not which('kubectl'): raise CLIError('Can not find kubectl executable in PATH') @@ -1236,8 +1277,8 @@ except subprocess.CalledProcessError as err: raise CLIError('Could not find dashboard pod: {}'.format(err)) if dashboard_pod: - # remove the "pods/" prefix from the name - dashboard_pod = str(dashboard_pod)[5:].strip() + # remove any "pods/" or "pod/" prefix from the name + dashboard_pod = str(dashboard_pod).split('/')[-1].strip() else: raise CLIError("Couldn't find the Kubernetes dashboard pod.") # launch kubectl port-forward locally to access the remote dashboard @@ -1253,8 +1294,8 @@ dns_name_prefix=None, location=None, admin_username="azureuser", - kubernetes_version="1.7.7", - node_vm_size="Standard_D1_v2", + kubernetes_version='', + node_vm_size="Standard_DS1_v2", node_osdisk_size=0, node_count=3, service_principal=None, client_secret=None, @@ -1272,7 +1313,7 @@ if not dns_name_prefix: dns_name_prefix = _get_default_dns_prefix(name, resource_group_name, subscription_id) - groups = _resource_client_factory(cmd.cli_ctx).resource_groups + groups = cf_resource_groups(cmd.cli_ctx) # Just do the get, we don't need the result, it will error out if the group doesn't exist. rg = groups.get(resource_group_name) if location is None: @@ -1314,8 +1355,8 @@ retry_exception = Exception(None) for _ in range(0, max_retry): try: - return client.create_or_update( - resource_group_name=resource_group_name, resource_name=name, parameters=mc, raw=no_wait) + return sdk_no_wait(no_wait, client.create_or_update, + resource_group_name=resource_group_name, resource_name=name, parameters=mc) except CloudError as ex: retry_exception = ex if 'not found in Active Directory tenant' in ex.message: @@ -1325,6 +1366,10 @@ raise retry_exception +def aks_get_versions(cmd, client, location): + return client.list_orchestrators(location, resource_type='managedClusters') + + def aks_get_credentials(cmd, client, resource_group_name, name, admin=False, path=os.path.join(os.path.expanduser('~'), '.kube', 'config')): access_profile = client.get_access_profiles( @@ -1359,7 +1404,7 @@ # null out the service principal because otherwise validation complains instance.service_principal_profile = None - return client.create_or_update(resource_group_name, name, instance, raw=no_wait) + return sdk_no_wait(no_wait, client.create_or_update, resource_group_name, name, instance) def aks_upgrade(cmd, client, resource_group_name, name, kubernetes_version, no_wait=False, **kwargs): # pylint: disable=unused-argument @@ -1369,7 +1414,7 @@ # null out the service principal because otherwise validation complains instance.service_principal_profile = None - return client.create_or_update(resource_group_name, name, instance, raw=no_wait) + return sdk_no_wait(no_wait, client.create_or_update, resource_group_name, name, instance) def _ensure_aks_service_principal(cli_ctx, @@ -1506,3 +1551,19 @@ if getattr(managed_cluster.service_principal_profile, attr, None) is None: delattr(managed_cluster.service_principal_profile, attr) return managed_clusters + + +def _validate_aci_location(location): + """ + Validate the Azure Container Instance location + """ + aci_locations = [ + "westus", + "eastus", + "westeurope", + "southeastasia", + ] + norm_location = location.replace(" ", "").lower() + if norm_location not in aci_locations: + raise CLIError('Azure Container Instance is not available at location "{}".'.format(location) + + ' The available locations are "{}"'.format(','.join(aci_locations))) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-acs-2.0.25/azure_cli_acs.egg-info/PKG-INFO new/azure-cli-acs-2.0.31/azure_cli_acs.egg-info/PKG-INFO --- old/azure-cli-acs-2.0.25/azure_cli_acs.egg-info/PKG-INFO 2018-01-26 17:12:47.000000000 +0100 +++ new/azure-cli-acs-2.0.31/azure_cli_acs.egg-info/PKG-INFO 2018-04-06 19:33:32.000000000 +0200 @@ -1,11 +1,12 @@ Metadata-Version: 1.1 Name: azure-cli-acs -Version: 2.0.25 +Version: 2.0.31 Summary: Microsoft Azure Command-Line Tools ACS Command Module Home-page: https://github.com/Azure/azure-cli Author: Microsoft Corporation Author-email: azpy...@microsoft.com License: MIT +Description-Content-Type: UNKNOWN Description: Microsoft Azure CLI 'acs' Command Module ======================================== @@ -18,6 +19,45 @@ Release History =============== + 2.0.31 + ++++++ + + * `sdist` is now compatible with wheel 0.31.0 + + 2.0.30 + ++++++ + * Minor fixes + * aks created spn will be valid for 5 years + + 2.0.29 + ++++++ + * fix a certificate verification error for `az aks install-cli` in Cloud Shell / PS + + 2.0.28 + ++++++ + * Support Autorest 3.0 based SDKs + * warn the user that `az aks browse` won't work in Azure Cloud Shell + * add `aks upgrade-connector` command to upgrade an existing connector + * `kubectl` config files are more readable block-style YAML + + 2.0.27 + ++++++ + * use the virtual-kubelet-for-aks helm chart for `aks install-connector` by default + * fix the service principal insufficient permission to create ACI container group issue + * add --aci-container-group, --location, --image-tag optional parameters for `aks install-connector` + * remove deprecation notice from `aks get-versions` + + 2.0.26 + ++++++ + * rename `aks get-versions` to `aks get-upgrades` in the interest of accuracy + * reimplement `aks get-versions` to show Kubernetes versions available for `aks create` + * `aks create` defaults to letting the server choose the version of Kubernetes + * update help messages referring to the service principal generated by AKS + * `aks create` VM node size default changed from "Standard_D1_v2" to "Standard_DS1_v2" + * improve reliability when locating the dashboard pod for `az aks browse` + * `aks get-credentials` handles UnicodeDecodeError when loading Kubernetes configuration files + * add a message to `az aks install-cli` to help get `kubectl.exe` in the search PATH + 2.0.25 ++++++ * clarify `--disable-browser` argument diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-acs-2.0.25/azure_cli_acs.egg-info/requires.txt new/azure-cli-acs-2.0.31/azure_cli_acs.egg-info/requires.txt --- old/azure-cli-acs-2.0.25/azure_cli_acs.egg-info/requires.txt 2018-01-26 17:12:47.000000000 +0100 +++ new/azure-cli-acs-2.0.31/azure_cli_acs.egg-info/requires.txt 2018-04-06 19:33:32.000000000 +0200 @@ -1,7 +1,7 @@ -azure-mgmt-authorization==0.30.0 -azure-mgmt-compute==3.1.0rc3 -azure-mgmt-containerservice==3.0.0 -azure-graphrbac==0.31.0 +azure-mgmt-authorization==0.40.0 +azure-mgmt-compute==4.0.0rc1 +azure-mgmt-containerservice==3.0.1 +azure-graphrbac==0.40.0 azure-cli-core paramiko pyyaml diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-cli-acs-2.0.25/setup.py new/azure-cli-acs-2.0.31/setup.py --- old/azure-cli-acs-2.0.25/setup.py 2018-01-26 17:12:23.000000000 +0100 +++ new/azure-cli-acs-2.0.31/setup.py 2018-04-06 19:33:13.000000000 +0200 @@ -14,7 +14,7 @@ logger.warn("Wheel is not available, disabling bdist_wheel hook") cmdclass = {} -VERSION = "2.0.25" +VERSION = "2.0.31" CLASSIFIERS = [ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', @@ -30,10 +30,10 @@ ] DEPENDENCIES = [ - 'azure-mgmt-authorization==0.30.0', - 'azure-mgmt-compute==3.1.0rc3', - 'azure-mgmt-containerservice==3.0.0', - 'azure-graphrbac==0.31.0', + 'azure-mgmt-authorization==0.40.0', + 'azure-mgmt-compute==4.0.0rc1', + 'azure-mgmt-containerservice==3.0.1', + 'azure-graphrbac==0.40.0', 'azure-cli-core', 'paramiko', 'pyyaml',