diff --git a/src/azure-cli/azure/cli/command_modules/storage/__init__.py b/src/azure-cli/azure/cli/command_modules/storage/__init__.py index d4692595ad7..33731a52811 100644 --- a/src/azure-cli/azure/cli/command_modules/storage/__init__.py +++ b/src/azure-cli/azure/cli/command_modules/storage/__init__.py @@ -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.') diff --git a/src/azure-cli/azure/cli/command_modules/storage/_params.py b/src/azure-cli/azure/cli/command_modules/storage/_params.py index 06ba2b45a72..78254b9c6fb 100644 --- a/src/azure-cli/azure/cli/command_modules/storage/_params.py +++ b/src/azure-cli/azure/cli/command_modules/storage/_params.py @@ -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, @@ -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 @@ -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']) @@ -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() 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 ' @@ -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: @@ -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)), diff --git a/src/azure-cli/azure/cli/command_modules/storage/_validators.py b/src/azure-cli/azure/cli/command_modules/storage/_validators.py index 146960917ab..016e8d5db73 100644 --- a/src/azure-cli/azure/cli/command_modules/storage/_validators.py +++ b/src/azure-cli/azure/cli/command_modules/storage/_validators.py @@ -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 @@ -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. """ @@ -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, [])) diff --git a/src/azure-cli/azure/cli/command_modules/storage/commands.py b/src/azure-cli/azure/cli/command_modules/storage/commands.py index 8f4d00494a2..7a4cf9c2f6a 100644 --- a/src/azure-cli/azure/cli/command_modules/storage/commands.py +++ b/src/azure-cli/azure/cli/command_modules/storage/commands.py @@ -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, @@ -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.{}', @@ -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, @@ -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') @@ -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') @@ -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: @@ -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#' diff --git a/src/azure-cli/azure/cli/command_modules/storage/operations/account.py b/src/azure-cli/azure/cli/command_modules/storage/operations/account.py index 59dcadfbe81..96dd8bbfe49 100644 --- a/src/azure-cli/azure/cli/command_modules/storage/operations/account.py +++ b/src/azure-cli/azure/cli/command_modules/storage/operations/account.py @@ -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 @@ -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 @@ -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 diff --git a/src/azure-cli/azure/cli/command_modules/storage/operations/blob.py b/src/azure-cli/azure/cli/command_modules/storage/operations/blob.py index 34b0462697c..2942dd27cdb 100644 --- a/src/azure-cli/azure/cli/command_modules/storage/operations/blob.py +++ b/src/azure-cli/azure/cli/command_modules/storage/operations/blob.py @@ -6,7 +6,7 @@ import os from datetime import datetime -from azure.cli.core.profiles import ResourceType +from azure.cli.core.profiles import ResourceType, get_sdk from azure.cli.core.util import sdk_no_wait from azure.cli.core.azclierror import AzureResponseError from azure.cli.command_modules.storage.url_quote_util import encode_for_url, make_encoded_file_url_and_params @@ -728,47 +728,78 @@ def _delete_blob(blob_name): logger.warning('%s of %s blobs not deleted due to "Failed Precondition"', num_failures, len(source_blobs)) -def generate_sas_blob_uri(client, container_name, blob_name, permission=None, - expiry=None, start=None, id=None, ip=None, # pylint: disable=redefined-builtin +def generate_sas_blob_uri(cmd, client, permission=None, expiry=None, start=None, id=None, ip=None, # pylint: disable=redefined-builtin protocol=None, cache_control=None, content_disposition=None, content_encoding=None, content_language=None, - content_type=None, full_uri=False, as_user=False): + content_type=None, full_uri=False, as_user=False, snapshot=None, **kwargs): from ..url_quote_util import encode_url_path from urllib.parse import quote + t_generate_blob_sas = get_sdk(cmd.cli_ctx, ResourceType.DATA_STORAGE_BLOB, + '_shared_access_signature#generate_blob_sas') + + account_name = client.account_name + user_delegation_key = None + account_key = None if as_user: user_delegation_key = client.get_user_delegation_key( get_datetime_from_string(start) if start else datetime.utcnow(), get_datetime_from_string(expiry)) - sas_token = client.generate_blob_shared_access_signature( - container_name, blob_name, permission=permission, expiry=expiry, start=start, id=id, ip=ip, - protocol=protocol, cache_control=cache_control, content_disposition=content_disposition, - content_encoding=content_encoding, content_language=content_language, content_type=content_type, - user_delegation_key=user_delegation_key) else: - sas_token = client.generate_blob_shared_access_signature( - container_name, blob_name, permission=permission, expiry=expiry, start=start, id=id, ip=ip, - protocol=protocol, cache_control=cache_control, content_disposition=content_disposition, - content_encoding=content_encoding, content_language=content_language, content_type=content_type) + account_key = client.credential.account_key + + blob_url = kwargs.pop('blob_url') + container_name = kwargs.pop('container_name') + blob_name = kwargs.pop('blob_name') + t_blob_client = get_sdk(cmd.cli_ctx, ResourceType.DATA_STORAGE_BLOB, '_blob_client#BlobClient') + if blob_url: + if as_user: + credential = client.credential._credential + else: + credential = client.credential.account_key + blob_client = t_blob_client.from_blob_url(blob_url=blob_url, credential=credential, snapshot=snapshot) + container_name = blob_client.container_name + blob_name = blob_client.blob_name + else: + blob_client = client.get_blob_client(container=container_name, blob=blob_name, snapshot=snapshot) + blob_url = blob_client.url + + sas_token = t_generate_blob_sas(account_name=account_name, container_name=container_name, blob_name=blob_name, + snapshot=snapshot, account_key=account_key, user_delegation_key=user_delegation_key, + permission=permission, expiry=expiry, start=start, policy_id=id, ip=ip, + protocol=protocol, cache_control=cache_control, + content_disposition=content_disposition, content_encoding=content_encoding, + content_language=content_language, content_type=content_type, **kwargs) + if full_uri: - return encode_url_path(client.make_blob_url(container_name, blob_name, protocol=protocol, - sas_token=quote(sas_token, safe='&%()$=\',~'))) + blob_client = t_blob_client(account_url=client.url, container_name=container_name, blob_name=blob_name, + snapshot=snapshot, credential=sas_token) + return encode_url_path(blob_client.url) return quote(sas_token, safe='&%()$=\',~') -def generate_container_shared_access_signature(client, container_name, permission=None, - expiry=None, start=None, id=None, ip=None, # pylint: disable=redefined-builtin - protocol=None, cache_control=None, content_disposition=None, - content_encoding=None, content_language=None, - content_type=None, as_user=False): +# pylint: disable=redefined-builtin +def generate_container_shared_access_signature(cmd, client, container_name, permission=None, expiry=None, + start=None, id=None, ip=None, protocol=None, cache_control=None, + content_disposition=None, content_encoding=None, content_language=None, + content_type=None, as_user=False, **kwargs): + + t_generate_container_sas = get_sdk(cmd.cli_ctx, ResourceType.DATA_STORAGE_BLOB, + '_shared_access_signature#generate_container_sas') + + account_name = client.account_name user_delegation_key = None + account_key = None if as_user: user_delegation_key = client.get_user_delegation_key( get_datetime_from_string(start) if start else datetime.utcnow(), get_datetime_from_string(expiry)) - - return client.generate_container_shared_access_signature( - container_name, permission=permission, expiry=expiry, start=start, id=id, ip=ip, - protocol=protocol, cache_control=cache_control, content_disposition=content_disposition, - content_encoding=content_encoding, content_language=content_language, content_type=content_type, - user_delegation_key=user_delegation_key) + else: + account_key = client.credential.account_key + + return t_generate_container_sas(account_name=account_name, container_name=container_name, + account_key=account_key, user_delegation_key=user_delegation_key, + permission=permission, expiry=expiry, start=start, policy_id=id, ip=ip, + protocol=protocol, cache_control=cache_control, + content_disposition=content_disposition, content_encoding=content_encoding, + content_language=content_language, content_type=content_type, **kwargs) def create_blob_url(client, container_name, blob_name, protocol=None, snapshot=None): diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/recordings/test_create_account_sas.yaml b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/recordings/test_create_account_sas.yaml index ab370bd5c8d..4ae12a54bb9 100644 --- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/recordings/test_create_account_sas.yaml +++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/recordings/test_create_account_sas.yaml @@ -1,2 +1,2 @@ interactions: [] -version: 1 +version: 1 \ No newline at end of file diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/recordings/test_storage_blob_container_operations.yaml b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/recordings/test_storage_blob_container_operations.yaml index 5378622dda9..1841e4dc00d 100644 --- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/recordings/test_storage_blob_container_operations.yaml +++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/recordings/test_storage_blob_container_operations.yaml @@ -15,12 +15,12 @@ interactions: ParameterSetName: - -n -g --query -o User-Agent: - - AZURECLI/2.33.1 azsdk-python-azure-mgmt-storage/19.1.0 Python/3.7.9 (Windows-10-10.0.22000-SP0) + - AZURECLI/2.34.1 azsdk-python-azure-mgmt-storage/19.1.0 Python/3.9.6 (Windows-10-10.0.19044-SP0) method: POST uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/listKeys?api-version=2021-08-01&$expand=kerb response: body: - string: '{"keys":[{"creationTime":"2022-02-23T03:33:16.3813577Z","keyName":"key1","value":"veryFakedStorageAccountKey==","permissions":"FULL"},{"creationTime":"2022-02-23T03:33:16.3813577Z","keyName":"key2","value":"veryFakedStorageAccountKey==","permissions":"FULL"}]}' + string: '{"keys":[{"creationTime":"2022-03-31T03:27:06.7160555Z","keyName":"key1","value":"veryFakedStorageAccountKey==","permissions":"FULL"},{"creationTime":"2022-03-31T03:27:06.7160555Z","keyName":"key2","value":"veryFakedStorageAccountKey==","permissions":"FULL"}]}' headers: cache-control: - no-cache @@ -29,7 +29,7 @@ interactions: content-type: - application/json date: - - Wed, 23 Feb 2022 03:33:37 GMT + - Thu, 31 Mar 2022 03:27:27 GMT expires: - '-1' pragma: @@ -57,9 +57,9 @@ interactions: Content-Length: - '0' User-Agent: - - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.7.9; Windows 10) AZURECLI/2.33.1 + - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.9.6; Windows 10) AZURECLI/2.34.1 x-ms-date: - - Wed, 23 Feb 2022 03:33:37 GMT + - Thu, 31 Mar 2022 03:27:27 GMT x-ms-version: - '2018-11-09' method: PUT @@ -71,11 +71,11 @@ interactions: content-length: - '0' date: - - Wed, 23 Feb 2022 03:33:38 GMT + - Thu, 31 Mar 2022 03:27:29 GMT etag: - - '"0x8D9F67D48391331"' + - '"0x8DA12C66286EA1E"' last-modified: - - Wed, 23 Feb 2022 03:33:39 GMT + - Thu, 31 Mar 2022 03:27:29 GMT server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 x-ms-version: @@ -89,9 +89,9 @@ interactions: Connection: - keep-alive User-Agent: - - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.7.9; Windows 10) AZURECLI/2.33.1 + - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.9.6; Windows 10) AZURECLI/2.34.1 x-ms-date: - - Wed, 23 Feb 2022 03:33:39 GMT + - Thu, 31 Mar 2022 03:27:28 GMT x-ms-version: - '2018-11-09' method: GET @@ -103,11 +103,11 @@ interactions: content-length: - '0' date: - - Wed, 23 Feb 2022 03:33:40 GMT + - Thu, 31 Mar 2022 03:27:30 GMT etag: - - '"0x8D9F67D48391331"' + - '"0x8DA12C66286EA1E"' last-modified: - - Wed, 23 Feb 2022 03:33:39 GMT + - Thu, 31 Mar 2022 03:27:29 GMT server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 x-ms-has-immutability-policy: @@ -129,9 +129,9 @@ interactions: Connection: - keep-alive User-Agent: - - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.7.9; Windows 10) AZURECLI/2.33.1 + - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.9.6; Windows 10) AZURECLI/2.34.1 x-ms-date: - - Wed, 23 Feb 2022 03:33:40 GMT + - Thu, 31 Mar 2022 03:27:29 GMT x-ms-version: - '2018-11-09' method: GET @@ -144,11 +144,11 @@ interactions: content-type: - application/xml date: - - Wed, 23 Feb 2022 03:33:41 GMT + - Thu, 31 Mar 2022 03:27:31 GMT etag: - - '"0x8D9F67D48391331"' + - '"0x8DA12C66286EA1E"' last-modified: - - Wed, 23 Feb 2022 03:33:39 GMT + - Thu, 31 Mar 2022 03:27:29 GMT server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: @@ -168,11 +168,11 @@ interactions: Content-Length: - '60' User-Agent: - - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.7.9; Windows 10) AZURECLI/2.33.1 + - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.9.6; Windows 10) AZURECLI/2.34.1 x-ms-blob-public-access: - blob x-ms-date: - - Wed, 23 Feb 2022 03:33:41 GMT + - Thu, 31 Mar 2022 03:27:30 GMT x-ms-version: - '2018-11-09' method: PUT @@ -184,11 +184,11 @@ interactions: content-length: - '0' date: - - Wed, 23 Feb 2022 03:33:42 GMT + - Thu, 31 Mar 2022 03:27:32 GMT etag: - - '"0x8D9F67D4A484190"' + - '"0x8DA12C664924CE9"' last-modified: - - Wed, 23 Feb 2022 03:33:42 GMT + - Thu, 31 Mar 2022 03:27:32 GMT server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 x-ms-version: @@ -202,9 +202,9 @@ interactions: Connection: - keep-alive User-Agent: - - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.7.9; Windows 10) AZURECLI/2.33.1 + - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.9.6; Windows 10) AZURECLI/2.34.1 x-ms-date: - - Wed, 23 Feb 2022 03:33:42 GMT + - Thu, 31 Mar 2022 03:27:32 GMT x-ms-version: - '2018-11-09' method: GET @@ -217,11 +217,11 @@ interactions: content-type: - application/xml date: - - Wed, 23 Feb 2022 03:33:43 GMT + - Thu, 31 Mar 2022 03:27:33 GMT etag: - - '"0x8D9F67D4A484190"' + - '"0x8DA12C664924CE9"' last-modified: - - Wed, 23 Feb 2022 03:33:42 GMT + - Thu, 31 Mar 2022 03:27:32 GMT server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: @@ -239,9 +239,9 @@ interactions: Connection: - keep-alive User-Agent: - - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.7.9; Windows 10) AZURECLI/2.33.1 + - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.9.6; Windows 10) AZURECLI/2.34.1 x-ms-date: - - Wed, 23 Feb 2022 03:33:43 GMT + - Thu, 31 Mar 2022 03:27:33 GMT x-ms-version: - '2018-11-09' method: GET @@ -254,11 +254,11 @@ interactions: content-type: - application/xml date: - - Wed, 23 Feb 2022 03:33:44 GMT + - Thu, 31 Mar 2022 03:27:34 GMT etag: - - '"0x8D9F67D4A484190"' + - '"0x8DA12C664924CE9"' last-modified: - - Wed, 23 Feb 2022 03:33:42 GMT + - Thu, 31 Mar 2022 03:27:32 GMT server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: @@ -280,9 +280,9 @@ interactions: Content-Length: - '60' User-Agent: - - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.7.9; Windows 10) AZURECLI/2.33.1 + - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.9.6; Windows 10) AZURECLI/2.34.1 x-ms-date: - - Wed, 23 Feb 2022 03:33:44 GMT + - Thu, 31 Mar 2022 03:27:34 GMT x-ms-version: - '2018-11-09' method: PUT @@ -294,11 +294,11 @@ interactions: content-length: - '0' date: - - Wed, 23 Feb 2022 03:33:45 GMT + - Thu, 31 Mar 2022 03:27:36 GMT etag: - - '"0x8D9F67D4C5B1AFA"' + - '"0x8DA12C666A17CF0"' last-modified: - - Wed, 23 Feb 2022 03:33:46 GMT + - Thu, 31 Mar 2022 03:27:36 GMT server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 x-ms-version: @@ -312,9 +312,9 @@ interactions: Connection: - keep-alive User-Agent: - - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.7.9; Windows 10) AZURECLI/2.33.1 + - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.9.6; Windows 10) AZURECLI/2.34.1 x-ms-date: - - Wed, 23 Feb 2022 03:33:46 GMT + - Thu, 31 Mar 2022 03:27:35 GMT x-ms-version: - '2018-11-09' method: GET @@ -327,11 +327,11 @@ interactions: content-type: - application/xml date: - - Wed, 23 Feb 2022 03:33:46 GMT + - Thu, 31 Mar 2022 03:27:37 GMT etag: - - '"0x8D9F67D4C5B1AFA"' + - '"0x8DA12C666A17CF0"' last-modified: - - Wed, 23 Feb 2022 03:33:46 GMT + - Thu, 31 Mar 2022 03:27:36 GMT server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: @@ -347,9 +347,9 @@ interactions: Connection: - keep-alive User-Agent: - - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.7.9; Windows 10) AZURECLI/2.33.1 + - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.9.6; Windows 10) AZURECLI/2.34.1 x-ms-date: - - Wed, 23 Feb 2022 03:33:47 GMT + - Thu, 31 Mar 2022 03:27:36 GMT x-ms-version: - '2018-11-09' method: GET @@ -361,11 +361,11 @@ interactions: content-length: - '0' date: - - Wed, 23 Feb 2022 03:33:48 GMT + - Thu, 31 Mar 2022 03:27:37 GMT etag: - - '"0x8D9F67D4C5B1AFA"' + - '"0x8DA12C666A17CF0"' last-modified: - - Wed, 23 Feb 2022 03:33:46 GMT + - Thu, 31 Mar 2022 03:27:36 GMT server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 x-ms-has-immutability-policy: @@ -395,30 +395,30 @@ interactions: ParameterSetName: - --query --account-name --account-key User-Agent: - - AZURECLI/2.33.1 azsdk-python-storage-blob/12.9.0 Python/3.7.9 (Windows-10-10.0.22000-SP0) + - AZURECLI/2.34.1 azsdk-python-storage-blob/12.10.0 Python/3.9.6 (Windows-10-10.0.19044-SP0) x-ms-date: - - Wed, 23 Feb 2022 03:33:48 GMT + - Thu, 31 Mar 2022 03:27:38 GMT x-ms-version: - - '2020-10-02' + - '2021-04-10' method: GET uri: https://clitest000002.blob.core.windows.net/?comp=list&maxresults=5000&include= response: body: string: "\uFEFF5000cont000003Wed, - 23 Feb 2022 03:33:46 GMT\"0x8D9F67D4C5B1AFA\"unlockedavailable$account-encryption-keyfalsefalsefalsefalse5000cont000003Thu, + 31 Mar 2022 03:27:36 GMT\"0x8DA12C666A17CF0\"unlockedavailable$account-encryption-keyfalsefalsefalsefalse" headers: content-type: - application/xml date: - - Wed, 23 Feb 2022 03:33:49 GMT + - Thu, 31 Mar 2022 03:27:38 GMT server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: - chunked x-ms-version: - - '2020-10-02' + - '2021-04-10' status: code: 200 message: OK @@ -430,9 +430,9 @@ interactions: Content-Length: - '0' User-Agent: - - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.7.9; Windows 10) AZURECLI/2.33.1 + - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.9.6; Windows 10) AZURECLI/2.34.1 x-ms-date: - - Wed, 23 Feb 2022 03:33:49 GMT + - Thu, 31 Mar 2022 03:27:39 GMT x-ms-meta-foo: - bar x-ms-meta-moo: @@ -448,11 +448,11 @@ interactions: content-length: - '0' date: - - Wed, 23 Feb 2022 03:33:50 GMT + - Thu, 31 Mar 2022 03:27:40 GMT etag: - - '"0x8D9F67D4F3370F5"' + - '"0x8DA12C669747BE0"' last-modified: - - Wed, 23 Feb 2022 03:33:50 GMT + - Thu, 31 Mar 2022 03:27:40 GMT server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 x-ms-version: @@ -466,9 +466,9 @@ interactions: Connection: - keep-alive User-Agent: - - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.7.9; Windows 10) AZURECLI/2.33.1 + - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.9.6; Windows 10) AZURECLI/2.34.1 x-ms-date: - - Wed, 23 Feb 2022 03:33:50 GMT + - Thu, 31 Mar 2022 03:27:40 GMT x-ms-version: - '2018-11-09' method: GET @@ -480,11 +480,11 @@ interactions: content-length: - '0' date: - - Wed, 23 Feb 2022 03:33:51 GMT + - Thu, 31 Mar 2022 03:27:41 GMT etag: - - '"0x8D9F67D4F3370F5"' + - '"0x8DA12C669747BE0"' last-modified: - - Wed, 23 Feb 2022 03:33:50 GMT + - Thu, 31 Mar 2022 03:27:40 GMT server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 x-ms-meta-foo: @@ -504,9 +504,9 @@ interactions: Content-Length: - '0' User-Agent: - - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.7.9; Windows 10) AZURECLI/2.33.1 + - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.9.6; Windows 10) AZURECLI/2.34.1 x-ms-date: - - Wed, 23 Feb 2022 03:33:52 GMT + - Thu, 31 Mar 2022 03:27:41 GMT x-ms-version: - '2018-11-09' method: PUT @@ -518,11 +518,11 @@ interactions: content-length: - '0' date: - - Wed, 23 Feb 2022 03:33:53 GMT + - Thu, 31 Mar 2022 03:27:42 GMT etag: - - '"0x8D9F67D509F74EA"' + - '"0x8DA12C66AE539BB"' last-modified: - - Wed, 23 Feb 2022 03:33:53 GMT + - Thu, 31 Mar 2022 03:27:43 GMT server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 x-ms-version: @@ -536,9 +536,9 @@ interactions: Connection: - keep-alive User-Agent: - - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.7.9; Windows 10) AZURECLI/2.33.1 + - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.9.6; Windows 10) AZURECLI/2.34.1 x-ms-date: - - Wed, 23 Feb 2022 03:33:53 GMT + - Thu, 31 Mar 2022 03:27:42 GMT x-ms-version: - '2018-11-09' method: GET @@ -550,11 +550,11 @@ interactions: content-length: - '0' date: - - Wed, 23 Feb 2022 03:33:54 GMT + - Thu, 31 Mar 2022 03:27:44 GMT etag: - - '"0x8D9F67D509F74EA"' + - '"0x8DA12C66AE539BB"' last-modified: - - Wed, 23 Feb 2022 03:33:53 GMT + - Thu, 31 Mar 2022 03:27:43 GMT server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 x-ms-version: @@ -572,9 +572,9 @@ interactions: If-Modified-Since: - Fri, 01 Apr 2016 12:00:00 GMT User-Agent: - - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.7.9; Windows 10) AZURECLI/2.33.1 + - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.9.6; Windows 10) AZURECLI/2.34.1 x-ms-date: - - Wed, 23 Feb 2022 03:33:54 GMT + - Thu, 31 Mar 2022 03:27:44 GMT x-ms-lease-action: - acquire x-ms-lease-duration: @@ -592,11 +592,11 @@ interactions: content-length: - '0' date: - - Wed, 23 Feb 2022 03:33:55 GMT + - Thu, 31 Mar 2022 03:27:45 GMT etag: - - '"0x8D9F67D509F74EA"' + - '"0x8DA12C66AE539BB"' last-modified: - - Wed, 23 Feb 2022 03:33:53 GMT + - Thu, 31 Mar 2022 03:27:43 GMT server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 x-ms-lease-id: @@ -612,9 +612,9 @@ interactions: Connection: - keep-alive User-Agent: - - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.7.9; Windows 10) AZURECLI/2.33.1 + - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.9.6; Windows 10) AZURECLI/2.34.1 x-ms-date: - - Wed, 23 Feb 2022 03:33:55 GMT + - Thu, 31 Mar 2022 03:27:45 GMT x-ms-version: - '2018-11-09' method: GET @@ -626,11 +626,11 @@ interactions: content-length: - '0' date: - - Wed, 23 Feb 2022 03:33:56 GMT + - Thu, 31 Mar 2022 03:27:46 GMT etag: - - '"0x8D9F67D509F74EA"' + - '"0x8DA12C66AE539BB"' last-modified: - - Wed, 23 Feb 2022 03:33:53 GMT + - Thu, 31 Mar 2022 03:27:43 GMT server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 x-ms-has-immutability-policy: @@ -656,9 +656,9 @@ interactions: Content-Length: - '0' User-Agent: - - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.7.9; Windows 10) AZURECLI/2.33.1 + - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.9.6; Windows 10) AZURECLI/2.34.1 x-ms-date: - - Wed, 23 Feb 2022 03:33:57 GMT + - Thu, 31 Mar 2022 03:27:46 GMT x-ms-lease-action: - change x-ms-lease-id: @@ -676,11 +676,11 @@ interactions: content-length: - '0' date: - - Wed, 23 Feb 2022 03:33:57 GMT + - Thu, 31 Mar 2022 03:27:47 GMT etag: - - '"0x8D9F67D509F74EA"' + - '"0x8DA12C66AE539BB"' last-modified: - - Wed, 23 Feb 2022 03:33:53 GMT + - Thu, 31 Mar 2022 03:27:43 GMT server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 x-ms-lease-id: @@ -698,9 +698,9 @@ interactions: Content-Length: - '0' User-Agent: - - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.7.9; Windows 10) AZURECLI/2.33.1 + - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.9.6; Windows 10) AZURECLI/2.34.1 x-ms-date: - - Wed, 23 Feb 2022 03:33:58 GMT + - Thu, 31 Mar 2022 03:27:47 GMT x-ms-lease-action: - renew x-ms-lease-id: @@ -716,11 +716,11 @@ interactions: content-length: - '0' date: - - Wed, 23 Feb 2022 03:33:58 GMT + - Thu, 31 Mar 2022 03:27:49 GMT etag: - - '"0x8D9F67D509F74EA"' + - '"0x8DA12C66AE539BB"' last-modified: - - Wed, 23 Feb 2022 03:33:53 GMT + - Thu, 31 Mar 2022 03:27:43 GMT server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 x-ms-lease-id: @@ -736,9 +736,9 @@ interactions: Connection: - keep-alive User-Agent: - - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.7.9; Windows 10) AZURECLI/2.33.1 + - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.9.6; Windows 10) AZURECLI/2.34.1 x-ms-date: - - Wed, 23 Feb 2022 03:33:59 GMT + - Thu, 31 Mar 2022 03:27:48 GMT x-ms-version: - '2018-11-09' method: GET @@ -750,11 +750,11 @@ interactions: content-length: - '0' date: - - Wed, 23 Feb 2022 03:34:00 GMT + - Thu, 31 Mar 2022 03:27:49 GMT etag: - - '"0x8D9F67D509F74EA"' + - '"0x8DA12C66AE539BB"' last-modified: - - Wed, 23 Feb 2022 03:33:53 GMT + - Thu, 31 Mar 2022 03:27:43 GMT server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 x-ms-has-immutability-policy: @@ -780,9 +780,9 @@ interactions: Content-Length: - '0' User-Agent: - - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.7.9; Windows 10) AZURECLI/2.33.1 + - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.9.6; Windows 10) AZURECLI/2.34.1 x-ms-date: - - Wed, 23 Feb 2022 03:34:00 GMT + - Thu, 31 Mar 2022 03:27:50 GMT x-ms-lease-action: - break x-ms-lease-break-period: @@ -798,11 +798,11 @@ interactions: content-length: - '0' date: - - Wed, 23 Feb 2022 03:34:01 GMT + - Thu, 31 Mar 2022 03:27:50 GMT etag: - - '"0x8D9F67D509F74EA"' + - '"0x8DA12C66AE539BB"' last-modified: - - Wed, 23 Feb 2022 03:33:53 GMT + - Thu, 31 Mar 2022 03:27:43 GMT server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 x-ms-lease-time: @@ -818,9 +818,9 @@ interactions: Connection: - keep-alive User-Agent: - - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.7.9; Windows 10) AZURECLI/2.33.1 + - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.9.6; Windows 10) AZURECLI/2.34.1 x-ms-date: - - Wed, 23 Feb 2022 03:34:01 GMT + - Thu, 31 Mar 2022 03:27:51 GMT x-ms-version: - '2018-11-09' method: GET @@ -832,11 +832,11 @@ interactions: content-length: - '0' date: - - Wed, 23 Feb 2022 03:34:03 GMT + - Thu, 31 Mar 2022 03:27:52 GMT etag: - - '"0x8D9F67D509F74EA"' + - '"0x8DA12C66AE539BB"' last-modified: - - Wed, 23 Feb 2022 03:33:53 GMT + - Thu, 31 Mar 2022 03:27:43 GMT server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 x-ms-has-immutability-policy: @@ -860,9 +860,9 @@ interactions: Content-Length: - '0' User-Agent: - - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.7.9; Windows 10) AZURECLI/2.33.1 + - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.9.6; Windows 10) AZURECLI/2.34.1 x-ms-date: - - Wed, 23 Feb 2022 03:34:03 GMT + - Thu, 31 Mar 2022 03:27:52 GMT x-ms-lease-action: - release x-ms-lease-id: @@ -878,11 +878,11 @@ interactions: content-length: - '0' date: - - Wed, 23 Feb 2022 03:34:03 GMT + - Thu, 31 Mar 2022 03:27:53 GMT etag: - - '"0x8D9F67D509F74EA"' + - '"0x8DA12C66AE539BB"' last-modified: - - Wed, 23 Feb 2022 03:33:53 GMT + - Thu, 31 Mar 2022 03:27:43 GMT server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 x-ms-version: @@ -896,9 +896,9 @@ interactions: Connection: - keep-alive User-Agent: - - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.7.9; Windows 10) AZURECLI/2.33.1 + - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.9.6; Windows 10) AZURECLI/2.34.1 x-ms-date: - - Wed, 23 Feb 2022 03:34:04 GMT + - Thu, 31 Mar 2022 03:27:53 GMT x-ms-version: - '2018-11-09' method: GET @@ -910,11 +910,11 @@ interactions: content-length: - '0' date: - - Wed, 23 Feb 2022 03:34:05 GMT + - Thu, 31 Mar 2022 03:27:54 GMT etag: - - '"0x8D9F67D509F74EA"' + - '"0x8DA12C66AE539BB"' last-modified: - - Wed, 23 Feb 2022 03:33:53 GMT + - Thu, 31 Mar 2022 03:27:43 GMT server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 x-ms-has-immutability-policy: @@ -938,9 +938,9 @@ interactions: Content-Length: - '0' User-Agent: - - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.7.9; Windows 10) AZURECLI/2.33.1 + - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.9.6; Windows 10) AZURECLI/2.34.1 x-ms-date: - - Wed, 23 Feb 2022 03:34:05 GMT + - Thu, 31 Mar 2022 03:27:54 GMT x-ms-version: - '2018-11-09' method: DELETE @@ -952,7 +952,7 @@ interactions: content-length: - '0' date: - - Wed, 23 Feb 2022 03:34:06 GMT + - Thu, 31 Mar 2022 03:27:56 GMT server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 x-ms-version: @@ -966,9 +966,9 @@ interactions: Connection: - keep-alive User-Agent: - - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.7.9; Windows 10) AZURECLI/2.33.1 + - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.9.6; Windows 10) AZURECLI/2.34.1 x-ms-date: - - Wed, 23 Feb 2022 03:34:06 GMT + - Thu, 31 Mar 2022 03:27:56 GMT x-ms-version: - '2018-11-09' method: GET @@ -976,14 +976,14 @@ interactions: response: body: string: "\uFEFFContainerNotFoundThe - specified container does not exist.\nRequestId:65da357a-001e-0056-6066-28a286000000\nTime:2022-02-23T03:34:08.0408524Z" + specified container does not exist.\nRequestId:c7e74248-a01e-0053-70af-44c26e000000\nTime:2022-03-31T03:27:57.9042210Z" headers: content-length: - '223' content-type: - application/xml date: - - Wed, 23 Feb 2022 03:34:07 GMT + - Thu, 31 Mar 2022 03:27:57 GMT server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 x-ms-error-code: diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/recordings/test_storage_blob_generate_sas_as_user.yaml b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/recordings/test_storage_blob_generate_sas_as_user.yaml index 120ec7bab80..bf893c8e9e2 100644 --- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/recordings/test_storage_blob_generate_sas_as_user.yaml +++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/recordings/test_storage_blob_generate_sas_as_user.yaml @@ -15,12 +15,12 @@ interactions: ParameterSetName: - -n -g --query -o User-Agent: - - AZURECLI/2.33.1 azsdk-python-azure-mgmt-storage/19.1.0 Python/3.7.9 (Windows-10-10.0.22000-SP0) + - AZURECLI/2.34.1 azsdk-python-azure-mgmt-storage/19.1.0 Python/3.9.6 (Windows-10-10.0.19044-SP0) method: POST uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/listKeys?api-version=2021-08-01&$expand=kerb response: body: - string: '{"keys":[{"creationTime":"2022-02-23T03:35:24.4127485Z","keyName":"key1","value":"veryFakedStorageAccountKey==","permissions":"FULL"},{"creationTime":"2022-02-23T03:35:24.4127485Z","keyName":"key2","value":"veryFakedStorageAccountKey==","permissions":"FULL"}]}' + string: '{"keys":[{"creationTime":"2022-03-31T03:30:48.3105631Z","keyName":"key1","value":"veryFakedStorageAccountKey==","permissions":"FULL"},{"creationTime":"2022-03-31T03:30:48.3105631Z","keyName":"key2","value":"veryFakedStorageAccountKey==","permissions":"FULL"}]}' headers: cache-control: - no-cache @@ -29,7 +29,7 @@ interactions: content-type: - application/json date: - - Wed, 23 Feb 2022 03:35:45 GMT + - Thu, 31 Mar 2022 03:31:09 GMT expires: - '-1' pragma: @@ -45,7 +45,7 @@ interactions: x-content-type-options: - nosniff x-ms-ratelimit-remaining-subscription-resource-requests: - - '11997' + - '11999' status: code: 200 message: OK @@ -57,9 +57,9 @@ interactions: Content-Length: - '0' User-Agent: - - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.7.9; Windows 10) AZURECLI/2.33.1 + - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.9.6; Windows 10) AZURECLI/2.34.1 x-ms-date: - - Wed, 23 Feb 2022 03:35:45 GMT + - Thu, 31 Mar 2022 03:31:09 GMT x-ms-version: - '2018-11-09' method: PUT @@ -71,11 +71,11 @@ interactions: content-length: - '0' date: - - Wed, 23 Feb 2022 03:35:46 GMT + - Thu, 31 Mar 2022 03:31:10 GMT etag: - - '"0x8D9F67D946CEA05"' + - '"0x8DA12C6E6AD6476"' last-modified: - - Wed, 23 Feb 2022 03:35:47 GMT + - Thu, 31 Mar 2022 03:31:10 GMT server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 x-ms-version: @@ -86,68 +86,88 @@ interactions: - request: body: ' - 2022-02-23T03:35:47Z2022-02-23T04:35:00Z' + 2022-03-31T03:31:10Z2022-03-31T04:31:00Z' headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + CommandName: + - storage blob generate-sas Connection: - keep-alive Content-Length: - '130' + Content-Type: + - application/xml + ParameterSetName: + - --account-name -n -c --expiry --permissions --https-only --as-user --auth-mode User-Agent: - - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.7.9; Windows 10) AZURECLI/2.33.1 + - AZURECLI/2.34.1 azsdk-python-storage-blob/12.10.0 Python/3.9.6 (Windows-10-10.0.19044-SP0) x-ms-date: - - Wed, 23 Feb 2022 03:35:47 GMT + - Thu, 31 Mar 2022 03:31:10 GMT x-ms-version: - - '2018-11-09' + - '2021-04-10' method: POST uri: https://clitest000002.blob.core.windows.net/?restype=service&comp=userdelegationkey response: body: - string: "\uFEFF3707fb2f-ac10-4591-a04f-8b0d786ea37d54826b22-38d6-4fb2-bad9-b7b93a3e9c5a2022-02-23T03:35:47Z2022-02-23T04:35:00Zb2018-11-09fqjW+TI//Hx8pwwXoqVxcGwCFJIbzRpnNOUuDp337b4=" + string: "\uFEFFa7250e3a-0e5e-48e2-9a34-45f1f5e1a91e54826b22-38d6-4fb2-bad9-b7b93a3e9c5a2022-03-31T03:31:10Z2022-03-31T04:31:00Zb2021-04-10ixfYJq1Txt0p5biDq5D255CtzhwGdBA+S6PHUq6yHuc=" headers: content-type: - application/xml date: - - Wed, 23 Feb 2022 03:35:48 GMT + - Thu, 31 Mar 2022 03:31:12 GMT server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: - chunked x-ms-version: - - '2018-11-09' + - '2021-04-10' status: code: 200 message: OK - request: body: ' - 2022-02-23T03:35:49Z2022-02-23T04:35:00Z' + 2022-03-31T03:31:12Z2022-03-31T04:31:00Z' headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + CommandName: + - storage container generate-sas Connection: - keep-alive Content-Length: - '130' + Content-Type: + - application/xml + ParameterSetName: + - --account-name -n --expiry --permissions --https-only --as-user --auth-mode User-Agent: - - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.7.9; Windows 10) AZURECLI/2.33.1 + - AZURECLI/2.34.1 azsdk-python-storage-blob/12.10.0 Python/3.9.6 (Windows-10-10.0.19044-SP0) x-ms-date: - - Wed, 23 Feb 2022 03:35:49 GMT + - Thu, 31 Mar 2022 03:31:12 GMT x-ms-version: - - '2018-11-09' + - '2021-04-10' method: POST uri: https://clitest000002.blob.core.windows.net/?restype=service&comp=userdelegationkey response: body: - string: "\uFEFF3707fb2f-ac10-4591-a04f-8b0d786ea37d54826b22-38d6-4fb2-bad9-b7b93a3e9c5a2022-02-23T03:35:49Z2022-02-23T04:35:00Zb2018-11-095++dvd5BnKLwT2bCGpL43rJqXPydMH8A2sscIzM/xUE=" + string: "\uFEFFa7250e3a-0e5e-48e2-9a34-45f1f5e1a91e54826b22-38d6-4fb2-bad9-b7b93a3e9c5a2022-03-31T03:31:12Z2022-03-31T04:31:00Zb2021-04-10CopyGhEHSLRwQhXhwFXvQEWxsbstEjqhb9AWeYceNlU=" headers: content-type: - application/xml date: - - Wed, 23 Feb 2022 03:35:50 GMT + - Thu, 31 Mar 2022 03:31:14 GMT server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 transfer-encoding: - chunked x-ms-version: - - '2018-11-09' + - '2021-04-10' status: code: 200 message: OK diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/recordings/test_storage_blob_generate_sas_full_uri.yaml b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/recordings/test_storage_blob_generate_sas_full_uri.yaml index 96e370d1a38..5ed04cba6db 100644 --- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/recordings/test_storage_blob_generate_sas_full_uri.yaml +++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/recordings/test_storage_blob_generate_sas_full_uri.yaml @@ -15,12 +15,12 @@ interactions: ParameterSetName: - -n -g --query -o User-Agent: - - AZURECLI/2.33.1 azsdk-python-azure-mgmt-storage/19.1.0 Python/3.7.9 (Windows-10-10.0.22000-SP0) + - AZURECLI/2.34.1 azsdk-python-azure-mgmt-storage/19.1.0 Python/3.9.6 (Windows-10-10.0.19044-SP0) method: POST uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Storage/storageAccounts/clitest000002/listKeys?api-version=2021-08-01&$expand=kerb response: body: - string: '{"keys":[{"creationTime":"2022-02-23T03:35:58.7565772Z","keyName":"key1","value":"veryFakedStorageAccountKey==","permissions":"FULL"},{"creationTime":"2022-02-23T03:35:58.7565772Z","keyName":"key2","value":"veryFakedStorageAccountKey==","permissions":"FULL"}]}' + string: '{"keys":[{"creationTime":"2022-03-31T03:34:13.1240054Z","keyName":"key1","value":"veryFakedStorageAccountKey==","permissions":"FULL"},{"creationTime":"2022-03-31T03:34:13.1240054Z","keyName":"key2","value":"veryFakedStorageAccountKey==","permissions":"FULL"}]}' headers: cache-control: - no-cache @@ -29,7 +29,7 @@ interactions: content-type: - application/json date: - - Wed, 23 Feb 2022 03:36:20 GMT + - Thu, 31 Mar 2022 03:34:34 GMT expires: - '-1' pragma: @@ -45,7 +45,7 @@ interactions: x-content-type-options: - nosniff x-ms-ratelimit-remaining-subscription-resource-requests: - - '11998' + - '11999' status: code: 200 message: OK @@ -57,9 +57,9 @@ interactions: Content-Length: - '0' User-Agent: - - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.7.9; Windows 10) AZURECLI/2.33.1 + - Azure-Storage/2.0.0-2.0.1 (Python CPython 3.9.6; Windows 10) AZURECLI/2.34.1 x-ms-date: - - Wed, 23 Feb 2022 03:36:21 GMT + - Thu, 31 Mar 2022 03:34:35 GMT x-ms-version: - '2018-11-09' method: PUT @@ -71,11 +71,11 @@ interactions: content-length: - '0' date: - - Wed, 23 Feb 2022 03:36:21 GMT + - Thu, 31 Mar 2022 03:34:36 GMT etag: - - '"0x8D9F67DA97BDA6F"' + - '"0x8DA12C7617E4520"' last-modified: - - Wed, 23 Feb 2022 03:36:22 GMT + - Thu, 31 Mar 2022 03:34:36 GMT server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 x-ms-version: diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_account_scenarios.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_account_scenarios.py index d51b6441d2a..b53a9f5aca3 100644 --- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_account_scenarios.py +++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_account_scenarios.py @@ -780,13 +780,13 @@ def test_renew_account_kerb_key(self, resource_group): @ResourceGroupPreparer() @StorageAccountPreparer() def test_create_account_sas(self, resource_group, storage_account_info): - from azure.cli.core.azclierror import RequiredArgumentMissingError - with self.assertRaises(RequiredArgumentMissingError): + from azure.cli.core.azclierror import InvalidArgumentValueError + with self.assertRaises(CLIError): self.cmd('storage account generate-sas --resource-types o --services b --expiry 2000-01-01 ' '--permissions r --account-name ""') invalid_connection_string = "DefaultEndpointsProtocol=https;EndpointSuffix=core.windows.net;" - with self.assertRaises(RequiredArgumentMissingError): + with self.assertRaises(InvalidArgumentValueError): self.cmd('storage account generate-sas --resource-types o --services b --expiry 2000-01-01 ' '--permissions r --connection-string {}'.format(invalid_connection_string)) diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_sas_scenarios.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_sas_scenarios.py index 2379d55aa5b..2a8d549a905 100644 --- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_sas_scenarios.py +++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_sas_scenarios.py @@ -7,7 +7,7 @@ from azure.cli.testsdk import (LiveScenarioTest, ResourceGroupPreparer, StorageAccountPreparer, JMESPathCheck, live_only) from ..storage_test_util import StorageScenarioMixin - +from knack.util import CLIError class StorageSASScenario(StorageScenarioMixin, LiveScenarioTest): @ResourceGroupPreparer() @@ -102,16 +102,24 @@ def test_storage_blob_sas_scenario(self, resource_group, storage_account): '-otsv').output.strip() self.kwargs['con_str'] = connection_str # test sas-token for a container - sas = self.cmd('storage container generate-sas -n {container} --https-only --permissions dlrw ' + sas = self.cmd('storage container generate-sas -n {container} --https-only --permissions racwdxyltfmei ' '--connection-string {con_str} --expiry {expiry} -otsv').output.strip() self.kwargs['container_sas'] = sas + self.assertIn('sig=', sas, 'SAS token {} does not contain sig segment'.format(sas)) + self.assertIn('se=', sas, 'SAS token {} does not contain se(expiry) segment'.format(sas)) + self.assertIn('sp=racwdxyltfmei', sas, 'SAS token {} does not contain permission segment'.format(sas)) + self.assertIn('spr=https', sas, 'SAS token {} does not contain https segment'.format(sas)) self.cmd('storage blob upload -c {container} -f "{local_file}" -n {blob} ' - '--account-name {account} --sas-token "{container_sas}"') + '--account-name {account} --sas-token "{container_sas}" --overwrite') # test sas-token for a blob sas = self.cmd('storage blob generate-sas -c {container} -n {blob} --account-name {account} --https-only ' - '--permissions acdrw --expiry {expiry} -otsv').output.strip() + '--permissions racwdxytmei --expiry {expiry} -otsv').output.strip() self.kwargs['blob_sas'] = sas + self.assertIn('sig=', sas, 'SAS token {} does not contain sig segment'.format(sas)) + self.assertIn('se=', sas, 'SAS token {} does not contain se(expiry) segment'.format(sas)) + self.assertIn('sp=racwdxytmei', sas, 'SAS token {} does not contain permission segment'.format(sas)) + self.assertIn('spr=https', sas, 'SAS token {} does not contain https segment'.format(sas)) self.cmd('storage blob show -c {container} -n {blob} --account-name {account} --sas-token {blob_sas}') \ .assert_with_checks(JMESPathCheck('name', blob_name)) @@ -152,6 +160,26 @@ def test_storage_account_sas_scenario(self, resource_group, storage_account): .format(container, blob_name, storage_account, sas), checks=JMESPathCheck('exists', False)) + from azure.cli.core.azclierror import InvalidArgumentValueError + with self.assertRaises(CLIError): + self.cmd('storage account generate-sas --resource-types o --services b --expiry 2000-01-01 ' + '--permissions r --account-name ""') + + invalid_connection_string = "DefaultEndpointsProtocol=https;EndpointSuffix=core.windows.net;" + with self.assertRaises(InvalidArgumentValueError): + self.cmd('storage account generate-sas --resource-types o --services b --expiry 2000-01-01 ' + '--permissions r --connection-string {}'.format(invalid_connection_string)) + + sas = self.storage_cmd('storage account generate-sas --resource-types sco --services bqtf ' + '--expiry 2046-12-31T08:23Z --permissions rwdxylacupfti --https-only ', + account_info).output + self.assertIn('sig=', sas, 'SAS token {} does not contain sig segment'.format(sas)) + self.assertIn('se=', sas, 'SAS token {} does not contain se(expiry) segment'.format(sas)) + self.assertIn('sp=rwdxylacupfti', sas, 'SAS token {} does not contain permission segment'.format(sas)) + self.assertIn('spr=https', sas, 'SAS token {} does not contain https segment'.format(sas)) + self.assertRegex(sas, '.*ss=[bqtf]{4}.*', 'SAS token {} does not contain services segment'.format(sas)) + self.assertRegex(sas, '.*srt=[sco]{3}.*', 'SAS token {} does not contain resource type segment'.format(sas)) + @ResourceGroupPreparer() @StorageAccountPreparer(hns=True, kind='StorageV2') def test_storage_fs_sas_scenario(self, resource_group, storage_account):