From 981a1dd95c18d40d56d6cca6ee0e983247e7cdbc Mon Sep 17 00:00:00 2001 From: "Lixia (Sylvia) Lei" Date: Tue, 18 Feb 2020 23:03:13 +0800 Subject: [PATCH 01/10] Add command 'az acr helm install-cli' --- .../azure/cli/command_modules/acr/_help.py | 9 +++ .../azure/cli/command_modules/acr/commands.py | 1 + .../azure/cli/command_modules/acr/helm.py | 59 +++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/src/azure-cli/azure/cli/command_modules/acr/_help.py b/src/azure-cli/azure/cli/command_modules/acr/_help.py index 5acb90af949..59b09b6e267 100644 --- a/src/azure-cli/azure/cli/command_modules/acr/_help.py +++ b/src/azure-cli/azure/cli/command_modules/acr/_help.py @@ -226,6 +226,15 @@ az acr helm show -n MyRegistry mychart --version 0.3.2 """ +helps['acr helm install-cli'] = """ +type: command +short-summary: Download and install Helm command-line tool. +examples: + - name: Install helm CLI + text: > + az acr helm install-cli +""" + helps['acr import'] = """ type: command short-summary: Imports an image to an Azure Container Registry from another Container Registry. Import removes the need to docker pull, docker tag, docker push. diff --git a/src/azure-cli/azure/cli/command_modules/acr/commands.py b/src/azure-cli/azure/cli/command_modules/acr/commands.py index 4920bbef4fd..a6760dfd5d6 100644 --- a/src/azure-cli/azure/cli/command_modules/acr/commands.py +++ b/src/azure-cli/azure/cli/command_modules/acr/commands.py @@ -267,6 +267,7 @@ def load_command_table(self, _): # pylint: disable=too-many-statements g.command('delete', 'acr_helm_delete') g.command('push', 'acr_helm_push') g.command('repo add', 'acr_helm_repo_add') + g.command('install-cli', 'acr_helm_install_cli') with self.command_group('acr network-rule', acr_network_rule_util) as g: g.command('list', 'acr_network_rule_list') diff --git a/src/azure-cli/azure/cli/command_modules/acr/helm.py b/src/azure-cli/azure/cli/command_modules/acr/helm.py index dcdd58891ab..fc945dfde3d 100644 --- a/src/azure-cli/azure/cli/command_modules/acr/helm.py +++ b/src/azure-cli/azure/cli/command_modules/acr/helm.py @@ -3,10 +3,19 @@ # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- +import json +import platform +import sys +import ssl + from knack.util import CLIError from knack.log import get_logger +from six.moves.urllib.request import urlopen # pylint: disable=import-error +from six.moves.urllib.error import URLError # pylint: disable=import-error +from azure.cli.core.util import in_cloud_console from ._utils import user_confirmation + from ._docker_utils import ( get_access_credentials, request_data_from_registry, @@ -175,6 +184,46 @@ def acr_helm_repo_add(cmd, p.wait() +def acr_helm_install_cli(cmd, version=None, architecture='amd64'): + if version is None: + releases_url = "https://api.github.com/repos/helm/helm/releases/latest" + try: + with urlopen(releases_url) as response: + result = response.read().decode('UTF-8') + values = json.loads(result) + version = values['tag_name'] + except URLError as e: + raise CLIError('{}'.format(e)) + + # filename="helm-$version-$system-$architecture.$extention" + filename_template = 'helm-{}-{}-{}.{}' + filename = '' + + system = platform.system() + if system == 'Windows': + filename = filename_template.format(version, 'windows', architecture, 'zip') + elif system == 'Linux': + filename = filename_template.format(version, 'linux', architecture, 'tar.gz') + elif system == 'Darwin': + filename = filename_template.format(version, 'darwin', architecture, 'tar.gz') + else: + raise CLIError('This system is not supported yet') + + try: + _install_helm_cli(filename) + except IOError as e: + raise CLIError('Error while installing {}: {}'.format(filename, e)) + + + +def _install_helm_cli(filename): + source_url = 'https://get.helm.sh/{}'.format(filename) + with urlopen(source_url) as response: + # Open for writing in binary mode + with open(filename, "wb") as f: + f.write(response.read()) + + def get_helm_command(is_diagnostics_context=False): from ._errors import HELM_COMMAND_ERROR helm_command = 'helm' @@ -230,3 +279,13 @@ def _get_chart_package_name(chart, version, prov=False): return '{}.prov'.format(chart_package_name) return chart_package_name + + +def _ssl_context(): + 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() \ No newline at end of file From 2670fa9b61570a6bcef5584dd4d3e0bab994016e Mon Sep 17 00:00:00 2001 From: "Lixia (Sylvia) Lei" Date: Sat, 22 Feb 2020 00:58:12 +0800 Subject: [PATCH 02/10] [ACR] `az acr helm install-cli`: Implement download and unzip --- .../azure/cli/command_modules/acr/_params.py | 22 +++ .../azure/cli/command_modules/acr/commands.py | 2 +- .../azure/cli/command_modules/acr/helm.py | 164 +++++++++++++----- 3 files changed, 141 insertions(+), 47 deletions(-) diff --git a/src/azure-cli/azure/cli/command_modules/acr/_params.py b/src/azure-cli/azure/cli/command_modules/acr/_params.py index 7b49e6e21ec..5073d5cd8b7 100644 --- a/src/azure-cli/azure/cli/command_modules/acr/_params.py +++ b/src/azure-cli/azure/cli/command_modules/acr/_params.py @@ -5,6 +5,9 @@ # pylint: disable=line-too-long import argparse +import os.path +import platform + from argcomplete.completers import FilesCompleter from knack.arguments import CLIArgumentType @@ -258,6 +261,10 @@ def load_arguments(self, _): # pylint: disable=too-many-statements c.positional('chart_package', help="The helm chart package.", completer=FilesCompleter()) c.argument('force', help='Overwrite the existing chart package.', action='store_true') + with self.argument_context('acr helm install-cli') as c: + c.argument('version', options_list=['--version', '-v'], help='The target helm CLI version. Helm v3 is currently not supported. ') + c.argument('install_location', options_list=['--install-location', '-l'], help='Path at which to install helm CLI.', default=_get_helm_default_install_location()) + with self.argument_context('acr network-rule') as c: c.argument('subnet', help='Name or ID of subnet. If name is supplied, `--vnet-name` must be supplied.') c.argument('vnet_name', help='Name of a virtual network.') @@ -307,3 +314,18 @@ def load_arguments(self, _): # pylint: disable=too-many-statements with self.argument_context('acr token credential delete') as c: c.argument('password1', options_list=['--password1'], help='Flag indicating if first password should be deleted', action='store_true', required=False) c.argument('password2', options_list=['--password2'], help='Flag indicating if second password should be deleted.', action='store_true', required=False) + + +def _get_helm_default_install_location(): + exe_name = 'helm' + system = platform.system() + if system == 'Windows': + home_dir = os.environ.get('USERPROFILE') + if not home_dir: + return None + install_location = os.path.join(home_dir, r'.azure-{0}\{0}.exe'.format(exe_name)) + elif system in ('Linux', 'Darwin'): + install_location = '/usr/local/bin/{}'.format(exe_name) + else: + install_location = None + return install_location \ No newline at end of file diff --git a/src/azure-cli/azure/cli/command_modules/acr/commands.py b/src/azure-cli/azure/cli/command_modules/acr/commands.py index a6760dfd5d6..a41d3e878cc 100644 --- a/src/azure-cli/azure/cli/command_modules/acr/commands.py +++ b/src/azure-cli/azure/cli/command_modules/acr/commands.py @@ -267,7 +267,7 @@ def load_command_table(self, _): # pylint: disable=too-many-statements g.command('delete', 'acr_helm_delete') g.command('push', 'acr_helm_push') g.command('repo add', 'acr_helm_repo_add') - g.command('install-cli', 'acr_helm_install_cli') + g.command('install-cli', 'acr_helm_install_cli', is_preview=True) with self.command_group('acr network-rule', acr_network_rule_util) as g: g.command('list', 'acr_network_rule_list') diff --git a/src/azure-cli/azure/cli/command_modules/acr/helm.py b/src/azure-cli/azure/cli/command_modules/acr/helm.py index fc945dfde3d..841b9f77b15 100644 --- a/src/azure-cli/azure/cli/command_modules/acr/helm.py +++ b/src/azure-cli/azure/cli/command_modules/acr/helm.py @@ -3,10 +3,8 @@ # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- -import json +import os import platform -import sys -import ssl from knack.util import CLIError from knack.log import get_logger @@ -184,44 +182,128 @@ def acr_helm_repo_add(cmd, p.wait() -def acr_helm_install_cli(cmd, version=None, architecture='amd64'): - if version is None: - releases_url = "https://api.github.com/repos/helm/helm/releases/latest" - try: - with urlopen(releases_url) as response: - result = response.read().decode('UTF-8') - values = json.loads(result) - version = values['tag_name'] - except URLError as e: - raise CLIError('{}'.format(e)) - - # filename="helm-$version-$system-$architecture.$extention" - filename_template = 'helm-{}-{}-{}.{}' - filename = '' - - system = platform.system() - if system == 'Windows': - filename = filename_template.format(version, 'windows', architecture, 'zip') - elif system == 'Linux': - filename = filename_template.format(version, 'linux', architecture, 'tar.gz') - elif system == 'Darwin': - filename = filename_template.format(version, 'darwin', architecture, 'tar.gz') - else: - raise CLIError('This system is not supported yet') +def acr_helm_install_cli(cmd, version='2.16.3', install_location=None): + """Install Helm command-line interface.""" - try: - _install_helm_cli(filename) - except IOError as e: - raise CLIError('Error while installing {}: {}'.format(filename, e)) + if version >= '3': + raise CLIError('Version not support.') + version = "v%s" % version + # source_url = 'https://get.helm.sh/{}' + source_url = 'http://localhost:8000/{}' + package_template = 'helm-{}-{}-{}.{}' + package = '' + download_path = '' # path to downloaded file + if not install_location: + raise CLIError('Invalid install location.') -def _install_helm_cli(filename): - source_url = 'https://get.helm.sh/{}'.format(filename) - with urlopen(source_url) as response: + # ensure installation directory exists + install_dir, cli = os.path.dirname(install_location), os.path.basename(install_location) + if not os.path.exists(install_dir): + os.makedirs(install_dir) + + arch = _get_machine_architecture() + if not arch: + raise CLIError("This machine type is not supported by Helm CLI.") + + import tempfile + with tempfile.TemporaryDirectory() as tmp_dir: + system = platform.system().lower() + try: + if system == 'windows': + package = package_template.format(version, system, arch, 'zip') + download_path = os.path.join(tmp_dir, package) + # Download + _urlretrieve(source_url.format(package), download_path) + + # Decomporess + import zipfile + with zipfile.ZipFile(download_path, 'r') as zipObj: + zipObj.extractall(tmp_dir) + elif system in ('linux', 'darwin'): + package = package_template.format(version, system, arch, 'tar.gz') + download_path = os.path.join(tmp_dir, package) + # Download + _urlretrieve(source_url.format(package), download_path) + + # Decomporess + import tarfile + with tarfile.open(download_path, 'r') as tarObj: + tarObj.extractall(tmp_dir) + else: + raise CLIError('This system is not supported yet') + + # Move files from temporary location to specified location + import shutil + sub_dir = '{}-{}'.format(system, arch) + for f in os.scandir(os.path.join(tmp_dir, sub_dir)): + if os.path.splitext(f.name)[0] == 'helm': + shutil.move(f.path, install_location) + else: + shutil.move(f.path, install_dir) + # TODO: ask user to agree or check license + + import stat + os.chmod(install_location, os.stat(install_location).st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) + except IOError as e: + raise CLIError('Error while installing {}: {}'.format(package, e)) + + # Remind user to add to path + if system == 'windows': # be verbose, as the install_location likely not in Windows's search PATHs + env_paths = os.environ['PATH'].split(';') + found = next((x for x in env_paths if x.lower().rstrip('\\') == install_dir.lower()), None) + if not found: + # pylint: disable=logging-format-interpolation + logger.warning('Please add "{0}" to your search PATH so the `{1}` can be found. 2 options: \n' + ' 1. Run "set PATH=%PATH%;{0}" or "$env:path += \'{0}\'" for PowerShell. ' + 'This is good for the current command session.\n' + ' 2. Update system PATH environment variable by following ' + '"Control Panel->System->Advanced->Environment Variables", and re-open the command window. ' + 'You only need to do it once'.format(install_dir, cli)) + else: + logger.warning('Please ensure that %s is in your search PATH, so the `%s` command can be found.', + install_dir, cli) + + # TODO: user to read license + + +def _get_machine_architecture(): +# ARCH=$(uname -m) +# case $ARCH in +# armv5*) ARCH="armv5";; +# armv6*) ARCH="armv6";; +# armv7*) ARCH="arm";; +# aarch64) ARCH="arm64";; +# x86) ARCH="386";; +# x86_64) ARCH="amd64";; +# i686) ARCH="386";; +# i386) ARCH="386";; + arch = { + 'armv5*': 'armv5', + 'armv6*': 'armv6', + 'armv7*': 'arm', + 'aarch64': 'arm64', + 'x86': '386', + 'x86_64': 'amd64', + 'i686': '386', + 'i386': '386', + 'AMD64': 'amd64', + 'ppc64le': 'ppc64le', + 's390x': 's390x' + } + machine = platform.machine() + return arch[machine] if machine in arch else None + + +def _urlretrieve(url, path): + logger.debug('Query %s', url) + with urlopen(url) as response: + logger.debug('Start downloading from %s to %s', url, path) # Open for writing in binary mode - with open(filename, "wb") as f: + with open(path, "wb") as f: f.write(response.read()) + logger.debug('Successfully downloaded from %s to %s', url, path) def get_helm_command(is_diagnostics_context=False): @@ -278,14 +360,4 @@ def _get_chart_package_name(chart, version, prov=False): if prov: return '{}.prov'.format(chart_package_name) - return chart_package_name - - -def _ssl_context(): - 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() \ No newline at end of file + return chart_package_name \ No newline at end of file From e4a65a3fd8f49a27fe0fc87804696369c211860e Mon Sep 17 00:00:00 2001 From: "Lixia (Sylvia) Lei" Date: Sun, 23 Feb 2020 18:40:15 +0800 Subject: [PATCH 03/10] [ACR] `az acr helm install-cli`: Add license confirmation --- .../azure/cli/command_modules/acr/_params.py | 2 +- .../azure/cli/command_modules/acr/helm.py | 190 ++++++++++-------- 2 files changed, 106 insertions(+), 86 deletions(-) diff --git a/src/azure-cli/azure/cli/command_modules/acr/_params.py b/src/azure-cli/azure/cli/command_modules/acr/_params.py index 5073d5cd8b7..7e0a2ceac72 100644 --- a/src/azure-cli/azure/cli/command_modules/acr/_params.py +++ b/src/azure-cli/azure/cli/command_modules/acr/_params.py @@ -262,7 +262,7 @@ def load_arguments(self, _): # pylint: disable=too-many-statements c.argument('force', help='Overwrite the existing chart package.', action='store_true') with self.argument_context('acr helm install-cli') as c: - c.argument('version', options_list=['--version', '-v'], help='The target helm CLI version. Helm v3 is currently not supported. ') + c.argument('client_version', options_list=['--client_version', '-v'], help='The target helm CLI version. Helm v3 is currently not supported. ') c.argument('install_location', options_list=['--install-location', '-l'], help='Path at which to install helm CLI.', default=_get_helm_default_install_location()) with self.argument_context('acr network-rule') as c: diff --git a/src/azure-cli/azure/cli/command_modules/acr/helm.py b/src/azure-cli/azure/cli/command_modules/acr/helm.py index 841b9f77b15..8de03853ace 100644 --- a/src/azure-cli/azure/cli/command_modules/acr/helm.py +++ b/src/azure-cli/azure/cli/command_modules/acr/helm.py @@ -52,7 +52,7 @@ def acr_helm_list(cmd, def acr_helm_show(cmd, registry_name, chart, - version=None, + client_version=None, repository='repo', resource_group_name=None, # pylint: disable=unused-argument tenant_suffix=None, @@ -70,7 +70,7 @@ def acr_helm_show(cmd, return request_data_from_registry( http_method='get', login_server=login_server, - path=_get_charts_path(repository, chart, version), + path=_get_charts_path(repository, chart, client_version), username=username, password=password)[0] @@ -78,7 +78,7 @@ def acr_helm_show(cmd, def acr_helm_delete(cmd, registry_name, chart, - version=None, + client_version=None, repository='repo', resource_group_name=None, # pylint: disable=unused-argument tenant_suffix=None, @@ -86,9 +86,9 @@ def acr_helm_delete(cmd, password=None, prov=False, yes=False): - if version: + if client_version: message = "This operation will delete the chart package '{}'".format( - _get_chart_package_name(chart, version, prov)) + _get_chart_package_name(chart, client_version, prov)) else: message = "This operation will delete all versions of the chart '{}'".format(chart) user_confirmation("{}.\nAre you sure you want to continue?".format(message), yes) @@ -105,7 +105,7 @@ def acr_helm_delete(cmd, return request_data_from_registry( http_method='delete', login_server=login_server, - path=_get_blobs_path(repository, chart, version, prov) if version else _get_charts_path(repository, chart), + path=_get_blobs_path(repository, chart, client_version, prov) if client_version else _get_charts_path(repository, chart), username=username, password=password)[0] @@ -182,18 +182,11 @@ def acr_helm_repo_add(cmd, p.wait() -def acr_helm_install_cli(cmd, version='2.16.3', install_location=None): +def acr_helm_install_cli(cmd, client_version='2.16.3', install_location=None, yes=False): """Install Helm command-line interface.""" - if version >= '3': - raise CLIError('Version not support.') - - version = "v%s" % version - # source_url = 'https://get.helm.sh/{}' - source_url = 'http://localhost:8000/{}' - package_template = 'helm-{}-{}-{}.{}' - package = '' - download_path = '' # path to downloaded file + if client_version >= '3': + raise CLIError('Helm v3 is not supported yet.') if not install_location: raise CLIError('Invalid install location.') @@ -203,46 +196,54 @@ def acr_helm_install_cli(cmd, version='2.16.3', install_location=None): if not os.path.exists(install_dir): os.makedirs(install_dir) - arch = _get_machine_architecture() - if not arch: - raise CLIError("This machine type is not supported by Helm CLI.") + client_version = "v%s" % client_version + # source_url = 'https://get.helm.sh/{}' + source_url = 'http://localhost:8000/{}' + package, folder = _get_helm_package_name(client_version) + download_path = '' # path to downloaded file + + if not package: + raise CLIError("Current system is not supported.") + # TODO: sha verification + + system = platform.system() import tempfile with tempfile.TemporaryDirectory() as tmp_dir: - system = platform.system().lower() - try: - if system == 'windows': - package = package_template.format(version, system, arch, 'zip') - download_path = os.path.join(tmp_dir, package) - # Download - _urlretrieve(source_url.format(package), download_path) + # Download + download_path = os.path.join(tmp_dir, package) + _urlretrieve(source_url.format(package), download_path) - # Decomporess + # Unzip + try: + if system == 'Windows': import zipfile with zipfile.ZipFile(download_path, 'r') as zipObj: zipObj.extractall(tmp_dir) - elif system in ('linux', 'darwin'): - package = package_template.format(version, system, arch, 'tar.gz') - download_path = os.path.join(tmp_dir, package) - # Download - _urlretrieve(source_url.format(package), download_path) - - # Decomporess + elif system in ('Linux', 'Darwin'): import tarfile with tarfile.open(download_path, 'r') as tarObj: tarObj.extractall(tmp_dir) else: - raise CLIError('This system is not supported yet') + raise CLIError('This system is not supported yet.') + + sub_dir = os.path.join(tmp_dir, folder) + # Show license + if not yes: + with open(os.path.join(sub_dir, 'LICENSE')) as f: + text = f.read() + logger.warning(text) + user_confirmation('Before proceeding with the installation, ' + 'please confirm that you have read and agreed the above license.') # Move files from temporary location to specified location import shutil - sub_dir = '{}-{}'.format(system, arch) - for f in os.scandir(os.path.join(tmp_dir, sub_dir)): + for f in os.scandir(sub_dir): + # Rename helm to specified name if os.path.splitext(f.name)[0] == 'helm': shutil.move(f.path, install_location) else: shutil.move(f.path, install_dir) - # TODO: ask user to agree or check license import stat os.chmod(install_location, os.stat(install_location).st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) @@ -250,7 +251,7 @@ def acr_helm_install_cli(cmd, version='2.16.3', install_location=None): raise CLIError('Error while installing {}: {}'.format(package, e)) # Remind user to add to path - if system == 'windows': # be verbose, as the install_location likely not in Windows's search PATHs + if system == 'Windows': # be verbose, as the install_location likely not in Windows's search PATHs env_paths = os.environ['PATH'].split(';') found = next((x for x in env_paths if x.lower().rstrip('\\') == install_dir.lower()), None) if not found: @@ -265,45 +266,18 @@ def acr_helm_install_cli(cmd, version='2.16.3', install_location=None): logger.warning('Please ensure that %s is in your search PATH, so the `%s` command can be found.', install_dir, cli) - # TODO: user to read license - - -def _get_machine_architecture(): -# ARCH=$(uname -m) -# case $ARCH in -# armv5*) ARCH="armv5";; -# armv6*) ARCH="armv6";; -# armv7*) ARCH="arm";; -# aarch64) ARCH="arm64";; -# x86) ARCH="386";; -# x86_64) ARCH="amd64";; -# i686) ARCH="386";; -# i386) ARCH="386";; - arch = { - 'armv5*': 'armv5', - 'armv6*': 'armv6', - 'armv7*': 'arm', - 'aarch64': 'arm64', - 'x86': '386', - 'x86_64': 'amd64', - 'i686': '386', - 'i386': '386', - 'AMD64': 'amd64', - 'ppc64le': 'ppc64le', - 's390x': 's390x' - } - machine = platform.machine() - return arch[machine] if machine in arch else None +def _ssl_context(): + import sys + import ssl -def _urlretrieve(url, path): - logger.debug('Query %s', url) - with urlopen(url) as response: - logger.debug('Start downloading from %s to %s', url, path) - # Open for writing in binary mode - with open(path, "wb") as f: - f.write(response.read()) - logger.debug('Successfully downloaded from %s to %s', url, path) + 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() def get_helm_command(is_diagnostics_context=False): @@ -335,9 +309,9 @@ def get_helm_command(is_diagnostics_context=False): return helm_command, None -def _get_charts_path(repository, chart=None, version=None): - if chart and version: - return '/helm/v1/{}/_charts/{}/{}'.format(repository, chart, version) +def _get_charts_path(repository, chart=None, client_version=None): + if chart and client_version: + return '/helm/v1/{}/_charts/{}/{}'.format(repository, chart, client_version) if chart: return '/helm/v1/{}/_charts/{}'.format(repository, chart) @@ -345,19 +319,65 @@ def _get_charts_path(repository, chart=None, version=None): return '/helm/v1/{}/_charts'.format(repository) -def _get_blobs_path(repository, chart, version=None, prov=False): +def _get_blobs_path(repository, chart, client_version=None, prov=False): path = '/helm/v1/{}/_blobs'.format(repository) - if version: - return '{}/{}'.format(path, _get_chart_package_name(chart, version, prov)) + if client_version: + return '{}/{}'.format(path, _get_chart_package_name(chart, client_version, prov)) return '{}/{}'.format(path, chart) -def _get_chart_package_name(chart, version, prov=False): - chart_package_name = '{}-{}.tgz'.format(chart, version) +def _get_chart_package_name(chart, client_version, prov=False): + chart_package_name = '{}-{}.tgz'.format(chart, client_version) if prov: return '{}.prov'.format(chart_package_name) - return chart_package_name \ No newline at end of file + return chart_package_name + + +def _get_helm_package_name(client_version): + package_template = 'helm-{}-{}-{}.{}' + folder_template = '{}-{}' + package = '' + folder = '' + + archs = { + 'armv5*': 'armv5', + 'armv6*': 'armv6', + 'armv7*': 'arm', + 'aarch64': 'arm64', + 'x86': '386', + 'x86_64': 'amd64', + 'i686': '386', + 'i386': '386', + 'AMD64': 'amd64', + 'ppc64le': 'ppc64le', + 's390x': 's390x' + } + machine = platform.machine() + if machine not in archs: + return None, None + arch = archs[machine] + + system = platform.system().lower() + if system == 'windows': + package = package_template.format(client_version, system, arch, 'zip') + elif system in ('linux', 'darwin'): + package = package_template.format(client_version, system, arch, 'tar.gz') + else: + return None, None + + folder = folder_template.format(system, arch) + return package, folder + + +def _urlretrieve(url, path): + logger.warning('Requesting %s, it may take a long time...', url) + with urlopen(url, context=_ssl_context()) as response: + logger.debug('Start downloading from %s to %s', url, path) + # Open for writing in binary mode + with open(path, "wb") as f: + f.write(response.read()) + logger.debug('Successfully downloaded from %s to %s', url, path) From bed084011997e36e18dd18bbf0be6f86b0024052 Mon Sep 17 00:00:00 2001 From: "Lixia (Sylvia) Lei" Date: Sun, 23 Feb 2020 23:04:00 +0800 Subject: [PATCH 04/10] [ACR] `az acr helm install-cli`: optimize code structure --- .../azure/cli/command_modules/acr/helm.py | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/azure-cli/azure/cli/command_modules/acr/helm.py b/src/azure-cli/azure/cli/command_modules/acr/helm.py index 8de03853ace..8362cfbcedc 100644 --- a/src/azure-cli/azure/cli/command_modules/acr/helm.py +++ b/src/azure-cli/azure/cli/command_modules/acr/helm.py @@ -183,7 +183,7 @@ def acr_helm_repo_add(cmd, def acr_helm_install_cli(cmd, client_version='2.16.3', install_location=None, yes=False): - """Install Helm command-line interface.""" + """Install Helm command-line tool.""" if client_version >= '3': raise CLIError('Helm v3 is not supported yet.') @@ -193,6 +193,9 @@ def acr_helm_install_cli(cmd, client_version='2.16.3', install_location=None, ye # ensure installation directory exists install_dir, cli = os.path.dirname(install_location), os.path.basename(install_location) + if not cli: + raise CLIError("{} is a directory. Please specify a complete file path.".format(install_location)) + if not os.path.exists(install_dir): os.makedirs(install_dir) @@ -203,19 +206,17 @@ def acr_helm_install_cli(cmd, client_version='2.16.3', install_location=None, ye download_path = '' # path to downloaded file if not package: - raise CLIError("Current system is not supported.") - - # TODO: sha verification + raise CLIError('The current system is not supported.') system = platform.system() import tempfile with tempfile.TemporaryDirectory() as tmp_dir: - # Download - download_path = os.path.join(tmp_dir, package) - _urlretrieve(source_url.format(package), download_path) - - # Unzip try: + # Download + download_path = os.path.join(tmp_dir, package) + _urlretrieve(source_url.format(package), download_path) + + # Unzip if system == 'Windows': import zipfile with zipfile.ZipFile(download_path, 'r') as zipObj: @@ -225,10 +226,10 @@ def acr_helm_install_cli(cmd, client_version='2.16.3', install_location=None, ye with tarfile.open(download_path, 'r') as tarObj: tarObj.extractall(tmp_dir) else: - raise CLIError('This system is not supported yet.') + raise CLIError('The current system is not supported.') sub_dir = os.path.join(tmp_dir, folder) - # Show license + # Ask user to check license if not yes: with open(os.path.join(sub_dir, 'LICENSE')) as f: text = f.read() @@ -241,15 +242,17 @@ def acr_helm_install_cli(cmd, client_version='2.16.3', install_location=None, ye for f in os.scandir(sub_dir): # Rename helm to specified name if os.path.splitext(f.name)[0] == 'helm': + # TODO: cli is empty shutil.move(f.path, install_location) else: - shutil.move(f.path, install_dir) + shutil.move(f.path, os.path.join(install_dir, f.name)) import stat os.chmod(install_location, os.stat(install_location).st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) except IOError as e: - raise CLIError('Error while installing {}: {}'.format(package, e)) + raise CLIError('Error while installing {} to {}: {}'.format(cli, install_dir, e)) + logger.warning('Successfully installed %s to %s.', cli, install_dir) # Remind user to add to path if system == 'Windows': # be verbose, as the install_location likely not in Windows's search PATHs env_paths = os.environ['PATH'].split(';') From fa992e288a21572183b26f98e50a71807528d8f1 Mon Sep 17 00:00:00 2001 From: "Lixia (Sylvia) Lei" Date: Mon, 24 Feb 2020 12:17:47 +0800 Subject: [PATCH 05/10] [ACR] `az acr helm install-cli`: Modify help --- .../azure/cli/command_modules/acr/_help.py | 11 ++++++- .../azure/cli/command_modules/acr/_params.py | 5 +-- .../azure/cli/command_modules/acr/helm.py | 33 +++++++++---------- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/azure-cli/azure/cli/command_modules/acr/_help.py b/src/azure-cli/azure/cli/command_modules/acr/_help.py index 59b09b6e267..c8022071135 100644 --- a/src/azure-cli/azure/cli/command_modules/acr/_help.py +++ b/src/azure-cli/azure/cli/command_modules/acr/_help.py @@ -230,9 +230,18 @@ type: command short-summary: Download and install Helm command-line tool. examples: - - name: Install helm CLI + - name: Install the default version of Helm CLI to the default location text: > az acr helm install-cli + - name: Install a specified version of Helm CLI to the default location + text: > + az acr helm install-cli --client-version 2.15.2 + - name: Install the default version of Helm CLI to a specified location + text: > + az acr helm install-cli --install-location folder\subFolder\\filename + - name: Install a specified version of Helm CLI to a specified location + text: > + az acr helm install-cli --client-version 2.15.2 --install-location folder\subFolder\\filename """ helps['acr import'] = """ diff --git a/src/azure-cli/azure/cli/command_modules/acr/_params.py b/src/azure-cli/azure/cli/command_modules/acr/_params.py index 7e0a2ceac72..e571107a4cd 100644 --- a/src/azure-cli/azure/cli/command_modules/acr/_params.py +++ b/src/azure-cli/azure/cli/command_modules/acr/_params.py @@ -262,8 +262,9 @@ def load_arguments(self, _): # pylint: disable=too-many-statements c.argument('force', help='Overwrite the existing chart package.', action='store_true') with self.argument_context('acr helm install-cli') as c: - c.argument('client_version', options_list=['--client_version', '-v'], help='The target helm CLI version. Helm v3 is currently not supported. ') - c.argument('install_location', options_list=['--install-location', '-l'], help='Path at which to install helm CLI.', default=_get_helm_default_install_location()) + c.argument('client_version', options_list=['--client-version'], help='The target helm CLI version. (Helm v3 is currently not supported) ') + c.argument('install_location', options_list=['--install-location'], help='Path at which to install helm CLI.', default=_get_helm_default_install_location()) + c.argument('yes', help='Agree to the license of Helm and do not prompt for confirmation.') with self.argument_context('acr network-rule') as c: c.argument('subnet', help='Name or ID of subnet. If name is supplied, `--vnet-name` must be supplied.') diff --git a/src/azure-cli/azure/cli/command_modules/acr/helm.py b/src/azure-cli/azure/cli/command_modules/acr/helm.py index 8362cfbcedc..9b8fd888d9c 100644 --- a/src/azure-cli/azure/cli/command_modules/acr/helm.py +++ b/src/azure-cli/azure/cli/command_modules/acr/helm.py @@ -191,11 +191,11 @@ def acr_helm_install_cli(cmd, client_version='2.16.3', install_location=None, ye if not install_location: raise CLIError('Invalid install location.') - # ensure installation directory exists install_dir, cli = os.path.dirname(install_location), os.path.basename(install_location) if not cli: raise CLIError("{} is a directory. Please specify a complete file path.".format(install_location)) + # Ensure installation directory exists if not os.path.exists(install_dir): os.makedirs(install_dir) @@ -203,20 +203,21 @@ def acr_helm_install_cli(cmd, client_version='2.16.3', install_location=None, ye # source_url = 'https://get.helm.sh/{}' source_url = 'http://localhost:8000/{}' package, folder = _get_helm_package_name(client_version) - download_path = '' # path to downloaded file + download_path = '' # downloaded package path if not package: raise CLIError('The current system is not supported.') system = platform.system() - import tempfile - with tempfile.TemporaryDirectory() as tmp_dir: - try: + try: + import tempfile + with tempfile.TemporaryDirectory() as tmp_dir: # Download download_path = os.path.join(tmp_dir, package) _urlretrieve(source_url.format(package), download_path) # Unzip + logger.debug('Extracting %s to %s.', download_path, tmp_dir) if system == 'Windows': import zipfile with zipfile.ZipFile(download_path, 'r') as zipObj: @@ -235,22 +236,20 @@ def acr_helm_install_cli(cmd, client_version='2.16.3', install_location=None, ye text = f.read() logger.warning(text) user_confirmation('Before proceeding with the installation, ' - 'please confirm that you have read and agreed the above license.') + 'please confirm that you have read and agreed the above license.') # Move files from temporary location to specified location import shutil for f in os.scandir(sub_dir): # Rename helm to specified name - if os.path.splitext(f.name)[0] == 'helm': - # TODO: cli is empty - shutil.move(f.path, install_location) - else: - shutil.move(f.path, os.path.join(install_dir, f.name)) - - import stat - os.chmod(install_location, os.stat(install_location).st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) - except IOError as e: - raise CLIError('Error while installing {} to {}: {}'.format(cli, install_dir, e)) + target_path = install_location if os.path.splitext(f.name)[0] == 'helm' \ + else os.path.join(install_dir, f.name) + logger.debug('Moving %s to %s', f.path, target_path) + shutil.move(f.path, target_path) + import stat + os.chmod(install_location, os.stat(install_location).st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) + except IOError as e: + raise CLIError('Error while installing {} to {}: {}'.format(cli, install_dir, e)) logger.warning('Successfully installed %s to %s.', cli, install_dir) # Remind user to add to path @@ -377,7 +376,7 @@ def _get_helm_package_name(client_version): def _urlretrieve(url, path): - logger.warning('Requesting %s, it may take a long time...', url) + logger.warning('Downloading client from %s, it may take a long time...', url) with urlopen(url, context=_ssl_context()) as response: logger.debug('Start downloading from %s to %s', url, path) # Open for writing in binary mode From a042b7af59f04d97beec2e57af2eebc99757db9f Mon Sep 17 00:00:00 2001 From: "Lixia (Sylvia) Lei" Date: Mon, 24 Feb 2020 18:22:05 +0800 Subject: [PATCH 06/10] [ACR] `az acr helm install-cli`: Optimize code structure and modify help --- .../azure/cli/command_modules/acr/_help.py | 6 +- .../azure/cli/command_modules/acr/_params.py | 8 +- .../azure/cli/command_modules/acr/helm.py | 78 ++++++++++--------- 3 files changed, 47 insertions(+), 45 deletions(-) diff --git a/src/azure-cli/azure/cli/command_modules/acr/_help.py b/src/azure-cli/azure/cli/command_modules/acr/_help.py index c8022071135..9cbdf5f6d5b 100644 --- a/src/azure-cli/azure/cli/command_modules/acr/_help.py +++ b/src/azure-cli/azure/cli/command_modules/acr/_help.py @@ -235,13 +235,13 @@ az acr helm install-cli - name: Install a specified version of Helm CLI to the default location text: > - az acr helm install-cli --client-version 2.15.2 + az acr helm install-cli --client-version x.x.x - name: Install the default version of Helm CLI to a specified location text: > - az acr helm install-cli --install-location folder\subFolder\\filename + az acr helm install-cli --install-location folder/subFolder/filename - name: Install a specified version of Helm CLI to a specified location text: > - az acr helm install-cli --client-version 2.15.2 --install-location folder\subFolder\\filename + az acr helm install-cli --client-version x.x.x --install-location folder/subFolder/filename """ helps['acr import'] = """ diff --git a/src/azure-cli/azure/cli/command_modules/acr/_params.py b/src/azure-cli/azure/cli/command_modules/acr/_params.py index e571107a4cd..25610b76f31 100644 --- a/src/azure-cli/azure/cli/command_modules/acr/_params.py +++ b/src/azure-cli/azure/cli/command_modules/acr/_params.py @@ -262,9 +262,9 @@ def load_arguments(self, _): # pylint: disable=too-many-statements c.argument('force', help='Overwrite the existing chart package.', action='store_true') with self.argument_context('acr helm install-cli') as c: - c.argument('client_version', options_list=['--client-version'], help='The target helm CLI version. (Helm v3 is currently not supported) ') - c.argument('install_location', options_list=['--install-location'], help='Path at which to install helm CLI.', default=_get_helm_default_install_location()) - c.argument('yes', help='Agree to the license of Helm and do not prompt for confirmation.') + c.argument('client_version', options_list=['--client-version'], help='The target Helm CLI version. (Helm v3 is currently not supported) ') + c.argument('install_location', options_list=['--install-location'], help='File path at which to install Helm CLI.', default=_get_helm_default_install_location()) + c.argument('yes', help='Agree to the license of Helm, and do not prompt for confirmation.') with self.argument_context('acr network-rule') as c: c.argument('subnet', help='Name or ID of subnet. If name is supplied, `--vnet-name` must be supplied.') @@ -329,4 +329,4 @@ def _get_helm_default_install_location(): install_location = '/usr/local/bin/{}'.format(exe_name) else: install_location = None - return install_location \ No newline at end of file + return install_location diff --git a/src/azure-cli/azure/cli/command_modules/acr/helm.py b/src/azure-cli/azure/cli/command_modules/acr/helm.py index 9b8fd888d9c..d2bee04fa5c 100644 --- a/src/azure-cli/azure/cli/command_modules/acr/helm.py +++ b/src/azure-cli/azure/cli/command_modules/acr/helm.py @@ -9,7 +9,6 @@ from knack.util import CLIError from knack.log import get_logger from six.moves.urllib.request import urlopen # pylint: disable=import-error -from six.moves.urllib.error import URLError # pylint: disable=import-error from azure.cli.core.util import in_cloud_console from ._utils import user_confirmation @@ -182,13 +181,13 @@ def acr_helm_repo_add(cmd, p.wait() -def acr_helm_install_cli(cmd, client_version='2.16.3', install_location=None, yes=False): +def acr_helm_install_cli(client_version='2.16.3', install_location=None, yes=False): """Install Helm command-line tool.""" if client_version >= '3': raise CLIError('Helm v3 is not supported yet.') - if not install_location: + if not install_location or install_location.isspace(): raise CLIError('Invalid install location.') install_dir, cli = os.path.dirname(install_location), os.path.basename(install_location) @@ -200,34 +199,19 @@ def acr_helm_install_cli(cmd, client_version='2.16.3', install_location=None, ye os.makedirs(install_dir) client_version = "v%s" % client_version - # source_url = 'https://get.helm.sh/{}' - source_url = 'http://localhost:8000/{}' + source_url = 'https://get.helm.sh/{}' package, folder = _get_helm_package_name(client_version) - download_path = '' # downloaded package path + download_path = '' if not package: raise CLIError('The current system is not supported.') - system = platform.system() try: import tempfile with tempfile.TemporaryDirectory() as tmp_dir: - # Download download_path = os.path.join(tmp_dir, package) _urlretrieve(source_url.format(package), download_path) - - # Unzip - logger.debug('Extracting %s to %s.', download_path, tmp_dir) - if system == 'Windows': - import zipfile - with zipfile.ZipFile(download_path, 'r') as zipObj: - zipObj.extractall(tmp_dir) - elif system in ('Linux', 'Darwin'): - import tarfile - with tarfile.open(download_path, 'r') as tarObj: - tarObj.extractall(tmp_dir) - else: - raise CLIError('The current system is not supported.') + _unzip(download_path, tmp_dir) sub_dir = os.path.join(tmp_dir, folder) # Ask user to check license @@ -236,23 +220,26 @@ def acr_helm_install_cli(cmd, client_version='2.16.3', install_location=None, ye text = f.read() logger.warning(text) user_confirmation('Before proceeding with the installation, ' - 'please confirm that you have read and agreed the above license.') + 'please confirm that you have read and agreed the above license.') # Move files from temporary location to specified location import shutil + import stat for f in os.scandir(sub_dir): # Rename helm to specified name target_path = install_location if os.path.splitext(f.name)[0] == 'helm' \ - else os.path.join(install_dir, f.name) + else os.path.join(install_dir, f.name) logger.debug('Moving %s to %s', f.path, target_path) shutil.move(f.path, target_path) - import stat - os.chmod(install_location, os.stat(install_location).st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) + + if os.path.splitext(f.name)[0] in ('helm', 'tiller'): + os.chmod(target_path, os.stat(target_path).st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) except IOError as e: raise CLIError('Error while installing {} to {}: {}'.format(cli, install_dir, e)) logger.warning('Successfully installed %s to %s.', cli, install_dir) # Remind user to add to path + system = platform.system() if system == 'Windows': # be verbose, as the install_location likely not in Windows's search PATHs env_paths = os.environ['PATH'].split(';') found = next((x for x in env_paths if x.lower().rstrip('\\') == install_dir.lower()), None) @@ -269,19 +256,6 @@ def acr_helm_install_cli(cmd, client_version='2.16.3', install_location=None, ye install_dir, cli) -def _ssl_context(): - import sys - import ssl - - 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() - - def get_helm_command(is_diagnostics_context=False): from ._errors import HELM_COMMAND_ERROR helm_command = 'helm' @@ -375,6 +349,19 @@ def _get_helm_package_name(client_version): return package, folder +def _ssl_context(): + import sys + import ssl + + 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() + + def _urlretrieve(url, path): logger.warning('Downloading client from %s, it may take a long time...', url) with urlopen(url, context=_ssl_context()) as response: @@ -383,3 +370,18 @@ def _urlretrieve(url, path): with open(path, "wb") as f: f.write(response.read()) logger.debug('Successfully downloaded from %s to %s', url, path) + + +def _unzip(src, dest): + logger.debug('Extracting %s to %s.', src, dest) + system = platform.system() + if system == 'Windows': + import zipfile + with zipfile.ZipFile(src, 'r') as zipObj: + zipObj.extractall(dest) + elif system in ('Linux', 'Darwin'): + import tarfile + with tarfile.open(src, 'r') as tarObj: + tarObj.extractall(dest) + else: + raise CLIError('The current system is not supported.') From 26e0a48048ec358fef7ceb3c85e188e4ecd573fa Mon Sep 17 00:00:00 2001 From: "Lixia (Sylvia) Lei" Date: Mon, 24 Feb 2020 18:29:37 +0800 Subject: [PATCH 07/10] [ACR] Fix mistakes --- .../azure/cli/command_modules/acr/helm.py | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/azure-cli/azure/cli/command_modules/acr/helm.py b/src/azure-cli/azure/cli/command_modules/acr/helm.py index d2bee04fa5c..965993f422e 100644 --- a/src/azure-cli/azure/cli/command_modules/acr/helm.py +++ b/src/azure-cli/azure/cli/command_modules/acr/helm.py @@ -51,7 +51,7 @@ def acr_helm_list(cmd, def acr_helm_show(cmd, registry_name, chart, - client_version=None, + version=None, repository='repo', resource_group_name=None, # pylint: disable=unused-argument tenant_suffix=None, @@ -69,7 +69,7 @@ def acr_helm_show(cmd, return request_data_from_registry( http_method='get', login_server=login_server, - path=_get_charts_path(repository, chart, client_version), + path=_get_charts_path(repository, chart, version), username=username, password=password)[0] @@ -77,7 +77,7 @@ def acr_helm_show(cmd, def acr_helm_delete(cmd, registry_name, chart, - client_version=None, + version=None, repository='repo', resource_group_name=None, # pylint: disable=unused-argument tenant_suffix=None, @@ -85,9 +85,9 @@ def acr_helm_delete(cmd, password=None, prov=False, yes=False): - if client_version: + if version: message = "This operation will delete the chart package '{}'".format( - _get_chart_package_name(chart, client_version, prov)) + _get_chart_package_name(chart, version, prov)) else: message = "This operation will delete all versions of the chart '{}'".format(chart) user_confirmation("{}.\nAre you sure you want to continue?".format(message), yes) @@ -104,7 +104,7 @@ def acr_helm_delete(cmd, return request_data_from_registry( http_method='delete', login_server=login_server, - path=_get_blobs_path(repository, chart, client_version, prov) if client_version else _get_charts_path(repository, chart), + path=_get_blobs_path(repository, chart, version, prov) if version else _get_charts_path(repository, chart), username=username, password=password)[0] @@ -285,9 +285,9 @@ def get_helm_command(is_diagnostics_context=False): return helm_command, None -def _get_charts_path(repository, chart=None, client_version=None): - if chart and client_version: - return '/helm/v1/{}/_charts/{}/{}'.format(repository, chart, client_version) +def _get_charts_path(repository, chart=None, version=None): + if chart and version: + return '/helm/v1/{}/_charts/{}/{}'.format(repository, chart, version) if chart: return '/helm/v1/{}/_charts/{}'.format(repository, chart) @@ -295,17 +295,17 @@ def _get_charts_path(repository, chart=None, client_version=None): return '/helm/v1/{}/_charts'.format(repository) -def _get_blobs_path(repository, chart, client_version=None, prov=False): +def _get_blobs_path(repository, chart, version=None, prov=False): path = '/helm/v1/{}/_blobs'.format(repository) - if client_version: - return '{}/{}'.format(path, _get_chart_package_name(chart, client_version, prov)) + if version: + return '{}/{}'.format(path, _get_chart_package_name(chart, version, prov)) return '{}/{}'.format(path, chart) -def _get_chart_package_name(chart, client_version, prov=False): - chart_package_name = '{}-{}.tgz'.format(chart, client_version) +def _get_chart_package_name(chart, version, prov=False): + chart_package_name = '{}-{}.tgz'.format(chart, version) if prov: return '{}.prov'.format(chart_package_name) From 7bf50ff3a8d6515d368f73a265619388f929f883 Mon Sep 17 00:00:00 2001 From: "Lixia (Sylvia) Lei" Date: Mon, 24 Feb 2020 22:22:22 +0800 Subject: [PATCH 08/10] [ACR] Modify help --- src/azure-cli/azure/cli/command_modules/acr/_help.py | 4 ++-- .../azure/cli/command_modules/acr/_params.py | 4 ++-- src/azure-cli/azure/cli/command_modules/acr/helm.py | 12 +++++++----- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/azure-cli/azure/cli/command_modules/acr/_help.py b/src/azure-cli/azure/cli/command_modules/acr/_help.py index 9cbdf5f6d5b..4f694fecd73 100644 --- a/src/azure-cli/azure/cli/command_modules/acr/_help.py +++ b/src/azure-cli/azure/cli/command_modules/acr/_help.py @@ -238,10 +238,10 @@ az acr helm install-cli --client-version x.x.x - name: Install the default version of Helm CLI to a specified location text: > - az acr helm install-cli --install-location folder/subFolder/filename + az acr helm install-cli --install-location /folder/filename - name: Install a specified version of Helm CLI to a specified location text: > - az acr helm install-cli --client-version x.x.x --install-location folder/subFolder/filename + az acr helm install-cli --client-version x.x.x --install-location /folder/filename """ helps['acr import'] = """ diff --git a/src/azure-cli/azure/cli/command_modules/acr/_params.py b/src/azure-cli/azure/cli/command_modules/acr/_params.py index 25610b76f31..2a87ce8c624 100644 --- a/src/azure-cli/azure/cli/command_modules/acr/_params.py +++ b/src/azure-cli/azure/cli/command_modules/acr/_params.py @@ -262,8 +262,8 @@ def load_arguments(self, _): # pylint: disable=too-many-statements c.argument('force', help='Overwrite the existing chart package.', action='store_true') with self.argument_context('acr helm install-cli') as c: - c.argument('client_version', options_list=['--client-version'], help='The target Helm CLI version. (Helm v3 is currently not supported) ') - c.argument('install_location', options_list=['--install-location'], help='File path at which to install Helm CLI.', default=_get_helm_default_install_location()) + c.argument('client_version', help='The target Helm CLI version. (Helm v3 is currently not supported) ') + c.argument('install_location', help='File path at which to install Helm CLI.', default=_get_helm_default_install_location()) c.argument('yes', help='Agree to the license of Helm, and do not prompt for confirmation.') with self.argument_context('acr network-rule') as c: diff --git a/src/azure-cli/azure/cli/command_modules/acr/helm.py b/src/azure-cli/azure/cli/command_modules/acr/helm.py index 965993f422e..0e0fbfc0c2b 100644 --- a/src/azure-cli/azure/cli/command_modules/acr/helm.py +++ b/src/azure-cli/azure/cli/command_modules/acr/helm.py @@ -5,12 +5,13 @@ import os import platform +from six.moves.urllib.request import urlopen # pylint: disable=import-error from knack.util import CLIError from knack.log import get_logger -from six.moves.urllib.request import urlopen # pylint: disable=import-error from azure.cli.core.util import in_cloud_console + from ._utils import user_confirmation from ._docker_utils import ( @@ -204,7 +205,7 @@ def acr_helm_install_cli(client_version='2.16.3', install_location=None, yes=Fal download_path = '' if not package: - raise CLIError('The current system is not supported.') + raise CLIError('No prebuilt binary for current system.') try: import tempfile @@ -319,10 +320,11 @@ def _get_helm_package_name(client_version): package = '' folder = '' + # Reference: https://github.com/helm/helm/blob/master/scripts/get archs = { - 'armv5*': 'armv5', - 'armv6*': 'armv6', - 'armv7*': 'arm', + 'armv5': 'armv5', + 'armv6': 'armv6', + 'armv7': 'arm', 'aarch64': 'arm64', 'x86': '386', 'x86_64': 'amd64', From 990a55fc7d31897253ee52377e680a49698c7227 Mon Sep 17 00:00:00 2001 From: "Lixia (Sylvia) Lei" Date: Tue, 25 Feb 2020 14:47:56 +0800 Subject: [PATCH 09/10] [ACR] `az acr helm install-cli`: Modify params help --- src/azure-cli/azure/cli/command_modules/acr/_params.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/azure-cli/azure/cli/command_modules/acr/_params.py b/src/azure-cli/azure/cli/command_modules/acr/_params.py index 2a87ce8c624..bc8750fa445 100644 --- a/src/azure-cli/azure/cli/command_modules/acr/_params.py +++ b/src/azure-cli/azure/cli/command_modules/acr/_params.py @@ -263,7 +263,7 @@ def load_arguments(self, _): # pylint: disable=too-many-statements with self.argument_context('acr helm install-cli') as c: c.argument('client_version', help='The target Helm CLI version. (Helm v3 is currently not supported) ') - c.argument('install_location', help='File path at which to install Helm CLI.', default=_get_helm_default_install_location()) + c.argument('install_location', help='File path at which to install Helm CLI (Existing one at the same path will be overwritten)', default=_get_helm_default_install_location()) c.argument('yes', help='Agree to the license of Helm, and do not prompt for confirmation.') with self.argument_context('acr network-rule') as c: From 9db468e277abafa0e8c0ff7af660436431dcaa9a Mon Sep 17 00:00:00 2001 From: "Lixia (Sylvia) Lei" Date: Tue, 25 Feb 2020 18:10:02 +0800 Subject: [PATCH 10/10] [ACR] `az acr helm install-cli`: Optimize code structure and modify help --- .../azure/cli/command_modules/acr/_params.py | 4 +- .../azure/cli/command_modules/acr/helm.py | 38 +++++++++++++------ 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/azure-cli/azure/cli/command_modules/acr/_params.py b/src/azure-cli/azure/cli/command_modules/acr/_params.py index bc8750fa445..31ae6b697c6 100644 --- a/src/azure-cli/azure/cli/command_modules/acr/_params.py +++ b/src/azure-cli/azure/cli/command_modules/acr/_params.py @@ -262,8 +262,8 @@ def load_arguments(self, _): # pylint: disable=too-many-statements c.argument('force', help='Overwrite the existing chart package.', action='store_true') with self.argument_context('acr helm install-cli') as c: - c.argument('client_version', help='The target Helm CLI version. (Helm v3 is currently not supported) ') - c.argument('install_location', help='File path at which to install Helm CLI (Existing one at the same path will be overwritten)', default=_get_helm_default_install_location()) + c.argument('client_version', help='The target Helm CLI version. (Attention: Currently, Helm 3 does not work with "az acr helm" commands) ') + c.argument('install_location', help='Path at which to install Helm CLI (Existing one at the same path will be overwritten)', default=_get_helm_default_install_location()) c.argument('yes', help='Agree to the license of Helm, and do not prompt for confirmation.') with self.argument_context('acr network-rule') as c: diff --git a/src/azure-cli/azure/cli/command_modules/acr/helm.py b/src/azure-cli/azure/cli/command_modules/acr/helm.py index 0e0fbfc0c2b..fd6ff3ab20c 100644 --- a/src/azure-cli/azure/cli/command_modules/acr/helm.py +++ b/src/azure-cli/azure/cli/command_modules/acr/helm.py @@ -186,18 +186,12 @@ def acr_helm_install_cli(client_version='2.16.3', install_location=None, yes=Fal """Install Helm command-line tool.""" if client_version >= '3': - raise CLIError('Helm v3 is not supported yet.') + logger.warning('Please note that "az acr helm" commands do not work with Helm 3, ' + 'but you can still push Helm chart to ACR using a different command flow. ' + 'For more information, please check out ' + 'https://docs.microsoft.com/en-us/azure/container-registry/container-registry-helm-repos') - if not install_location or install_location.isspace(): - raise CLIError('Invalid install location.') - - install_dir, cli = os.path.dirname(install_location), os.path.basename(install_location) - if not cli: - raise CLIError("{} is a directory. Please specify a complete file path.".format(install_location)) - - # Ensure installation directory exists - if not os.path.exists(install_dir): - os.makedirs(install_dir) + install_location, install_dir, cli = _process_helm_install_location_info(install_location) client_version = "v%s" % client_version source_url = 'https://get.helm.sh/{}' @@ -236,6 +230,8 @@ def acr_helm_install_cli(client_version='2.16.3', install_location=None, yes=Fal if os.path.splitext(f.name)[0] in ('helm', 'tiller'): os.chmod(target_path, os.stat(target_path).st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) except IOError as e: + import traceback + logger.debug(traceback.format_exc()) raise CLIError('Error while installing {} to {}: {}'.format(cli, install_dir, e)) logger.warning('Successfully installed %s to %s.', cli, install_dir) @@ -314,6 +310,26 @@ def _get_chart_package_name(chart, version, prov=False): return chart_package_name +def _process_helm_install_location_info(install_location): + if not install_location or install_location.isspace(): + raise CLIError('Invalid install location.') + + install_dir, cli = os.path.dirname(install_location), os.path.basename(install_location) + if not install_dir: + # Use current working directory + install_dir = os.getcwd() + install_location = os.path.join(install_dir, cli) + # Ensure installation directory exists + if not os.path.exists(install_dir): + os.makedirs(install_dir) + if not cli: + system = platform.system() + cli = 'helm.exe' if system == 'Windows' else 'helm' + install_location = os.path.join(install_dir, cli) + + return install_location, install_dir, cli + + def _get_helm_package_name(client_version): package_template = 'helm-{}-{}-{}.{}' folder_template = '{}-{}'