Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/azure-cli/azure/cli/command_modules/storage/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@ def register_sas_arguments(self):
'only IPv4 style addresses.')
self.argument('expiry', type=get_datetime_type(True),
help='Specifies the UTC datetime (Y-m-d\'T\'H:M\'Z\') at which the SAS becomes invalid. Do not '
'use if a stored access policy is referenced with --id that specifies this value.')
'use if a stored access policy is referenced with --policy-name that specifies this value.')
self.argument('start', type=get_datetime_type(True),
help='Specifies the UTC datetime (Y-m-d\'T\'H:M\'Z\') at which the SAS becomes valid. Do not use '
'if a stored access policy is referenced with --id that specifies this value. Defaults to '
'the time of the request.')
'if a stored access policy is referenced with --policy-name that specifies this value. '
'Defaults to the time of the request.')
self.argument('protocol', options_list=('--https-only',), action='store_const', const='https',
help='Only permit requests made with the HTTPS protocol. If omitted, requests from both the HTTP '
'and HTTPS protocol are permitted.')
Expand Down
28 changes: 17 additions & 11 deletions src/azure-cli/azure/cli/command_modules/storage/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from azure.cli.core.local_context import LocalContextAttribute, LocalContextAction, ALL

from ._validators import (get_datetime_type, validate_metadata, get_permission_validator, get_permission_help_string,
resource_type_type, services_type, validate_entity, validate_select, validate_blob_type,
validate_entity, validate_select, validate_blob_type,
validate_included_datasets_validator, validate_custom_domain, validate_hns_migration_type,
validate_container_public_access,
add_progress_callback, process_resource_group,
Expand All @@ -23,7 +23,8 @@
validate_fs_public_access, validate_logging_version, validate_or_policy, validate_policy,
get_api_version_type, blob_download_file_path_validator, blob_tier_validator, validate_subnet,
validate_immutability_arguments, validate_blob_name_for_upload, validate_share_close_handle,
add_upload_progress_callback, blob_tier_validator_track2, add_download_progress_callback)
add_upload_progress_callback, blob_tier_validator_track2, add_download_progress_callback,
services_type_v2, resource_type_type_v2)


def load_arguments(self, _): # pylint: disable=too-many-locals, too-many-statements, too-many-lines, too-many-branches, line-too-long
Expand Down Expand Up @@ -667,11 +668,12 @@ def load_arguments(self, _): # pylint: disable=too-many-locals, too-many-statem
help="SMB channel encryption supported by server. Valid values are AES-128-CCM, AES-128-GCM, "
"AES-256-GCM. Should be passed as a string with delimiter ';' ")

with self.argument_context('storage account generate-sas') as c:
t_account_permissions = self.get_sdk('common.models#AccountPermissions')
with self.argument_context('storage account generate-sas', resource_type=ResourceType.DATA_STORAGE_BLOB) as c:
t_account_permissions = self.get_sdk('_shared.models#AccountSasPermissions',
resource_type=ResourceType.DATA_STORAGE_BLOB)
c.register_sas_arguments()
c.argument('services', type=services_type(self))
c.argument('resource_types', type=resource_type_type(self))
c.argument('services', type=services_type_v2())
c.argument('resource_types', type=resource_type_type_v2(self))
c.argument('expiry', type=get_datetime_type(True))
c.argument('start', type=get_datetime_type(True))
c.argument('account_name', acct_name_type, options_list=['--account-name'])
Expand Down Expand Up @@ -796,11 +798,12 @@ def load_arguments(self, _): # pylint: disable=too-many-locals, too-many-statem
c.argument('show_next_marker', action='store_true',
help='Show nextMarker in result when specified.')

with self.argument_context('storage blob generate-sas') as c:
with self.argument_context('storage blob generate-sas', resource_type=ResourceType.DATA_STORAGE_BLOB) as c:
from .completers import get_storage_acl_name_completion_list

t_blob_permissions = self.get_sdk('blob.models#BlobPermissions')
t_blob_permissions = self.get_sdk('_models#BlobSasPermissions', resource_type=ResourceType.DATA_STORAGE_BLOB)
c.register_sas_arguments()
c.register_blob_arguments_track2()
Comment thread
calvinhzy marked this conversation as resolved.
c.argument('cache_control', help='Response header value for Cache-Control when resource is accessed '
'using this shared access signature.')
c.argument('content_disposition', help='Response header value for Content-Disposition when resource is '
Expand All @@ -824,6 +827,8 @@ def load_arguments(self, _): # pylint: disable=too-many-locals, too-many-statem
c.argument('permission', options_list='--permissions',
help=sas_help.format(get_permission_help_string(t_blob_permissions)),
validator=get_permission_validator(t_blob_permissions))
c.argument('snapshot', help='An optional blob snapshot ID. Opaque DateTime value that, when present, '
'specifies the blob snapshot to grant permission.')
c.ignore('sas_token')

with self.argument_context('storage blob restore', resource_type=ResourceType.MGMT_STORAGE) as c:
Expand Down Expand Up @@ -1403,13 +1408,14 @@ def load_arguments(self, _): # pylint: disable=too-many-locals, too-many-statem
with self.argument_context('storage container policy {}'.format(item)) as c:
c.extra('lease_id', options_list='--lease-id', help='The container lease ID.')

with self.argument_context('storage container generate-sas') as c:
with self.argument_context('storage container generate-sas', resource_type=ResourceType.DATA_STORAGE_BLOB) as c:
from .completers import get_storage_acl_name_completion_list
t_container_permissions = self.get_sdk('blob.models#ContainerPermissions')
t_container_permissions = self.get_sdk('_models#ContainerSasPermissions',
resource_type=ResourceType.DATA_STORAGE_BLOB)
c.register_sas_arguments()
c.argument('id', options_list='--policy-name', validator=validate_policy,
help='The name of a stored access policy within the container\'s ACL.',
completer=get_storage_acl_name_completion_list(t_container_permissions, 'container_name',
completer=get_storage_acl_name_completion_list(t_base_blob_service, 'container_name',
'get_container_acl'))
c.argument('permission', options_list='--permissions',
help=sas_help.format(get_permission_help_string(t_container_permissions)),
Expand Down
31 changes: 30 additions & 1 deletion src/azure-cli/azure/cli/command_modules/storage/_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -813,11 +813,15 @@ def get_permission_allowed_values(permission_class):
for i, item in enumerate(allowed_values):
if item == 'delete_previous_version':
allowed_values[i] = 'x' + item
if item == 'permanent_delete':
allowed_values[i] = 'y' + item
if item == 'set_immutability_policy':
allowed_values[i] = 'i' + item
if item == 'manage_access_control':
allowed_values[i] = 'permissions'
if item == 'manage_ownership':
allowed_values[i] = 'ownership'
return allowed_values
return sorted(allowed_values)
return None


Expand Down Expand Up @@ -1266,6 +1270,19 @@ def impl(string):
return impl


def resource_type_type_v2(loader):
""" Returns a function which validates that resource types string contains only a combination of service,
container, and object. Their shorthand representations are s, c, and o. """

def impl(string):
t_resources = loader.get_models('_shared.models#ResourceTypes', resource_type=ResourceType.DATA_STORAGE_BLOB)
if set(string) - set("sco"):
raise ValueError
return t_resources.from_string(''.join(set(string)))

return impl


def services_type(loader):
""" Returns a function which validates that services string contains only a combination of blob, queue, table,
and file. Their shorthand representations are b, q, t, and f. """
Expand All @@ -1279,6 +1296,18 @@ def impl(string):
return impl


def services_type_v2():
""" Returns a function which validates that services string contains only a combination of blob, queue, table,
and file. Their shorthand representations are b, q, t, and f. """

def impl(string):
if set(string) - set("bqtf"):
raise ValueError
return ''.join(set(string))

return impl


def get_char_options_validator(types, property_name):
def _validator(namespace):
service_types = set(getattr(namespace, property_name, []))
Expand Down
23 changes: 12 additions & 11 deletions src/azure-cli/azure/cli/command_modules/storage/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from azure.cli.command_modules.storage._client_factory import (cf_sa, cf_blob_container_mgmt, blob_data_service_factory,
page_blob_service_factory, file_data_service_factory,
queue_data_service_factory,
cloud_storage_account_service_factory,
multi_service_properties_factory,
cf_mgmt_policy,
cf_blob_data_gen_update, cf_sa_for_keys,
Expand Down Expand Up @@ -138,9 +137,11 @@ def get_custom_sdk(custom_module, client_factory, resource_type=ResourceType.DAT
transform=lambda x: getattr(x, 'keys', x))
g.command('revoke-delegation-keys', 'revoke_user_delegation_keys', min_api='2019-04-01')

with self.command_group('storage account',
command_type=get_custom_sdk('account', cloud_storage_account_service_factory)) as g:
g.storage_command('generate-sas', 'generate_sas')
account_blob_service_custom_sdk = get_custom_sdk('account', client_factory=cf_blob_service,
resource_type=ResourceType.DATA_STORAGE_BLOB)
with self.command_group('storage account', resource_type=ResourceType.DATA_STORAGE_BLOB,
custom_command_type=account_blob_service_custom_sdk) as g:
g.storage_custom_command_oauth('generate-sas', 'generate_sas')

blob_inventory_sdk = CliCommandType(
operations_tmpl='azure.mgmt.storage.operations#BlobInventoryPoliciesOperations.{}',
Expand Down Expand Up @@ -345,6 +346,12 @@ def get_custom_sdk(custom_module, client_factory, resource_type=ResourceType.DAT
validator=process_blob_download_batch_parameters,
exception_handler=file_related_exception_handler)

blob_service_custom_sdk = get_custom_sdk('blob', client_factory=cf_blob_service,
resource_type=ResourceType.DATA_STORAGE_BLOB)
with self.command_group('storage blob', resource_type=ResourceType.DATA_STORAGE_BLOB,
custom_command_type=blob_service_custom_sdk) as g:
g.storage_custom_command_oauth('generate-sas', 'generate_sas_blob_uri')

blob_lease_client_sdk = CliCommandType(
operations_tmpl='azure.multiapi.storagev2.blob._lease#BlobLeaseClient.{}',
client_factory=cf_blob_lease_client,
Expand All @@ -371,7 +378,6 @@ def get_custom_sdk(custom_module, client_factory, resource_type=ResourceType.DAT
# g.storage_command_oauth(
# 'download', 'get_blob_to_path', table_transformer=transform_blob_output,
# exception_handler=file_related_exception_handler)
g.storage_custom_command_oauth('generate-sas', 'generate_sas_blob_uri')
g.storage_custom_command_oauth(
'url', 'create_blob_url', transform=transform_url)
g.storage_command_oauth('snapshot', 'snapshot_blob')
Expand Down Expand Up @@ -456,10 +462,6 @@ def get_custom_sdk(custom_module, client_factory, resource_type=ResourceType.DAT
client_factory=None,
transform=create_boolean_result_output_transformer('created'),
table_transformer=transform_boolean_for_table)
g.storage_custom_command_oauth('generate-sas', 'generate_container_shared_access_signature',
min_api='2018-11-09')
g.storage_command_oauth(
'generate-sas', 'generate_container_shared_access_signature', max_api='2018-03-28')
g.storage_command_oauth('exists', 'exists', transform=create_boolean_result_output_transformer('exists'),
table_transformer=transform_boolean_for_table)
g.storage_command_oauth('set-permission', 'set_container_acl')
Expand All @@ -475,8 +477,6 @@ def get_custom_sdk(custom_module, client_factory, resource_type=ResourceType.DAT
g.storage_command_oauth('lease change', 'change_container_lease')
g.storage_command_oauth('lease break', 'break_container_lease')

blob_service_custom_sdk = get_custom_sdk('blob', client_factory=cf_blob_service,
resource_type=ResourceType.DATA_STORAGE_BLOB)
with self.command_group('storage container', custom_command_type=blob_service_custom_sdk,
resource_type=ResourceType.DATA_STORAGE_BLOB,
min_api='2019-02-02') as g:
Expand All @@ -486,6 +486,7 @@ def get_custom_sdk(custom_module, client_factory, resource_type=ResourceType.DAT
g.storage_custom_command_oauth('list', 'list_containers',
transform=transform_container_list_output,
table_transformer=transform_container_list)
g.storage_custom_command_oauth('generate-sas', 'generate_container_shared_access_signature')

blob_service_sdk = CliCommandType(
operations_tmpl='azure.multiapi.storagev2.blob._blob_service_client#'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import os
from azure.cli.command_modules.storage._client_factory import storage_client_factory, cf_sa_for_keys
from azure.cli.core.util import get_file_json, shell_safe_json_parse, find_child_item
from azure.cli.core.profiles import ResourceType, get_sdk
from knack.log import get_logger
from knack.util import CLIError

Expand All @@ -26,9 +27,10 @@ def regenerate_key(cmd, client, account_name, key_name, resource_group_name=None
return client.regenerate_key(resource_group_name, account_name, regenerate_key_parameters)


def generate_sas(client, services, resource_types, permission, expiry, start=None, ip=None, protocol=None):
def generate_sas(cmd, client, services, resource_types, permission, expiry, start=None,
ip=None, protocol=None, **kwargs):
from azure.cli.core.azclierror import RequiredArgumentMissingError
if not client.account_name or not client.account_key:
if not client.account_name or not client.credential or not client.credential.account_key:
error_msg = """
Missing/Invalid credentials to access storage service. The following variations are accepted:
(1) account name and key (--account-name and --account-key options or
Expand All @@ -40,8 +42,13 @@ def generate_sas(client, services, resource_types, permission, expiry, start=Non
quoting to preserve literal character interpretation.
"""
raise RequiredArgumentMissingError(error_msg)
return client.generate_shared_access_signature(services, resource_types, permission, expiry,
start=start, ip=ip, protocol=protocol)

t_account_sas = get_sdk(cmd.cli_ctx, ResourceType.DATA_STORAGE_BLOB,
'_shared.shared_access_signature#SharedAccessSignature')

return t_account_sas(account_name=client.account_name, account_key=client.credential.account_key).\
generate_account(services=services, resource_types=resource_types, permission=permission, expiry=expiry,
start=start, ip=ip, protocol=protocol, **kwargs)


# pylint: disable=too-many-locals, too-many-statements, too-many-branches, unused-argument
Expand Down
Loading