Skip to content

Commit 42086ea

Browse files
authored
{Storage} Make storage batch tests non-live so CI can catch issues (#32143)
1 parent b80331e commit 42086ea

14 files changed

Lines changed: 278683 additions & 8083 deletions

src/azure-cli/azure/cli/command_modules/storage/operations/blob.py

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,9 @@ def storage_blob_copy_batch(cmd, client, source_client, container_name=None, des
374374
if source_container:
375375
# copy blobs for blob container, skip empty dir
376376
# pylint: disable=inconsistent-return-statements
377+
if source_client is None:
378+
source_client = client
379+
377380
def action_blob_copy(blob_name):
378381
if dryrun:
379382
logger.warning(' - copy blob %s', blob_name)
@@ -392,12 +395,25 @@ def action_blob_copy(blob_name):
392395
if source_share:
393396
# copy blob from file share, skip empty dir
394397
# pylint: disable=inconsistent-return-statements
398+
if source_client is None:
399+
t_share_service = get_sdk(cmd.cli_ctx, ResourceType.DATA_STORAGE_FILESHARE,
400+
'_share_service_client#ShareServiceClient')
401+
account_url = client.url.replace('blob', 'file')
402+
if client.credential and client.credential.account_key:
403+
credential = {
404+
"account_name": client.credential.account_name,
405+
"account_key": client.credential.account_key
406+
}
407+
source_client = t_share_service(account_url=account_url, credential=credential)
408+
else:
409+
source_client = t_share_service(account_url=account_url, credential=client.credential)
410+
395411
def action_file_copy(file_info):
396412
dir_name, file_name = file_info
397413
if dryrun:
398-
logger.warning(' - copy file %s', os.path.join(dir_name, file_name))
414+
logger.warning(' - copy file %s', '/'.join(dir_name, file_name))
399415
else:
400-
return _copy_file_to_blob_container(client, source_client, container_name, destination_path,
416+
return _copy_file_to_blob_container(cmd, client, source_client, container_name, destination_path,
401417
source_share, source_sas, dir_name, file_name)
402418

403419
return list(filter_none(action_file_copy(file) for file in collect_files_track2(source_client,
@@ -908,16 +924,21 @@ def create_blob_url(client, container_name, blob_name, snapshot, protocol='https
908924
def _copy_blob_to_blob_container(cmd, blob_service, source_blob_service, destination_container, destination_path,
909925
source_container, source_blob_name, source_sas, **kwargs):
910926
t_blob_client = cmd.get_models('_blob_client#BlobClient')
911-
# generate sas for oauth copy source
912-
if not source_sas:
913-
from ..util import create_short_lived_blob_sas_v2
914-
start = datetime.utcnow()
915-
expiry = datetime.utcnow() + timedelta(hours=1)
916-
source_user_delegation_key = source_blob_service.get_user_delegation_key(start, expiry)
917-
source_sas = create_short_lived_blob_sas_v2(cmd, source_blob_service.account_name, source_container,
918-
source_blob_name, user_delegation_key=source_user_delegation_key)
919-
source_client = t_blob_client(account_url=source_blob_service.url, container_name=source_container,
920-
blob_name=source_blob_name, credential=source_sas)
927+
# if blob_service and source_blob_service are the same
928+
if blob_service == source_blob_service:
929+
source_client = source_blob_service.get_blob_client(container=source_container, blob=source_blob_name)
930+
else:
931+
# generate sas for oauth copy source
932+
if not source_sas:
933+
from ..util import create_short_lived_blob_sas_v2
934+
start = datetime.utcnow()
935+
expiry = datetime.utcnow() + timedelta(days=1)
936+
source_user_delegation_key = source_blob_service.get_user_delegation_key(start, expiry)
937+
source_sas = create_short_lived_blob_sas_v2(cmd, source_blob_service.account_name, source_container,
938+
source_blob_name,
939+
user_delegation_key=source_user_delegation_key)
940+
source_client = t_blob_client(account_url=source_blob_service.url, container_name=source_container,
941+
blob_name=source_blob_name, credential=source_sas)
921942
source_blob_url = source_client.url
922943

923944
destination_blob_name = normalize_blob_file_path(destination_path, source_blob_name)
@@ -935,16 +956,30 @@ def _copy_blob_to_blob_container(cmd, blob_service, source_blob_service, destina
935956
raise CLIError(error_template.format(source_blob_name, destination_container, ex))
936957

937958

938-
def _copy_file_to_blob_container(blob_service, source_file_service, destination_container, destination_path,
959+
def _copy_file_to_blob_container(cmd, blob_service, source_file_service, destination_container, destination_path,
939960
source_share, source_sas, source_file_dir, source_file_name):
940961
t_share_client = source_file_service.get_share_client(source_share)
941-
t_file_client = t_share_client.get_file_client(os.path.join(source_file_dir, source_file_name))
962+
source_path = os.path.join(source_file_dir, source_file_name) if source_file_dir else source_file_name
963+
source_path = normalize_blob_file_path(None, source_path)
964+
t_file_client = t_share_client.get_file_client(source_path)
965+
if source_sas is None:
966+
t_generate_share_sas = get_sdk(cmd.cli_ctx, ResourceType.DATA_STORAGE_FILESHARE,
967+
'_shared_access_signature#generate_share_sas')
968+
t_file_permissions = get_sdk(cmd.cli_ctx, ResourceType.DATA_STORAGE_FILESHARE,
969+
'_models#FileSasPermissions')
970+
start = datetime.utcnow()
971+
expiry = datetime.utcnow() + timedelta(days=1)
972+
source_sas = t_generate_share_sas(account_name=t_file_client.account_name, share_name=source_share,
973+
account_key=t_file_client.credential.account_key,
974+
permission=t_file_permissions(read=True),
975+
expiry=expiry, start=start)
976+
from urllib.parse import quote
977+
source_sas = quote(source_sas, safe='&%()$=\',~')
942978
if '?' not in t_file_client.url:
943979
source_file_url = '{}?{}'.format(t_file_client.url, source_sas)
944980
else:
945981
source_file_url = t_file_client.url
946982

947-
source_path = os.path.join(source_file_dir, source_file_name) if source_file_dir else source_file_name
948983
destination_blob_name = normalize_blob_file_path(destination_path, source_path)
949984
try:
950985
blob_client = blob_service.get_blob_client(container=destination_container, blob=destination_blob_name)

src/azure-cli/azure/cli/command_modules/storage/operations/file.py

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ def _upload_action(src, dst2):
184184
dir_name = os.path.dirname(dst2)
185185
file_name = os.path.basename(dst2)
186186

187-
_make_directory_in_files_share(client, destination, dir_name, V2=True)
187+
_make_directory_in_files_share(client, dir_name)
188188

189189
logger.warning('uploading %s', src)
190190
storage_file_upload(client.get_file_client(dst2), src, content_settings, metadata, validate_content,
@@ -233,7 +233,7 @@ def storage_file_download_batch(client, source, destination, pattern=None, dryru
233233
Download files from file share to local directory in batch
234234
"""
235235

236-
from azure.cli.command_modules.storage.util import glob_files_remotely_track2
236+
from azure.cli.command_modules.storage.util import glob_files_remotely_track2, normalize_blob_file_path
237237

238238
source_files = glob_files_remotely_track2(client, source, pattern, is_share_client=True)
239239

@@ -255,12 +255,13 @@ def storage_file_download_batch(client, source, destination, pattern=None, dryru
255255
def _download_action(pair):
256256
path = os.path.join(*pair)
257257
local_path = os.path.join(destination, *pair)
258+
path = normalize_blob_file_path(None, path)
258259
file_client = client.get_file_client(path)
259260

260261
download_file(file_client, destination_path=local_path, max_connections=max_connections,
261262
progress_callback=progress_callback, validate_content=validate_content)
262263

263-
return file_client.url.replace('%5C', '/')
264+
return file_client.url
264265

265266
return list(_download_action(f) for f in source_files)
266267

@@ -298,6 +299,19 @@ def storage_file_copy_batch(cmd, client, source_client, share_name=None, destina
298299
# repeatedly create existing directory so as to optimize the performance.
299300
existing_dirs = set()
300301

302+
if source_client is None:
303+
t_blob_service_client = get_sdk(cmd.cli_ctx, ResourceType.DATA_STORAGE_BLOB,
304+
'_blob_service_client#BlobServiceClient')
305+
account_url = '/'.join(client.url.replace('file', 'blob').split('/')[:-1])
306+
if client.credential and client.credential.account_key:
307+
credential = {
308+
"account_name": client.credential.account_name,
309+
"account_key": client.credential.account_key
310+
}
311+
source_client = t_blob_service_client(account_url=account_url, credential=credential)
312+
else:
313+
source_client = t_blob_service_client(account_url=account_url, credential=client.credential)
314+
301315
# pylint: disable=inconsistent-return-statements
302316
def action_blob_copy(blob_name):
303317
if dryrun:
@@ -318,6 +332,12 @@ def action_blob_copy(blob_name):
318332
# repeatedly create existing directory so as to optimize the performance.
319333
existing_dirs = set()
320334

335+
if source_client is None:
336+
t_share_service = get_sdk(cmd.cli_ctx, ResourceType.DATA_STORAGE_FILESHARE,
337+
'_share_service_client#ShareServiceClient')
338+
account_url = '/'.join(client.url.split('/')[:-1])
339+
source_client = t_share_service(account_url=account_url, credential=client.credential)
340+
321341
# pylint: disable=inconsistent-return-statements
322342
def action_file_copy(file_info):
323343
dir_name, file_name = file_info
@@ -339,9 +359,11 @@ def storage_file_delete_batch(client, source, pattern=None, dryrun=False, timeou
339359
"""
340360
Delete files from file share in batch
341361
"""
362+
from azure.cli.command_modules.storage.util import normalize_blob_file_path
342363

343364
def delete_action(pair):
344365
path = os.path.join(*pair)
366+
path = normalize_blob_file_path(None, path)
345367
file_client = client.get_file_client(path)
346368
return file_client.delete_file(timeout=timeout)
347369

@@ -362,6 +384,7 @@ def delete_action(pair):
362384
delete_action(f)
363385

364386

387+
# pylint: disable=too-many-locals
365388
def _create_file_and_directory_from_blob(cmd, file_service, blob_service, share, container, sas, blob_name,
366389
destination_dir=None, metadata=None, timeout=None, existing_dirs=None):
367390
"""
@@ -371,13 +394,29 @@ def _create_file_and_directory_from_blob(cmd, file_service, blob_service, share,
371394
from azure.cli.command_modules.storage.util import normalize_blob_file_path
372395

373396
t_blob_client = cmd.get_models('_blob_client#BlobClient', resource_type=ResourceType.DATA_STORAGE_BLOB)
397+
if sas is None:
398+
t_generate_blob_sas = get_sdk(cmd.cli_ctx, ResourceType.DATA_STORAGE_BLOB,
399+
'_shared_access_signature#generate_blob_sas')
400+
t_blob_permissions = get_sdk(cmd.cli_ctx, ResourceType.DATA_STORAGE_BLOB,
401+
'_models#BlobSasPermissions')
402+
from datetime import datetime, timedelta
403+
start = datetime.utcnow()
404+
expiry = datetime.utcnow() + timedelta(days=1)
405+
source_sas = t_generate_blob_sas(account_name=blob_service.account_name, container_name=container,
406+
blob_name=blob_name,
407+
account_key=blob_service.credential.account_key,
408+
permission=t_blob_permissions(read=True),
409+
expiry=expiry, start=start)
410+
from urllib.parse import quote
411+
sas = quote(source_sas, safe='&%()$=\',~')
412+
374413
source_client = t_blob_client(account_url=blob_service.url, container_name=container,
375414
blob_name=blob_name, credential=sas)
376415
blob_url = source_client.url
377416

378417
full_path = normalize_blob_file_path(destination_dir, blob_name)
379418
dir_name = os.path.dirname(full_path)
380-
_make_directory_in_files_share(file_service, share, dir_name, existing_dirs, V2=True)
419+
_make_directory_in_files_share(file_service, dir_name, existing_dirs)
381420

382421
try:
383422
file_client = file_service.get_file_client(full_path)
@@ -390,6 +429,7 @@ def _create_file_and_directory_from_blob(cmd, file_service, blob_service, share,
390429
raise CLIError(error_template.format(blob_name, share))
391430

392431

432+
# pylint: disable=too-many-locals
393433
def _create_file_and_directory_from_file(cmd, file_service, source_file_service, share, source_share, sas,
394434
source_file_dir, source_file_name, destination_dir=None, metadata=None,
395435
timeout=None, existing_dirs=None):
@@ -403,14 +443,29 @@ def _create_file_and_directory_from_file(cmd, file_service, source_file_service,
403443
if source_file_dir:
404444
file_path = source_file_dir + '/' + file_path
405445
t_file_client = cmd.get_models('_file_client#ShareFileClient', resource_type=ResourceType.DATA_STORAGE_FILESHARE)
446+
if sas is None:
447+
t_generate_share_sas = get_sdk(cmd.cli_ctx, ResourceType.DATA_STORAGE_FILESHARE,
448+
'_shared_access_signature#generate_share_sas')
449+
t_file_permissions = get_sdk(cmd.cli_ctx, ResourceType.DATA_STORAGE_FILESHARE,
450+
'_models#FileSasPermissions')
451+
from datetime import datetime, timedelta
452+
start = datetime.utcnow()
453+
expiry = datetime.utcnow() + timedelta(days=1)
454+
source_sas = t_generate_share_sas(account_name=source_file_service.account_name, share_name=source_share,
455+
account_key=source_file_service.credential.account_key,
456+
permission=t_file_permissions(read=True),
457+
expiry=expiry, start=start)
458+
from urllib.parse import quote
459+
sas = quote(source_sas, safe='&%()$=\',~')
460+
406461
source_client = t_file_client(account_url=source_file_service.url, share_name=source_share, file_path=file_path,
407462
credential=sas)
408463
file_url = source_client.url
409464

410465
full_path = normalize_blob_file_path(destination_dir, os.path.join(source_file_dir, source_file_name))
411466
file_name = os.path.basename(full_path)
412467
dir_name = os.path.dirname(full_path)
413-
_make_directory_in_files_share(file_service, share, dir_name, existing_dirs, V2=True)
468+
_make_directory_in_files_share(file_service, dir_name, existing_dirs)
414469

415470
try:
416471
file_client = file_service.get_file_client(full_path)
@@ -423,7 +478,7 @@ def _create_file_and_directory_from_file(cmd, file_service, source_file_service,
423478
raise CLIError(error_template.format(file_name, source_share, share))
424479

425480

426-
def _make_directory_in_files_share(file_service, file_share, directory_path, existing_dirs=None, V2=False):
481+
def _make_directory_in_files_share(file_service, directory_path, existing_dirs=None):
427482
"""
428483
Create directories recursively.
429484
This method accept a existing_dirs set which serves as the cache of existing directory. If the
@@ -446,10 +501,7 @@ def _make_directory_in_files_share(file_service, file_share, directory_path, exi
446501
continue
447502

448503
try:
449-
if V2:
450-
file_service.create_directory(directory_name=dir_name)
451-
else:
452-
file_service.create_directory(share_name=file_share, directory_name=dir_name, fail_on_exist=False)
504+
file_service.create_directory(directory_name=dir_name)
453505
except ResourceExistsError:
454506
pass
455507
except AzureHttpError:

0 commit comments

Comments
 (0)