diff --git a/azure-cli.pyproj b/azure-cli.pyproj index eb91ee8ac..a67f4661d 100644 --- a/azure-cli.pyproj +++ b/azure-cli.pyproj @@ -97,6 +97,9 @@ X86 + + + \ No newline at end of file diff --git a/src/azure/cli/_output.py b/src/azure/cli/_output.py index 1830b1a63..af96bf7ed 100644 --- a/src/azure/cli/_output.py +++ b/src/azure/cli/_output.py @@ -104,7 +104,7 @@ class ListOutput(object): #pylint: disable=too-few-public-methods @staticmethod def _dump_line(io, line, indent): io.write(' ' * indent) - io.write(line) + io.write(str(line)) io.write('\n') def _dump_object(self, io, obj, indent): diff --git a/src/azure/cli/commands/_auto_command.py b/src/azure/cli/commands/_auto_command.py index 5666dcf87..73dbee5f2 100644 --- a/src/azure/cli/commands/_auto_command.py +++ b/src/azure/cli/commands/_auto_command.py @@ -6,6 +6,9 @@ from msrest.paging import Paged from msrest.exceptions import ClientException from azure.cli.parser import IncorrectUsageError from ..commands import COMMON_PARAMETERS +from azure.cli._argparse import IncorrectUsageError +from ..commands import command, description, option +from .._logging import logger EXCLUDED_PARAMS = frozenset(['self', 'raw', 'custom_headers', 'operation_config']) @@ -44,13 +47,15 @@ def _get_member(obj, path): Ex. a.b.c would get the property 'c' of property 'b' of the object a """ + if not path: + return obj for segment in path.split('.'): obj = getattr(obj, segment) return obj def _make_func(client_factory, member_path, return_type_or_func, unbound_func): def call_client(args): - client = client_factory() + client = client_factory(args) ops_instance = _get_member(client, member_path) try: result = unbound_func(ops_instance, **args) @@ -79,10 +84,13 @@ def _option_description(operation, arg): return ' '.join(l.split(':')[-1] for l in inspect.getdoc(operation).splitlines() if l.startswith(':param') and arg + ':' in l) -def build_operation(command_name, member_path, client_type, operations, command_table): +#pylint: disable=too-many-arguments +def build_operation(command_name, member_path, client_type, operations, #pylint: disable=dangerous-default-value + paramaliases=GLOBALPARAMALIASES, extra_args=None): for operation, return_type_name in operations: opname = operation.__name__.replace('_', '-') func = _make_func(client_type, member_path, return_type_name, operation) + func = _decorate_command(' '.join([command_name, opname]), func) args = [] try: @@ -111,3 +119,10 @@ def build_operation(command_name, member_path, client_type, operations, command_ 'arguments': options } + if extra_args: + for arg in extra_args: + if len(arg) != 2: + logger.warning('%s is in invalid format. Should be: (spec, description)', + (str(arg))) + continue + func = _decorate_option(arg[0], arg[1], target=None, func=func) diff --git a/src/azure/cli/commands/network.py b/src/azure/cli/commands/network.py index d4c63fc08..efb02b729 100644 --- a/src/azure/cli/commands/network.py +++ b/src/azure/cli/commands/network.py @@ -25,7 +25,7 @@ from ..commands import CommandTable command_table = CommandTable() -def _network_client_factory(): +def _network_client_factory(*args): # pylint: disable=unused-argument return get_mgmt_service_client(NetworkManagementClient, NetworkManagementClientConfiguration) diff --git a/src/azure/cli/commands/storage.py b/src/azure/cli/commands/storage.py index 35c075dfc..e1ea8e9a2 100644 --- a/src/azure/cli/commands/storage.py +++ b/src/azure/cli/commands/storage.py @@ -2,9 +2,8 @@ from datetime import datetime from os import environ from sys import stderr -from six.moves import input #pylint: disable=redefined-builtin -from azure.storage.blob import PublicAccess +from azure.storage.blob import PublicAccess, BlockBlobService from azure.mgmt.storage import StorageManagementClient, StorageManagementClientConfiguration from azure.mgmt.storage.models import AccountType from azure.mgmt.storage.operations import StorageAccountsOperations @@ -66,9 +65,30 @@ COMMON_PARAMETERS.update({ } }) -def _storage_client_factory(): +def _storage_client_factory(*args): # pylint: disable=unused-argument return get_mgmt_service_client(StorageManagementClient, StorageManagementClientConfiguration) +STORAGE_DATA_CLIENT_ARGS = [ + ('--account-name -n ', L('the storage account name')), + ('--account-key -k ', L('the storage account key')), + ('--connection-string -t ', L('the storage account connection string')) +] + +def _blob_data_service_factory(*args): + def _resolve_arg(key, envkey): + try: + value = args[0][key] + args[0].pop(key, None) + except (IndexError, KeyError): + value = environ.get(envkey) + return value + + return get_data_service_client( + BlockBlobService, + _resolve_arg('account-name', 'AZURE_STORAGE_ACCOUNT'), + _resolve_arg('account-key', 'AZURE_STORAGE_ACCOUNT_KEY'), + _resolve_arg('connection-string', 'AZURE_STORAGE_CONNECTION_STRING')) + # ACCOUNT COMMANDS build_operation('storage account', @@ -203,6 +223,16 @@ def set_account(args, unexpected): #pylint: disable=unused-argument # CONTAINER COMMANDS +build_operation('storage container', None, _blob_data_service_factory, + [ + (BlockBlobService.list_containers, '[Container]'), + (BlockBlobService.delete_container, 'None'), + (BlockBlobService.get_container_properties, '[ContainerProperties]'), + (BlockBlobService.create_container, 'None') + ], + extra_args=STORAGE_DATA_CLIENT_ARGS) + +# TODO: update this once enums are supported in commands first-class (task #115175885) public_access_types = {'none': None, 'blob': PublicAccess.Blob, 'container': PublicAccess.Container} @@ -272,45 +302,12 @@ def delete_container(args): @option('--snapshot ', L('UTC datetime value which specifies a snapshot')) @option('--timeout ') def exists_container(args, unexpected): #pylint: disable=unused-argument - bbs = _get_blob_service_client(args) + bbs = _blob_data_service_factory(args) return str(bbs.exists( container_name=args.get('container-name'), snapshot=_parse_datetime(args, 'snapshot'), timeout=_parse_int(args, 'timeout'))) -@command_table.command('storage container list') -@command_table.description(L('List storage containers.')) -@command_table.option(**COMMON_PARAMETERS['account-name']) -@command_table.option(**COMMON_PARAMETERS['account_key']) -@command_table.option(**COMMON_PARAMETERS['connection-string']) -@command_table.option('--prefix -p', help=L('container name prefix to filter by')) -@command_table.option('--num-results ') -@command_table.option('--include-metadata') -@command_table.option('--marker ', L('continuation token for enumerating additional results')) -@command_table.option(**COMMON_PARAMETERS['timeout']) -def list_containers(args): - bbs = _get_blob_service_client(args) - return bbs.list_containers( - prefix=args.get('prefix'), - num_results=_parse_int(args, 'num-results'), - include_metadata=True if args.get('include-metadata') else False, - marker=args.get('marker'), - timeout=_parse_int(args, 'timeout')) - -@command_table.command('storage container show') -@command_table.description(L('Show details of a storage container')) -@command_table.option(**COMMON_PARAMETERS['container-name']) -@command_table.option(**COMMON_PARAMETERS['account-name']) -@command_table.option(**COMMON_PARAMETERS['account_key']) -@command_table.option(**COMMON_PARAMETERS['connection-string']) -@command_table.option('--lease-id ', L('delete only if lease is ID active and matches')) -@command_table.option(**COMMON_PARAMETERS['timeout']) -def show_container(args): - bbs = _get_blob_service_client(args) - return bbs.get_container_properties( - container_name=args.get('container-name'), - lease_id=args.get('lease-id'), - timeout=_parse_int(args, 'timeout')) lease_duration_values = {'min':15, 'max':60, 'infinite':-1} lease_duration_values_string = 'Between {} and {} seconds. ({} for infinite)'.format( @@ -318,6 +315,14 @@ lease_duration_values_string = 'Between {} and {} seconds. ({} for infinite)'.fo lease_duration_values['max'], lease_duration_values['infinite']) +build_operation('storage container lease', None, _blob_data_service_factory, + [ + (BlockBlobService.renew_container_lease, 'None'), + (BlockBlobService.release_container_lease, 'None'), + (BlockBlobService.change_container_lease, 'LeaseId') + ], + extra_args=STORAGE_DATA_CLIENT_ARGS) + @command_table.command('storage container lease acquire') @command_table.description(L('Acquire a lock on a container for delete operations.')) @command_table.option(**COMMON_PARAMETERS['container-name']) @@ -333,7 +338,7 @@ lease_duration_values_string = 'Between {} and {} seconds. ({} for infinite)'.fo 'modified since supplied UTC datetime')) @command_table.option(**COMMON_PARAMETERS['timeout']) def acquire_container_lease(args): #pylint: disable=unused-argument - bbs = _get_blob_service_client(args) + bbs = _blob_data_service_factory(args) try: lease_duration = int(args.get('lease-duration')) except ValueError: @@ -347,71 +352,6 @@ def acquire_container_lease(args): #pylint: disable=unused-argument if_unmodified_since=_parse_int(args, 'if-unmodified-since'), timeout=True if args.get('timeout') else False) -@command_table.command('storage container lease renew') -@command_table.description(L('Renew a lock on a container for delete operations.')) -@command_table.option(**COMMON_PARAMETERS['container-name']) -@command_table.option('--lease-id --lid ', L('lease id to renew in GUID format'), required=True) -@command_table.option('--account-name -n ', L('the storage account name')) -@command_table.option('--account-key -k ', L('the storage account key')) -@command_table.option('--connection-string -t ', L('the storage connection string')) -@command_table.option('--if-modified-since ', L('delete only if container modified since ' + \ - 'supplied UTC datetime')) -@option('--in-unmodified-since ', L('delete only if container has not been modified ' + \ - 'since supplied UTC datetime')) -@option('--timeout ') -def renew_container_lease(args, unexpected): #pylint: disable=unused-argument - bbs = _get_blob_service_client(args) - return bbs.renew_container_lease( - container_name=args.get('container-name'), - lease_id=args.get('lease-id'), - if_modified_since=_parse_int(args, 'if-modified-since'), - if_unmodified_since=_parse_int(args, 'if-unmodified-since'), - timeout=True if args.get('timeout') else False) - -@command('storage container lease release') -@description(L('Release a lock on a container for delete operations.')) -@option('--container-name -c ', L('the name of the container'), required=True) -@option('--lease-id --lid ', L('lease id in GUID format to release'), required=True) -@option('--account-name -n ', L('the storage account name')) -@option('--account-key -k ', L('the storage account key')) -@option('--connection-string -t ', L('the storage connection string')) -@option('--if-modified-since ', L('delete only if container modified since ' + \ - 'supplied UTC datetime')) -@option('--in-unmodified-since ', L('delete only if container has not been modified ' + \ - 'since supplied UTC datetime')) -@option('--timeout ') -def release_container_lease(args, unexpected): #pylint: disable=unused-argument - bbs = _get_blob_service_client(args) - bbs.release_container_lease( - container_name=args.get('container-name'), - lease_id=args.get('lease-id'), - if_modified_since=_parse_int(args, 'if-modified-since'), - if_unmodified_since=_parse_int(args, 'if-unmodified-since'), - timeout=True if args.get('timeout') else False) - -@command('storage container lease change') -@description(L('Change the lease id for a container lease.')) -@option('--container-name -c ', L('the name of the container'), required=True) -@option('--lease-id --lid ', L('the lease id to change'), required=True) -@option('--proposed-lease-id --plid ', L('proposed lease id in GUID format')) -@option('--account-name -n ', L('the storage account name')) -@option('--account-key -k ', L('the storage account key')) -@option('--connection-string -t ', L('the storage connection string')) -@option('--if-modified-since ', L('delete only if container modified since ' + \ - 'supplied UTC datetime')) -@option('--in-unmodified-since ', L('delete only if container has not been modified ' + \ - 'since supplied UTC datetime')) -@option('--timeout ') -def change_container_lease(args, unexpected): #pylint: disable=unused-argument - bbs = _get_blob_service_client(args) - return bbs.change_container_lease( - container_name=args.get('container-name'), - lease_id=args.get('lease-id'), - proposed_lease_id=args.get('proposed-lease-id'), - if_modified_since=_parse_int(args, 'if-modified-since'), - if_unmodified_since=_parse_int(args, 'if-unmodified-since'), - timeout=True if args.get('timeout') else False) - @command('storage container lease break') @description(L('Break a lock on a container for delete operations.')) @option('--container-name -c ', L('the name of the container'), required=True) @@ -426,12 +366,11 @@ def change_container_lease(args, unexpected): #pylint: disable=unused-argument 'since supplied UTC datetime')) @option('--timeout ') def break_container_lease(args, unexpected): #pylint: disable=unused-argument - bbs = _get_blob_service_client(args) + bbs = _blob_data_service_factory(args) try: lease_break_period = int(args.get('lease-break-period')) except ValueError: raise ValueError('lease-break-period must be: {}'.format(lease_duration_values_string)) - bbs.break_container_lease( container_name=args.get('container-name'), lease_break_period=lease_break_period, @@ -440,7 +379,15 @@ def break_container_lease(args, unexpected): #pylint: disable=unused-argument timeout=True if args.get('timeout') else False) # BLOB COMMANDS -# TODO: Evaluate for removing hand-authored commands in favor of auto-commands (task ##115068835) + +build_operation('storage blob', None, _blob_data_service_factory, + [ + (BlockBlobService.list_blobs, '[Blob]'), + (BlockBlobService.delete_blob, 'None'), + (BlockBlobService.exists, 'Boolean'), + (BlockBlobService.get_blob_properties, 'BlobProperties') + ], + extra_args=STORAGE_DATA_CLIENT_ARGS) @command_table.command('storage blob upload-block-blob') @command_table.description(L('Upload a block blob to a container.')) @@ -461,8 +408,15 @@ def break_container_lease(args, unexpected): #pylint: disable=unused-argument @command_table.option('--content.cache-control -cscc') def create_block_blob(args): from azure.storage.blob import ContentSettings - bbs = _get_blob_service_client(args) - public_access = args.get('container.public-access') + bbs = _blob_data_service_factory(args) + try: + public_access = public_access_types[args.get('public-access')] \ + if args.get('public-access') \ + else None + except KeyError: + raise IncorrectUsageError(L('container.public-access must be: {}' + .format(public_access_string))) + bbs.create_container(args.get('container-name'), public_access=public_access) return bbs.create_blob_from_path( @@ -478,80 +432,77 @@ def create_block_blob(args): cache_control=args.get('content.cache-control')) ) +#@command('storage blob list') +#@command(L('List all blobs in a container.')) +#@option('--container-name -c ', L('the name of the container'), required=True) +#@option('--account-name -n ', L('the storage account name')) +#@option('--account-key -k ', L('the storage account key')) +#@option('--connection-string -t ', L('the storage connection string')) +#@option('--prefix -p ', L('blob name prefix to filter by')) +#@option('--num-results ') +#@option('--include ', L('specifies one or more additional datasets to include '\ +# + 'in the response. Unsupported this release')) +#@option('--delimiter ', L('Unsupported this release')) +#@option('--marker ', L('continuation token for enumerating additional results')) +#@option('--timeout ') +#def list_blobs(args, unexpected): #pylint: disable=unused-argument +# bbs = _blob_data_service_factory(args) +# blobs = bbs.list_blobs( +# container_name=args.get('container-name'), +# prefix=args.get('prefix'), +# num_results=_parse_int(args, 'num-results'), +# include=None, +# delimiter=None, +# marker=args.get('marker'), +# timeout=_parse_int(args, 'timeout')) +# return list(blobs.items) -@option('--num-results ') -@option('--include ', L('specifies one or more additional datasets to include '\ - + 'in the response. Unsupported this release')) -@option('--delimiter ', L('Unsupported this release')) -@option('--marker ', L('continuation token for enumerating additional results')) -@option('--timeout ') -def list_blobs(args, unexpected): #pylint: disable=unused-argument -@command_table.command('storage blob list') -@command_table.description(L('List all blobs in a container.')) -@command_table.option(**COMMON_PARAMETERS['container-name']) -@command_table.option(**COMMON_PARAMETERS['account-name']) -@command_table.option(**COMMON_PARAMETERS['account_key']) -@command_table.option(**COMMON_PARAMETERS['connection-string']) -@command_table.option('--prefix -p', help=L('blob name prefix to filter by')) -def list_blobs(args): - bbs = _get_blob_service_client(args) - blobs = bbs.list_blobs( - container_name=args.get('container-name'), - prefix=args.get('prefix'), - num_results=_parse_int(args, 'num-results'), - include=None, - delimiter=None, - marker=args.get('marker'), - timeout=_parse_int(args, 'timeout')) - return list(blobs.items) +#@command('storage blob delete') +#@description(L('Delete a blob from a container.')) +#@option('--container-name -c ', L('the name of the container'), required=True) +#@option('--blob-name -b ', L('the name of the blob'), required=True) +#@option('--account-name -n ', L('the storage account name')) +#@option('--account-key -k ', L('the storage account key')) +#@option('--connection-string -t ', L('the storage connection string')) +#def delete_blob(args, unexpected): #pylint: disable=unused-argument +# bbs = _blob_data_service_factory(args) +# return bbs.delete_blob(args.get('container-name'), args.get('blob-name')) -def delete_blob(args, unexpected): #pylint: disable=unused-argument -@command_table.command('storage blob delete') -@command_table.description(L('Delete a blob from a container.')) -@command_table.option(**COMMON_PARAMETERS['container-name']) -@command_table.option(**COMMON_PARAMETERS['blob-name']) -def delete_blob(args): - bbs = _get_blob_service_client(args) - return bbs.delete_blob(args.get('container-name'), args.get('blob-name')) +#@command('storage blob exists') +#@description(L('Check if a blob exists.')) +#@option('--container-name -c ', L('the name of the container'), required=True) +#@option('--blob-name -b ', L('the name of the blob'), required=True) +#@option('--account-name -n ', L('the storage account name')) +#@option('--account-key -k ', L('the storage account key')) +#@option('--connection-string -t ', L('the storage connection string')) +#@option('--snapshot ', L('UTC datetime value which specifies a snapshot')) +#@option('--timeout ') +#def exists_blob(args, unexpected): #pylint: disable=unused-argument +# bbs = _blob_data_service_factory(args) +# return str(bbs.exists( +# container_name=args.get('container-name'), +# blob_name=args.get('blob-name'), +# snapshot=_parse_datetime(args, 'snapshot'), +# timeout=_parse_int(args, 'timeout'))) -@command('storage blob exists') -@description(L('Check if a blob exists.')) -@option('--container-name -c ', L('the name of the container'), required=True) -@option('--blob-name -b ', L('the name of the blob'), required=True) -@option('--account-name -n ', L('the storage account name')) -@option('--account-key -k ', L('the storage account key')) -@option('--connection-string -t ', L('the storage connection string')) -@option('--snapshot ', L('UTC datetime value which specifies a snapshot')) -@option('--timeout ') -def exists_blob(args, unexpected): #pylint: disable=unused-argument - bbs = _get_blob_service_client(args) - return str(bbs.exists( - container_name=args.get('container-name'), - blob_name=args.get('blob-name'), - snapshot=_parse_datetime(args, 'snapshot'), - timeout=_parse_int(args, 'timeout'))) +#@command('storage blob show') +#@description(L('Show properties of the specified blob.')) +#@option('--container-name -c ', L('the name of the container'), required=True) +#@option('--blob-name -bn ', L('the name of the blob'), required=True) +#@option('--account-name -n ', L('the storage account name')) +#@option('--account-key -k ', L('the storage account key')) +#@option('--connection-string -t ', L('the storage connection string')) +#def show_blob(args, unexpected): #pylint: disable=unused-argument +# bbs = _blob_data_service_factory(args) +# return bbs.get_blob_properties(args.get('container-name'), args.get('blob-name')) -@command('storage blob show') -@description(L('Show properties of the specified blob.')) -@option('--container-name -c ', L('the name of the container'), required=True) -@option('--blob-name -bn ', L('the name of the blob'), required=True) -@option('--account-name -n ', L('the storage account name')) -@option('--account-key -k ', L('the storage account key')) -@option('--connection-string -t ', L('the storage connection string')) -def show_blob(args, unexpected): #pylint: disable=unused-argument - bbs = _get_blob_service_client(args) - return bbs.get_blob_properties(args.get('container-name'), args.get('blob-name')) - -@option('--account-name -n ', L('the storage account name')) -@option('--account-key -k ', L('the storage account key')) -@option('--connection-string -t ', L('the storage connection string')) @command_table.command('storage blob download') @command_table.description(L('Download the specified blob.')) @command_table.option(**COMMON_PARAMETERS['container-name']) @command_table.option(**COMMON_PARAMETERS['blob-name']) @command_table.option('--download-to -dt', help=L('the file path to download to'), required=True) def download_blob(args): - bbs = _get_blob_service_client(args) + bbs = _blob_data_service_factory(args) # show dot indicator of download progress (one for every 10%) bbs.get_blob_to_path(args.get('container-name'), @@ -727,13 +678,6 @@ def storage_file_delete(args, unexpected): #pylint: disable=unused-argument # HELPER METHODS -def _get_blob_service_client(args): - from azure.storage.blob import BlockBlobService - return get_data_service_client(BlockBlobService, - args.get('storage-account', None), - args.get('storage-account-key', None), - args.get('connection-string', None)) - def _get_file_service_client(args): from azure.storage.file import FileService return get_data_service_client(FileService, diff --git a/src/azure/cli/commands/vm.py b/src/azure/cli/commands/vm.py index c03e7bcf9..a0fe51910 100644 --- a/src/azure/cli/commands/vm.py +++ b/src/azure/cli/commands/vm.py @@ -14,7 +14,7 @@ from ._command_creation import get_mgmt_service_client from ..commands._auto_command import build_operation, LongRunningOperation from ..commands import CommandTable -def _compute_client_factory(): +def _compute_client_factory(*args): # pylint: disable=unused-argument return get_mgmt_service_client(ComputeManagementClient, ComputeManagementClientConfiguration) command_table = CommandTable()