From 55ca9d33e5a100bdec4d54332f86f24ccf44311a Mon Sep 17 00:00:00 2001 From: Zunli Hu Date: Mon, 5 Jul 2021 14:12:22 +0800 Subject: [PATCH 1/3] fix sas issue --- .../cli/command_modules/storage/_validators.py | 12 +++++++++--- .../azure/cli/command_modules/storage/util.py | 13 +++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) 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 ddef933669e..0ca5c84e776 100644 --- a/src/azure-cli/azure/cli/command_modules/storage/_validators.py +++ b/src/azure-cli/azure/cli/command_modules/storage/_validators.py @@ -210,7 +210,7 @@ def process_blob_source_uri(cmd, namespace): """ Validate the parameters referenced to a blob source and create the source URI from them. """ - from .util import create_short_lived_blob_sas + from .util import create_short_lived_blob_sas, create_short_lived_file_sas usage_string = \ 'Invalid usage: {}. Supply only one of the following argument sets to specify source:' \ '\n\t --source-uri' \ @@ -388,7 +388,7 @@ def validate_source_uri(cmd, namespace): # pylint: disable=too-many-statements def validate_source_url(cmd, namespace): # pylint: disable=too-many-statements - from .util import create_short_lived_blob_sas, create_short_lived_file_sas + from .util import create_short_lived_blob_sas, create_short_lived_blob_sas_v2, create_short_lived_file_sas from azure.cli.core.azclierror import InvalidArgumentValueError, RequiredArgumentMissingError, \ MutuallyExclusiveArgumentError usage_string = \ @@ -472,7 +472,13 @@ def validate_source_url(cmd, namespace): # pylint: disable=too-many-statements source_sas = create_short_lived_file_sas(cmd, source_account_name, source_account_key, share, dir_name, file_name) elif valid_blob_source and (ns.get('share_name', None) or not same_account): - source_sas = create_short_lived_blob_sas(cmd, source_account_name, source_account_key, container, blob) + prefix = cmd.command_kwargs['resource_type'].value[0] + # is_storagev2() is used to distinguish if the command is in track2 SDK + # If yes, we will use get_login_credentials() as token credential + if is_storagev2(prefix): + source_sas = create_short_lived_blob_sas_v2(cmd, source_account_name, source_account_key, container, blob) + else: + source_sas = create_short_lived_blob_sas(cmd, source_account_name, source_account_key, container, blob) query_params = [] if source_sas: diff --git a/src/azure-cli/azure/cli/command_modules/storage/util.py b/src/azure-cli/azure/cli/command_modules/storage/util.py index f0aac7480f4..36b2c150606 100644 --- a/src/azure-cli/azure/cli/command_modules/storage/util.py +++ b/src/azure-cli/azure/cli/command_modules/storage/util.py @@ -5,6 +5,7 @@ import os +from azure.cli.core.profiles import ResourceType def collect_blobs(blob_service, container, pattern=None): @@ -116,6 +117,18 @@ def create_short_lived_blob_sas(cmd, account_name, account_key, container, blob) return sas.generate_blob(container, blob, permission=t_blob_permissions(read=True), expiry=expiry, protocol='https') +def create_short_lived_blob_sas_v2(cmd, account_name, account_key, container, blob): + from datetime import datetime, timedelta + + t_sas = cmd.get_models('_shared_access_signature#BlobSharedAccessSignature', + resource_type=ResourceType.DATA_STORAGE_BLOB) + + t_blob_permissions = cmd.get_models('_models#BlobSasPermissions', resource_type=ResourceType.DATA_STORAGE_BLOB) + expiry = (datetime.utcnow() + timedelta(days=1)).strftime('%Y-%m-%dT%H:%M:%SZ') + sas = t_sas(account_name, account_key) + return sas.generate_blob(container, blob, permission=t_blob_permissions(read=True), expiry=expiry, protocol='https') + + def create_short_lived_file_sas(cmd, account_name, account_key, share, directory_name, file_name): from datetime import datetime, timedelta if cmd.supported_api_version(min_api='2017-04-17'): From 61a139358346ed3f65906f1283a75e5df4d5e0b6 Mon Sep 17 00:00:00 2001 From: Zunli Hu Date: Mon, 5 Jul 2021 14:34:06 +0800 Subject: [PATCH 2/3] test pass --- .../test_storage_blob_copy_scenarios.py | 39 ++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_copy_scenarios.py b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_copy_scenarios.py index 6fd9dbc3aa4..7d03e6d6264 100644 --- a/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_copy_scenarios.py +++ b/src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_blob_copy_scenarios.py @@ -134,23 +134,36 @@ def test_storage_blob_copy_same_account_sas(self, resource_group, storage_accoun self.assertEqual(expect_content, actual_content) @ResourceGroupPreparer() - @StorageAccountPreparer(kind='storageV2') - def test_storage_blob_copy_requires_sync(self, resource_group, storage_account): + @StorageAccountPreparer(parameter_name='account1', kind='storageV2') + @StorageAccountPreparer(parameter_name='account2', kind='storageV2') + def test_storage_blob_copy_requires_sync(self, resource_group, account1, account2): source_file = self.create_temp_file(16, full_random=True) - account_info = self.get_account_info(resource_group, storage_account) + account1_info = self.get_account_info(resource_group, account1) + account2_info = self.get_account_info(resource_group, account2) - source_container = self.create_container(account_info) - target_container = self.create_container(account_info) + # Prepare + source_container = self.create_container(account1_info) + target_container1 = self.create_container(account1_info) + target_container2 = self.create_container(account2_info) - self.storage_cmd('storage blob upload -c {} -f "{}" -n src', account_info, + self.storage_cmd('storage blob upload -c {} -f "{}" -n src', account1_info, source_container, source_file) - source_uri = self.storage_cmd('storage blob url -c {} -n src', account_info, source_container).output - self.storage_cmd('storage blob copy start -b dst -c {} --source-uri {}', account_info, - target_container, source_uri) - self.storage_cmd('storage blob upload -c {} -f "{}" -n pagesrc --type page', account_info, + # with different account name and account key + self.storage_cmd('storage blob copy start --destination-blob dst --destination-container {} ' + '--source-account-name {} --source-container {} --source-blob src --requires-sync true', + account2_info, target_container2, account1, source_container) + + # with source uri in the same account + source_uri = self.storage_cmd('storage blob url -c {} -n src', account1_info, source_container).output + self.storage_cmd('storage blob copy start -b dst -c {} --source-uri {}', account1_info, + target_container1, source_uri) + + self.storage_cmd('storage blob upload -c {} -f "{}" -n pagesrc --type page', account1_info, source_container, source_file) - source_uri = self.storage_cmd('storage blob url -c {} -n pagesrc', account_info, source_container).output + source_uri = self.storage_cmd('storage blob url -c {} -n pagesrc', account1_info, source_container).output # expect failure with page blob - self.storage_cmd_negative('storage blob copy start -b dst -c {} --source-uri {} --requires-sync', account_info, - target_container, source_uri) + self.storage_cmd_negative('storage blob copy start -b dst -c {} --source-uri {} --requires-sync', account1_info, + target_container1, source_uri) + + From 5bb6bfe4ca9e0e67e010481d0058f7f139f0d297 Mon Sep 17 00:00:00 2001 From: Zunli Hu Date: Mon, 5 Jul 2021 14:40:18 +0800 Subject: [PATCH 3/3] fix style --- .../azure/cli/command_modules/storage/_validators.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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 0ca5c84e776..5af3038a683 100644 --- a/src/azure-cli/azure/cli/command_modules/storage/_validators.py +++ b/src/azure-cli/azure/cli/command_modules/storage/_validators.py @@ -210,7 +210,7 @@ def process_blob_source_uri(cmd, namespace): """ Validate the parameters referenced to a blob source and create the source URI from them. """ - from .util import create_short_lived_blob_sas, create_short_lived_file_sas + from .util import create_short_lived_blob_sas usage_string = \ 'Invalid usage: {}. Supply only one of the following argument sets to specify source:' \ '\n\t --source-uri' \ @@ -387,7 +387,7 @@ def validate_source_uri(cmd, namespace): # pylint: disable=too-many-statements namespace.copy_source = uri -def validate_source_url(cmd, namespace): # pylint: disable=too-many-statements +def validate_source_url(cmd, namespace): # pylint: disable=too-many-statements, too-many-locals from .util import create_short_lived_blob_sas, create_short_lived_blob_sas_v2, create_short_lived_file_sas from azure.cli.core.azclierror import InvalidArgumentValueError, RequiredArgumentMissingError, \ MutuallyExclusiveArgumentError @@ -476,7 +476,8 @@ def validate_source_url(cmd, namespace): # pylint: disable=too-many-statements # is_storagev2() is used to distinguish if the command is in track2 SDK # If yes, we will use get_login_credentials() as token credential if is_storagev2(prefix): - source_sas = create_short_lived_blob_sas_v2(cmd, source_account_name, source_account_key, container, blob) + source_sas = create_short_lived_blob_sas_v2(cmd, source_account_name, source_account_key, container, + blob) else: source_sas = create_short_lived_blob_sas(cmd, source_account_name, source_account_key, container, blob)