diff --git a/Dockerfile b/Dockerfile index ab9ce338641..4359e0949bb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -39,6 +39,8 @@ complete -o nospace -F _python_argcomplete \"az\"\n\ " > /etc/az.completion RUN echo "\nsource '/etc/az.completion'\n" >> /etc/bash.bashrc +RUN curl -sSL https://get.docker.com/ | sh + WORKDIR / CMD az; bash diff --git a/src/command_modules/azure-cli-cr/README.rst b/src/command_modules/azure-cli-cr/README.rst deleted file mode 100644 index c200631a78d..00000000000 --- a/src/command_modules/azure-cli-cr/README.rst +++ /dev/null @@ -1,7 +0,0 @@ -Microsoft Azure CLI 'cr' Command Module -================================== - -This package is for the 'cr' module. -i.e. 'az cr' - -This package has [not] been tested [much] with Python 2.7, 3.4 and 3.5. diff --git a/src/command_modules/azure-cli-cr/azure/__init__.py b/src/command_modules/azure-cli-cr/azure/__init__.py deleted file mode 100644 index e8f024a89a8..00000000000 --- a/src/command_modules/azure-cli-cr/azure/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -#--------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -#--------------------------------------------------------------------------------------------- -import pkg_resources -pkg_resources.declare_namespace(__name__) diff --git a/src/command_modules/azure-cli-cr/azure/cli/__init__.py b/src/command_modules/azure-cli-cr/azure/cli/__init__.py deleted file mode 100644 index e8f024a89a8..00000000000 --- a/src/command_modules/azure-cli-cr/azure/cli/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -#--------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -#--------------------------------------------------------------------------------------------- -import pkg_resources -pkg_resources.declare_namespace(__name__) diff --git a/src/command_modules/azure-cli-cr/azure/cli/command_modules/__init__.py b/src/command_modules/azure-cli-cr/azure/cli/command_modules/__init__.py deleted file mode 100644 index e8f024a89a8..00000000000 --- a/src/command_modules/azure-cli-cr/azure/cli/command_modules/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -#--------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -#--------------------------------------------------------------------------------------------- -import pkg_resources -pkg_resources.declare_namespace(__name__) diff --git a/src/command_modules/azure-cli-cr/azure/cli/command_modules/cr/__init__.py b/src/command_modules/azure-cli-cr/azure/cli/command_modules/cr/__init__.py deleted file mode 100644 index 5865e9ee32c..00000000000 --- a/src/command_modules/azure-cli-cr/azure/cli/command_modules/cr/__init__.py +++ /dev/null @@ -1,58 +0,0 @@ -#--------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -#--------------------------------------------------------------------------------------------- -# Add command module logic to this package. - -import httplib -import base64 -import json - -from azure.cli.commands import cli_command - -def obtain_data_from_registry(registry, username, password, path, resultIndex): - registryEndpoint = registry + '.azurecr.io' - tokenSeed = username + ':' + password - token = 'Basic ' + base64.b64encode(tokenSeed) - headers = {"Authorization": token} - conn = httplib.HTTPSConnection(registryEndpoint) - aggregateList = [] - executeNextHttpCall = True - while executeNextHttpCall: - executeNextHttpCall = False - conn.request('GET', path, None, headers) - res = conn.getresponse() - if res.status == 200: - linkHeader = res.getheader('link') - if linkHeader <> None: - # the registry is telling us there's more items in the list, and another call is needed - # the link header looks something like `Link: ; rel="next"` - # we should follow the next path indicated in the link header - path = linkHeader[(linkHeader.index('<')+1):linkHeader.index('>')] - executeNextHttpCall = True - repos = json.loads(res.read())[resultIndex] - for repo in repos: - aggregateList.append(repo) - return {resultIndex: aggregateList} - -def cr_catalog(registry, username, password): - '''Returns the catalog of containers in the specified registry. - :param str registry: The name of your Azure container registry - :param str username: The user name used to log into the container registry - :param str password: The password used to log into the container registry - ''' - path = '/v2/_catalog' - return obtain_data_from_registry(registry, username, password, path, 'repositories') - -def cr_tags(registry, username, password, container): - '''Returns the list of tags for a given container in the specified registry. - :param str registry: The name of your Azure container registry - :param str username: The user name used to log into the container registry - :param str password: The password used to log into the container registry - :param str container: The container to obtain tags from - ''' - path = '/v2/' + container + '/tags/list' - return obtain_data_from_registry(registry, username, password, path, 'tags') - -cli_command('cr catalog', cr_catalog) -cli_command('cr tags', cr_tags) diff --git a/src/command_modules/azure-cli-cr/requirements.txt b/src/command_modules/azure-cli-cr/requirements.txt deleted file mode 100644 index 41918b6f1bd..00000000000 --- a/src/command_modules/azure-cli-cr/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -azure==2.0.0rc5 diff --git a/src/command_modules/azure-cli-cr/setup.py b/src/command_modules/azure-cli-cr/setup.py deleted file mode 100644 index a95625e4359..00000000000 --- a/src/command_modules/azure-cli-cr/setup.py +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env python - -#--------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -#--------------------------------------------------------------------------------------------- - -from codecs import open -from setuptools import setup - -VERSION = '0.0.5' - -CLASSIFIERS = [ - 'Development Status :: 3 - Alpha', - 'Intended Audience :: Developers', - 'Intended Audience :: System Administrators', - 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'License :: OSI Approved :: MIT License', -] - -DEPENDENCIES = [ - 'azure==2.0.0rc5', -] - -with open('README.rst', 'r', encoding='utf-8') as f: - README = f.read() - -setup( - name='azure-cli-cr', - version=VERSION, - description='Microsoft Azure Command-Line Tools', - long_description=README, - license='MIT', - author='Microsoft Corporation', - author_email='azpycli@microsoft.com', - url='https://github.com/Azure/azure-cli', - classifiers=CLASSIFIERS, - namespace_packages = [ - 'azure', - 'azure.cli', - 'azure.cli.command_modules', - ], - packages=[ - 'azure.cli.command_modules.cr' - ], - install_requires=DEPENDENCIES, -) diff --git a/src/command_modules/azure-cli-registry/azure/cli/command_modules/registry/__init__.py b/src/command_modules/azure-cli-registry/azure/cli/command_modules/registry/__init__.py index 2f03a3efed7..26d4c1e7a79 100644 --- a/src/command_modules/azure-cli-registry/azure/cli/command_modules/registry/__init__.py +++ b/src/command_modules/azure-cli-registry/azure/cli/command_modules/registry/__init__.py @@ -8,3 +8,4 @@ import azure.cli.command_modules.registry._help import azure.cli.command_modules.registry._params import azure.cli.command_modules.registry.custom +import azure.cli.command_modules.registry.container diff --git a/src/command_modules/azure-cli-registry/azure/cli/command_modules/registry/_arm_utils.py b/src/command_modules/azure-cli-registry/azure/cli/command_modules/registry/_arm_utils.py index 1badeefed29..2d7d131921c 100644 --- a/src/command_modules/azure-cli-registry/azure/cli/command_modules/registry/_arm_utils.py +++ b/src/command_modules/azure-cli-registry/azure/cli/command_modules/registry/_arm_utils.py @@ -33,17 +33,17 @@ def arm_get_registry_by_name(registry_name): :param str registry_name: The name of container registry ''' registries = arm_get_registries_in_subscription() - elements = [item for item in registries if item.name == registry_name] + elements = [item for item in registries if item.name.lower() == registry_name.lower()] if len(elements) == 0: - raise ValueError('No container registry can be found with name: ' + registry_name) + return None elif len(elements) == 1: return elements[0] else: raise ValueError('More than one container registries are found with name: ' + registry_name) def arm_deploy_template(resource_group, registry_name, location, storage_account_name, - deployment_name="Microsoft.Krater", mode='incremental'): + deployment_name, mode='incremental'): '''Deploys ARM template to create a container registry. :param str resource_group: The name of resource group :param str registry_name: The name of container registry diff --git a/src/command_modules/azure-cli-registry/azure/cli/command_modules/registry/_params.py b/src/command_modules/azure-cli-registry/azure/cli/command_modules/registry/_params.py index 186a0efd0b7..be35f4b39f4 100644 --- a/src/command_modules/azure-cli-registry/azure/cli/command_modules/registry/_params.py +++ b/src/command_modules/azure-cli-registry/azure/cli/command_modules/registry/_params.py @@ -20,8 +20,14 @@ help='Name of storage account.' ) +deployment_name_type = CliArgumentType( + options_list=('--deployment-name', '-d'), + help='Name of deployment.' +) + register_cli_argument('registry', 'registry_name', arg_type=name_type) register_cli_argument('registry', 'resource_group', arg_type=resource_group_name_type) register_cli_argument('registry', 'location', arg_type=location_type) register_cli_argument('registry', 'tags', arg_type=tags_type) register_cli_argument('registry', 'storage_account_name', arg_type=storage_account_type) +register_cli_argument('registry', 'deployment_name', arg_type=deployment_name_type) diff --git a/src/command_modules/azure-cli-registry/azure/cli/command_modules/registry/_utils.py b/src/command_modules/azure-cli-registry/azure/cli/command_modules/registry/_utils.py index 5e8749a9b56..12aaf399558 100644 --- a/src/command_modules/azure-cli-registry/azure/cli/command_modules/registry/_utils.py +++ b/src/command_modules/azure-cli-registry/azure/cli/command_modules/registry/_utils.py @@ -23,10 +23,10 @@ def get_registry_by_name(registry_name): :param str registry_name: The name of container registry ''' registries = _get_registries_in_subscription() - elements = [item for item in registries if item.name == registry_name] + elements = [item for item in registries if item.name.lower() == registry_name.lower()] if len(elements) == 0: - raise ValueError('No container registry can be found with name: ' + registry_name) + return None elif len(elements) == 1: return elements[0] else: diff --git a/src/command_modules/azure-cli-registry/azure/cli/command_modules/registry/container.py b/src/command_modules/azure-cli-registry/azure/cli/command_modules/registry/container.py new file mode 100644 index 00000000000..313970623d5 --- /dev/null +++ b/src/command_modules/azure-cli-registry/azure/cli/command_modules/registry/container.py @@ -0,0 +1,78 @@ +#--------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +#--------------------------------------------------------------------------------------------- +# Add command module logic to this package. + +import requests + +from azure.cli.commands import cli_command + +from ._utils import get_registry_by_name + +import azure.cli._logging as _logging +logger = _logging.get_az_logger(__name__) + +def _obtain_data_from_registry(registry_name, path, resultIndex, username, password): + registryEndpoint = 'https://' + registry_name + '.azurecr.io' + resultList = [] + executeNextHttpCall = True + + while executeNextHttpCall: + executeNextHttpCall = False + response = requests.get(registryEndpoint + path, + auth=requests.auth.HTTPBasicAuth( + username, + password + ) + ) + + if response.status_code == 200: + resultList += response.json()[resultIndex] + if 'link' in response.headers and response.headers['link']: + linkHeader = response.headers['link'] + # the registry is telling us there's more items in the list, and another call is needed + # the link header looks something like `Link: ; rel="next"` + # we should follow the next path indicated in the link header + path = linkHeader[(linkHeader.index('<')+1):linkHeader.index('>')] + executeNextHttpCall = True + else: + response.raise_for_status() + + return {resultIndex: resultList} + +def _validate_user_credentials(registry_name, path, resultIndex, username=None, password=None): + if username and password: + return _obtain_data_from_registry(registry_name, path, resultIndex, username, password) + + try: + registry = get_registry_by_name(registry_name) + username = registry.properties.username + password = registry.properties.key + return _obtain_data_from_registry(registry_name, path, resultIndex, username, password) + except: # pylint: disable=W0702 + logger.error('No container registry can be found with name: ' + registry_name) + logger.error('Please switch subscription or enter username/password') + raise SystemExit(1) + +def cr_catalog(registry_name, username=None, password=None): + '''Returns the catalog of containers in the specified registry. + :param str registry_name: The name of your Azure container registry + :param str username: The user name used to log into the container registry + :param str password: The password used to log into the container registry + ''' + path = '/v2/_catalog' + return _validate_user_credentials(registry_name, path, 'repositories', username, password) + +def cr_tags(registry_name, container, username=None, password=None): + '''Returns the list of tags for a given container in the specified registry. + :param str registry_name: The name of your Azure container registry + :param str container: The container to obtain tags from + :param str username: The user name used to log into the container registry + :param str password: The password used to log into the container registry + ''' + path = '/v2/' + container + '/tags/list' + return _validate_user_credentials(registry_name, path, 'tags', username, password) + +cli_command('registry catalog', cr_catalog) +cli_command('registry tags', cr_tags) diff --git a/src/command_modules/azure-cli-registry/azure/cli/command_modules/registry/custom.py b/src/command_modules/azure-cli-registry/azure/cli/command_modules/registry/custom.py index 8c92544d680..69270f75077 100644 --- a/src/command_modules/azure-cli-registry/azure/cli/command_modules/registry/custom.py +++ b/src/command_modules/azure-cli-registry/azure/cli/command_modules/registry/custom.py @@ -23,7 +23,10 @@ from ._format import output_format -def _cr_list(resource_group=None): +import azure.cli._logging as _logging +logger = _logging.get_az_logger(__name__) + +def cr_list(resource_group=None): '''Returns the list of container registries. :param str resource_group: The name of resource group ''' @@ -32,39 +35,52 @@ def _cr_list(resource_group=None): else: return arm_get_registries_in_subscription() -def _cr_create(resource_group, registry_name, location, storage_account_name=None): +def cr_create(resource_group, registry_name, location, storage_account_name=None, deployment_name="Microsoft.Krater"): '''Returns the created container registry. :param str resource_group: The name of resource group :param str registry_name: The name of container registry :param str location: The name of location :param str storage_account_name: The name of storage account + :param str deployment_name: The name of deployment ''' if storage_account_name: - return arm_deploy_template(resource_group, registry_name, location, storage_account_name) + return arm_deploy_template(resource_group, registry_name, location, storage_account_name, deployment_name) else: return get_mgmt_service_client().create(resource_group, registry_name, RegistryParameters(location=location)) -def _cr_delete(registry_name): +def cr_delete(registry_name): '''Deletes the container registry that matches the registry name :param str registry_name: The name of container registry ''' registry = arm_get_registry_by_name(registry_name) + if registry is None: + logger.error('No container registry can be found with name: ' + registry_name) + raise SystemExit(1) + resource_group = get_resource_group_by_registry(registry) return get_mgmt_service_client().delete(resource_group, registry_name) -def _cr_show(registry_name): +def cr_show(registry_name): '''Returns the container registry that matches the registry name. :param str registry_name: The name of container registry ''' registry = arm_get_registry_by_name(registry_name) + if registry is None: + logger.error('No container registry can be found with name: ' + registry_name) + raise SystemExit(1) + resource_group = get_resource_group_by_registry(registry) return get_mgmt_service_client().get_properties(resource_group, registry_name) -def _cr_update(registry_name, tags=None): +def cr_update(registry_name, tags=None): '''Returns the updated container registry that matches the registry name. :param str registry_name: The name of container registry ''' registry = get_registry_by_name(registry_name) + if registry is None: + logger.error('No container registry can be found with name: ' + registry_name) + raise SystemExit(1) + resource_group = get_resource_group_by_registry(registry) newTags = registry.tags @@ -81,8 +97,8 @@ def _cr_update(registry_name, tags=None): return get_mgmt_service_client().update(resource_group, registry_name, RegistryParameters(location=registry.location, tags=newTags)) -cli_command('registry list', _cr_list, simple_output_query=output_format) -cli_command('registry create', _cr_create, simple_output_query=output_format) -cli_command('registry delete', _cr_delete, simple_output_query=output_format) -cli_command('registry show', _cr_show, simple_output_query=output_format) -cli_command('registry update', _cr_update, simple_output_query=output_format) +cli_command('registry list', cr_list, simple_output_query=output_format) +cli_command('registry create', cr_create, simple_output_query=output_format) +cli_command('registry delete', cr_delete, simple_output_query=output_format) +cli_command('registry show', cr_show, simple_output_query=output_format) +cli_command('registry update', cr_update, simple_output_query=output_format)