Skip to content

Commit 7dd0f54

Browse files
authored
[Storage] Fix #29929: az storage copy: Fix when wildcard * is in --source-file-path (#30569)
* fix `az storage copy` with wildcard '*' in source share file path * fix cases when * is in --source-file-path * fix cases when * is in --source-blob or --source-container
1 parent 6632120 commit 7dd0f54

File tree

2 files changed

+83
-16
lines changed

2 files changed

+83
-16
lines changed

src/azure-cli/azure/cli/command_modules/storage/_validators.py

+16-6
Original file line numberDiff line numberDiff line change
@@ -2025,18 +2025,28 @@ def get_url_with_sas(cmd, namespace, url=None, container=None, blob=None, share=
20252025
client = cf_blob_service(cmd.cli_ctx, kwargs)
20262026
if blob is None:
20272027
blob = ''
2028-
from .operations.blob import create_blob_url
2029-
url = create_blob_url(client, container, blob, snapshot=None)
2028+
if '*' in container or '*' in blob:
2029+
url = client.url
2030+
if not url.endswith('/'):
2031+
url = url + '/'
2032+
url = url + container + '/' + blob
2033+
else:
2034+
from .operations.blob import create_blob_url
2035+
url = create_blob_url(client, container, blob, snapshot=None)
20302036
service = 'blob'
20312037
elif share:
20322038
if hasattr(namespace, 'enable_file_backup_request_intent'):
20332039
kwargs.update({'enable_file_backup_request_intent': namespace.enable_file_backup_request_intent})
20342040
client = cf_share_service(cmd.cli_ctx, kwargs)
20352041
client = client.get_share_client(share)
2036-
dir_name, file_name = os.path.split(file_path) if file_path else (None, '')
2037-
dir_name = None if dir_name in ('', '.') else dir_name
2038-
from .operations.file import create_file_url
2039-
url = create_file_url(client, directory_name=dir_name, file_name=file_name)
2042+
# if wildcard '*' in file path, skip manually parsing the url
2043+
if file_path and '*' in file_path:
2044+
url = client.url + '/' + file_path
2045+
else:
2046+
dir_name, file_name = os.path.split(file_path) if file_path else (None, '')
2047+
dir_name = None if dir_name in ('', '.') else dir_name
2048+
from .operations.file import create_file_url
2049+
url = create_file_url(client, directory_name=dir_name, file_name=file_name)
20402050
service = 'file'
20412051
elif not any([url, container, share]): # In account level, only blob service is supported
20422052
service = 'blob'

src/azure-cli/azure/cli/command_modules/storage/tests/latest/test_storage_azcopy_scenarios.py

+67-10
Original file line numberDiff line numberDiff line change
@@ -615,9 +615,8 @@ def test_storage_azcopy_blob_url(self, resource_group, first_account, second_acc
615615
local_file = self.create_temp_file(20480.5)
616616
self.cmd('disk create -n {} -g {} --for-upload --upload-size-bytes 20972032'
617617
.format(diskname, resource_group))
618-
sasURL = self.cmd(
619-
'disk grant-access --access-level Write --duration-in-seconds 3600 -n {} -g {} --query accessSas -o tsv'
620-
.format(diskname, resource_group)).output.strip('\n')
618+
sasURL = self.cmd('disk grant-access --access-level Write --duration-in-seconds 3600 -n {} -g {} -o tsv'
619+
.format(diskname, resource_group)).output.strip('\n')
621620
self.cmd('storage copy -s "{}" -d "{}" --blob-type PageBlob'
622621
.format(local_file, sasURL))
623622

@@ -632,6 +631,7 @@ def test_storage_azcopy_blob_account(self, resource_group, first_account, second
632631

633632
first_container = self.create_container(first_account_info)
634633
second_container = self.create_container(second_account_info)
634+
third_container = self.create_container(second_account_info)
635635

636636
first_account_url = 'https://{}.blob.core.windows.net'.format(first_account)
637637

@@ -708,13 +708,20 @@ def test_storage_azcopy_blob_account(self, resource_group, first_account, second
708708
.format(second_container, second_account), checks=JMESPathCheck('length(@)', 11))
709709

710710
# Copy an entire storage account data to another blob account
711-
self.cmd('storage copy --source-account-name {} --destination-account-name {} --recursive --preserve-s2s-access-tier false'
712-
.format(first_account, second_account))
711+
self.cmd('storage copy --source-account-name {} --destination-account-name {} --recursive '
712+
'--preserve-s2s-access-tier false'.format(first_account, second_account))
713713
self.cmd('storage container list --account-name {}'
714-
.format(second_account), checks=JMESPathCheck('length(@)', 2))
714+
.format(second_account), checks=JMESPathCheck('length(@)', 3))
715715
self.cmd('storage blob list -c {} --account-name {}'
716716
.format(first_container, second_account), checks=JMESPathCheck('length(@)', 22))
717717

718+
# Copy an entire directory from blob virtual directory to another blob virtual directory with wildcard
719+
self.cmd('storage copy --source-account-name {} --source-container {} --source-blob {} '
720+
'--destination-account-name {} --destination-container {} --recursive --preserve-s2s-access-tier false'
721+
.format(second_account, second_container, 'apple/*', second_account, third_container))
722+
self.cmd('storage blob list -c {} --account-name {}'
723+
.format(third_container, second_account), checks=JMESPathCheck('length(@)', 10))
724+
718725
@ResourceGroupPreparer()
719726
@StorageAccountPreparer(parameter_name='first_account')
720727
@StorageAccountPreparer(parameter_name='second_account', sku='Premium_LRS', kind='BlockBlobStorage')
@@ -881,6 +888,26 @@ def test_storage_azcopy_file_account(self, resource_group, storage_account_info,
881888
self.assertEqual(3, sum(len(d) for r, d, f in os.walk(local_folder)))
882889
self.assertEqual(21, sum(len(f) for r, d, f in os.walk(local_folder)))
883890

891+
# Copy with wildcard *
892+
self.cmd('storage directory create -s {} -n {} --account-name {}'.format(share, 'parent', storage_account))
893+
self.cmd('storage directory create -s {} -n {} --account-name {}'
894+
.format(share, 'parent/source', storage_account))
895+
self.cmd('storage copy --source-local-path "{}" --destination-account-name {} --destination-share {} '
896+
'--destination-file-path {} --recursive'
897+
.format(os.path.join(test_dir, 'butter/file_*'), storage_account, share, 'parent/source'))
898+
self.cmd('storage copy --source-account-name {} --source-share {} --source-file-path {} --account-name {} '
899+
'--destination-share {} --destination-file-path {} --recursive -- --as-subdir=false'
900+
.format(storage_account, share, 'parent/source/*', storage_account, share, 'parent/target'))
901+
self.cmd('storage file list -s {} --path {} --account-name {}'.format(
902+
share, 'parent/target', storage_account), checks=JMESPathCheck('length(@)', 10))
903+
self.cmd('storage copy --source-account-name {} --source-share {} --source-file-path {} --account-name {} '
904+
'--destination-share {} --destination-file-path {} --recursive -- --as-subdir=false'
905+
.format(storage_account, share, 'parent/*', storage_account, share, 'parentdst'))
906+
self.cmd('storage file list -s {} --path {} --account-name {}'
907+
.format(share, 'parentdst/source', storage_account), checks=JMESPathCheck('length(@)', 10))
908+
self.cmd('storage file list -s {} --path {} --account-name {}'
909+
.format(share, 'parentdst/target', storage_account), checks=JMESPathCheck('length(@)', 10))
910+
884911
@ResourceGroupPreparer()
885912
@StorageAccountPreparer(parameter_name='first_account', allow_shared_key_access=False)
886913
@StorageAccountPreparer(parameter_name='second_account', sku='Premium_LRS', kind='BlockBlobStorage',
@@ -972,9 +999,8 @@ def test_storage_azcopy_blob_url_oauth(self, resource_group, first_account, seco
972999
local_file = self.create_temp_file(20480.5)
9731000
self.cmd('disk create -n {} -g {} --for-upload --upload-size-bytes 20972032'
9741001
.format(diskname, resource_group))
975-
sasURL = self.cmd(
976-
'disk grant-access --access-level Write --duration-in-seconds 3600 -n {} -g {} --query accessSas -o tsv'
977-
.format(diskname, resource_group)).output.strip('\n')
1002+
sasURL = self.cmd('disk grant-access --access-level Write --duration-in-seconds 3600 -n {} -g {} -o tsv'
1003+
.format(diskname, resource_group)).output.strip('\n')
9781004
self.oauth_cmd('storage copy -s "{}" -d "{}" --blob-type PageBlob'.format(
9791005
local_file, sasURL))
9801006

@@ -986,8 +1012,10 @@ def test_storage_azcopy_blob_url_oauth(self, resource_group, first_account, seco
9861012
def test_storage_azcopy_blob_account_oauth(self, resource_group, first_account, second_account, test_dir):
9871013
first_container = self.create_random_name(prefix='container', length=24)
9881014
second_container = self.create_random_name(prefix='container', length=24)
1015+
third_container = self.create_random_name(prefix='container', length=24)
9891016
self.oauth_cmd('storage container create -n {} --account-name {}', first_container, first_account)
9901017
self.oauth_cmd('storage container create -n {} --account-name {}', second_container, second_account)
1018+
self.oauth_cmd('storage container create -n {} --account-name {}', third_container, second_account)
9911019

9921020
first_account_url = 'https://{}.blob.core.windows.net'.format(first_account)
9931021

@@ -1072,10 +1100,18 @@ def test_storage_azcopy_blob_account_oauth(self, resource_group, first_account,
10721100
'--preserve-s2s-access-tier false'.format(
10731101
first_account, second_account))
10741102
self.oauth_cmd('storage container list --account-name {}'.format(
1075-
second_account), checks=JMESPathCheck('length(@)', 2))
1103+
second_account), checks=JMESPathCheck('length(@)', 3))
10761104
self.oauth_cmd('storage blob list -c {} --account-name {}'.format(
10771105
first_container, second_account), checks=JMESPathCheck('length(@)', 22))
10781106

1107+
# Copy an entire directory from blob virtual directory to another blob virtual directory with wildcard
1108+
self.oauth_cmd('storage copy --source-account-name {} --source-container {} --source-blob {} '
1109+
'--destination-account-name {} --destination-container {} --recursive '
1110+
'--preserve-s2s-access-tier false'
1111+
.format(second_account, second_container, 'apple/*', second_account, third_container))
1112+
self.oauth_cmd('storage blob list -c {} --account-name {}'
1113+
.format(third_container, second_account), checks=JMESPathCheck('length(@)', 10))
1114+
10791115
@ResourceGroupPreparer()
10801116
@StorageAccountPreparer(parameter_name='first_account', allow_shared_key_access=False)
10811117
@StorageAccountPreparer(parameter_name='second_account', sku='Premium_LRS', kind='BlockBlobStorage',
@@ -1236,3 +1272,24 @@ def test_storage_azcopy_file_account_oauth(self, resource_group, storage_account
12361272
storage_account, share, local_folder))
12371273
self.assertEqual(3, sum(len(d) for r, d, f in os.walk(local_folder)))
12381274
self.assertEqual(21, sum(len(f) for r, d, f in os.walk(local_folder)))
1275+
1276+
# Copy with wildcard *
1277+
self.file_oauth_cmd('storage directory create -s {} -n {} --account-name {}'
1278+
.format(share, 'parent', storage_account))
1279+
self.file_oauth_cmd('storage directory create -s {} -n {} --account-name {}'
1280+
.format(share, 'parent/source', storage_account))
1281+
self.oauth_cmd('storage copy --source-local-path "{}" --destination-account-name {} --destination-share {} '
1282+
'--destination-file-path {} --recursive'
1283+
.format(os.path.join(test_dir, 'butter/file_*'), storage_account, share, 'parent/source'))
1284+
self.cmd('storage copy --source-account-name {} --source-share {} --source-file-path {} --account-name {} '
1285+
'--destination-share {} --destination-file-path {} --recursive --auth-mode login -- --as-subdir=false'
1286+
.format(storage_account, share, 'parent/source/*', storage_account, share, 'parent/target'))
1287+
self.file_oauth_cmd('storage file list -s {} --path {} --account-name {}'
1288+
.format(share, 'parent/target', storage_account), checks=JMESPathCheck('length(@)', 10))
1289+
self.cmd('storage copy --source-account-name {} --source-share {} --source-file-path {} --account-name {} '
1290+
'--destination-share {} --destination-file-path {} --recursive --auth-mode login -- --as-subdir=false'
1291+
.format(storage_account, share, 'parent/*', storage_account, share, 'parentdst'))
1292+
self.file_oauth_cmd('storage file list -s {} --path {} --account-name {}'
1293+
.format(share, 'parentdst/source', storage_account), checks=JMESPathCheck('length(@)', 10))
1294+
self.file_oauth_cmd('storage file list -s {} --path {} --account-name {}'
1295+
.format(share, 'parentdst/target', storage_account), checks=JMESPathCheck('length(@)', 10))

0 commit comments

Comments
 (0)