Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

{Storage} Migrate storage file share to track2 #22585

Merged
merged 21 commits into from
Jun 9, 2022
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ def cf_share_service(cli_ctx, kwargs):


def cf_share_client(cli_ctx, kwargs):
return cf_share_service(cli_ctx, kwargs).get_share_client(share=kwargs.pop('share_name'),
return cf_share_service(cli_ctx, kwargs).get_share_client(share=kwargs.pop('s_name'),
evelyn-ys marked this conversation as resolved.
Show resolved Hide resolved
snapshot=kwargs.pop('snapshot', None))


Expand Down
5 changes: 5 additions & 0 deletions src/azure-cli/azure/cli/command_modules/storage/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -2923,6 +2923,11 @@
short-summary: Set service-defined properties for the specified share.
"""

helps['storage share snapshot'] = """
type: command
short-summary: Creates a snapshot of an existing share under the specified account.
jonie001 marked this conversation as resolved.
Show resolved Hide resolved
"""

helps['storage share metadata'] = """
type: group
short-summary: Manage the metadata of a file share.
Expand Down
48 changes: 31 additions & 17 deletions src/azure-cli/azure/cli/command_modules/storage/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -1634,15 +1634,23 @@ def load_arguments(self, _): # pylint: disable=too-many-locals, too-many-statem
help='A new file share name to be restored. If not specified, deleted share name will be used.')

with self.argument_context('storage share create') as c:
c.extra('share_name', share_name_type, options_list=('--name', '-n'), required=True)
c.extra('s_name', share_name_type, options_list=('--name', '-n'), required=True)
c.argument('fail_on_exist', help='Specify whether to throw an exception when the share exists. False by '
'default.')
c.argument('quota', type=int, help='Specifies the maximum size of the share, in gigabytes. Must be greater '
'than 0, and less than or equal to 5TB (5120).')

with self.argument_context('storage share url') as c:
c.argument('unc', action='store_true', help='Output UNC network path.')
c.extra('unc', action='store_true', help='Output UNC network path.')
c.argument('protocol', arg_type=get_enum_type(['http', 'https'], 'https'), help='Protocol to use.')
c.ignore('snapshot')

with self.argument_context('storage share snapshot') as c:
c.extra('metadata', nargs='+',
help='Metadata in space-separated key=value pairs. This overwrites any existing metadata.',
validator=validate_metadata)
c.extra('quota', help='Specifies the maximum size of the share, in gigabytes. Must be greater than 0, and '
'less than or equal to 5 TB (5120 GB).')

with self.argument_context('storage share list') as c:
c.argument('num_results', arg_type=num_results_type)
Expand All @@ -1658,33 +1666,38 @@ def load_arguments(self, _): # pylint: disable=too-many-locals, too-many-statem
c.ignore('name_starts_with')

with self.argument_context('storage share exists') as c:
c.extra('share_name', share_name_type, options_list=('--name', '-n'), required=True)
c.extra('s_name', share_name_type, options_list=('--name', '-n'), required=True)
c.extra('snapshot', options_list=['--snapshot'],
help='A string that represents the snapshot version, if applicable.')
c.ignore('directory_name', 'file_name')
c.extra('timeout', timeout_type)

for item in ['show', 'metadata show']:
with self.argument_context('storage share {}'.format(item)) as c:
c.extra('share_name', share_name_type, options_list=('--name', '-n'), required=True)
c.extra('s_name', share_name_type, options_list=('--name', '-n'), required=True)
c.extra('snapshot', options_list=['--snapshot'],
help='A string that represents the snapshot version, if applicable.')
c.extra('timeout', timeout_type)

for item in ['stats', 'metadata update']:
for item in ['stats', 'snapshot', 'metadata update']:
with self.argument_context('storage share {}'.format(item)) as c:
c.extra('share_name', share_name_type, options_list=('--name', '-n'), required=True)
c.extra('s_name', share_name_type, options_list=('--name', '-n'), required=True)
c.extra('timeout', timeout_type)

for item in ['create', 'delete', 'show', 'list', 'update']:
with self.argument_context('storage share policy {}'.format(item)) as c:
c.extra('s_name', share_name_type, required=True)
evelyn-ys marked this conversation as resolved.
Show resolved Hide resolved

with self.argument_context('storage share policy') as c:
from .completers import get_storage_acl_name_completion_list

t_file_svc = self.get_sdk('file#FileService')
t_share_permissions = self.get_sdk('file.models#SharePermissions')
t_share_permissions = self.get_sdk('_models#ShareSasPermissions',
resource_type=ResourceType.DATA_STORAGE_FILESHARE)

c.argument('container_name', share_name_type)
c.argument('policy_name', options_list=('--name', '-n'), help='The stored access policy name.',
completer=get_storage_acl_name_completion_list(t_file_svc, 'container_name', 'get_share_acl'))
completer=get_storage_acl_name_completion_list(t_share_service, 'container_name',
'get_share_access_policy'))

help_str = 'Allowed values: {}. Can be combined'.format(get_permission_help_string(t_share_permissions))
c.argument('permission', options_list='--permissions', help=help_str,
Expand All @@ -1693,10 +1706,11 @@ def load_arguments(self, _): # pylint: disable=too-many-locals, too-many-statem
c.argument('start', type=get_datetime_type(True),
help='start UTC datetime (Y-m-d\'T\'H:M:S\'Z\'). Defaults to time of request.')
c.argument('expiry', type=get_datetime_type(True), help='expiration UTC datetime in (Y-m-d\'T\'H:M:S\'Z\')')
c.ignore('auth_mode')

with self.argument_context('storage share delete') as c:
from .sdkutil import get_delete_file_snapshot_type_names
c.extra('share_name', share_name_type, options_list=('--name', '-n'), required=True)
c.extra('s_name', share_name_type, options_list=('--name', '-n'), required=True)
c.argument('delete_snapshots', arg_type=get_enum_type(get_delete_file_snapshot_type_names()),
help='Specify the deletion strategy when the share has snapshots.')
c.argument('fail_not_exist', help="Specify whether to throw an exception when the share doesn't exists. False "
Expand All @@ -1712,7 +1726,7 @@ def load_arguments(self, _): # pylint: disable=too-many-locals, too-many-statem
t_share_permissions = self.get_sdk('_models#ShareSasPermissions',
resource_type=ResourceType.DATA_STORAGE_FILESHARE)
c.register_sas_arguments()
c.extra('share_name', share_name_type, options_list=('--name', '-n'), required=True)
c.extra('s_name', share_name_type, options_list=('--name', '-n'), required=True)
c.argument('cache_control', help='Response header value for Cache-Control when resource is accessed using this '
'shared access signature.')
c.argument('content_disposition', help='Response header value for Content-Disposition when resource is '
Expand All @@ -1733,14 +1747,14 @@ def load_arguments(self, _): # pylint: disable=too-many-locals, too-many-statem
c.ignore('sas_token')

with self.argument_context('storage share update') as c:
c.extra('share_name', share_name_type, options_list=('--name', '-n'), required=True)
c.extra('s_name', share_name_type, options_list=('--name', '-n'), required=True)
c.argument('quota', help='Specifies the maximum size of the share, in gigabytes. Must be greater than 0, and '
'less than or equal to 5 TB (5120 GB).')
c.extra('timeout', timeout_type)

with self.argument_context('storage share list-handle') as c:
c.register_path_argument(default_file_param="", fileshare=True)
c.extra('share_name', share_name_type, options_list=('--name', '-n'), required=True)
c.extra('s_name', share_name_type, options_list=('--name', '-n'), required=True)
c.extra('marker', help='An opaque continuation token. This value can be retrieved from the '
'next_marker field of a previous generator object if max_results was '
'specified and that generator has finished enumerating results. If '
Expand All @@ -1760,7 +1774,7 @@ def load_arguments(self, _): # pylint: disable=too-many-locals, too-many-statem

with self.argument_context('storage share close-handle') as c:
c.register_path_argument(default_file_param="", fileshare=True)
c.extra('share_name', share_name_type, options_list=('--name', '-n'), required=True)
c.extra('s_name', share_name_type, options_list=('--name', '-n'), required=True)
c.extra('recursive', arg_type=get_three_state_flag(),
help="Boolean that specifies if operation should apply to the directory specified in the URI, its "
"files, with its subdirectories and their files.")
Expand All @@ -1774,13 +1788,13 @@ def load_arguments(self, _): # pylint: disable=too-many-locals, too-many-statem

for scope in ['create', 'delete', 'show', 'exists', 'metadata show', 'metadata update']:
with self.argument_context(f'storage directory {scope}') as c:
c.extra('share_name', share_name_type, required=True)
c.extra('s_name', share_name_type, required=True)
c.extra('snapshot', help="A string that represents the snapshot version, if applicable.")
c.extra('directory_path', directory_type, options_list=('--name', '-n'), required=True)
c.extra('timeout', help='Request timeout in seconds. Applies to each call to the service.', type=int)

with self.argument_context('storage directory list') as c:
c.extra('share_name', share_name_type, required=True)
c.extra('s_name', share_name_type, required=True)
c.extra('directory_path', directory_type, options_list=('--name', '-n'))
c.argument('exclude_extended_info',
help='Specify to exclude "timestamps", "Etag", "Attributes", "PermissionKey" info from response')
Expand Down Expand Up @@ -1841,7 +1855,7 @@ def load_arguments(self, _): # pylint: disable=too-many-locals, too-many-statem

with self.argument_context('storage file list') as c:
from .completers import dir_path_completer
c.extra('share_name', share_name_type, required=True)
c.extra('s_name', share_name_type, required=True)
c.extra('snapshot', help="A string that represents the snapshot version, if applicable.")
c.argument('directory_name', options_list=('--path', '-p'), help='The directory path within the file share.',
completer=dir_path_completer)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
# --------------------------------------------------------------------------------------------

import base64
from uuid import UUID

from uuid import UUID
from dateutil import parser
from knack.log import get_logger
from knack.util import todict, to_camel_case
Expand Down Expand Up @@ -396,6 +396,28 @@ def transform_file_share_json_output(result):
return new_result


def transform_acl_edit(result):
if "last_modified" in result.keys():
result["lastModified"] = result.pop("last_modified")
return result


def transform_acl_list_output_v2(result):
new_result = {}
for identifier in result['signed_identifiers']:
new_result[identifier.id] = identifier.access_policy
return new_result


def transform_acl_datetime(result):
result = todict(result)
if result['start']:
result['start'] = result["start"].split('.')[0] + '+00:00'
if result['expiry']:
result['expiry'] = result["expiry"].split('.')[0] + '+00:00'
return result


def transform_share_directory_json_output(result):
result = todict(result)
new_result = {
Expand Down
27 changes: 15 additions & 12 deletions src/azure-cli/azure/cli/command_modules/storage/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,7 @@ def get_custom_sdk(custom_module, client_factory, resource_type=ResourceType.DAT
table_transformer=transform_boolean_for_table)
g.storage_custom_command('generate-sas', 'generate_share_sas')
g.storage_custom_command('stats', 'get_share_stats')
g.storage_custom_command('snapshot', 'create_snapshot')
g.storage_command('show', 'get_share_properties', exception_handler=show_exception_handler,
transform=transform_file_share_json_output)
g.storage_custom_command('exists', 'share_exists', transform=create_boolean_result_output_transformer('exists'))
Expand All @@ -642,23 +643,25 @@ def get_custom_sdk(custom_module, client_factory, resource_type=ResourceType.DAT
ResourceType.DATA_STORAGE_FILESHARE),
resource_type=ResourceType.DATA_STORAGE_FILESHARE, min_api='2019-02-02') as g:
from ._format import transform_share_list
from ._transformers import transform_url_without_encode
g.storage_custom_command('list', 'list_shares', transform=transform_storage_list_output,
table_transformer=transform_share_list)
g.storage_custom_command('url', 'create_share_url', transform=transform_url_without_encode)

with self.command_group('storage share', command_type=file_sdk,
custom_command_type=get_custom_sdk('file', file_data_service_factory)) as g:
g.storage_command('snapshot', 'snapshot_share', min_api='2017-04-17')
g.storage_custom_command('url', 'create_share_url', transform=transform_url)

with self.command_group('storage share policy', command_type=file_sdk,
custom_command_type=get_custom_sdk('acl', file_data_service_factory)) as g:
g.storage_custom_command('create', 'create_acl_policy')
g.storage_custom_command('delete', 'delete_acl_policy')
with self.command_group('storage share policy',
custom_command_type=get_custom_sdk('access_policy', cf_share_client,
ResourceType.DATA_STORAGE_FILESHARE),
resource_type=ResourceType.DATA_STORAGE_FILESHARE, min_api='2019-02-02') as g:
from ._transformers import transform_acl_list_output, transform_acl_edit, transform_acl_list_output_v2,\
transform_acl_datetime
g.storage_custom_command('create', 'create_acl_policy', transform=transform_acl_edit)
g.storage_custom_command('delete', 'delete_acl_policy', transform=transform_acl_edit)
g.storage_custom_command(
'show', 'get_acl_policy', exception_handler=show_exception_handler)
'show', 'get_acl_policy', exception_handler=show_exception_handler, transform=transform_acl_datetime)
g.storage_custom_command(
'list', 'list_acl_policies', table_transformer=transform_acl_list_output)
g.storage_custom_command('update', 'set_acl_policy')
'list', 'list_acl_policies', transform=transform_acl_list_output_v2,
table_transformer=transform_acl_list_output)
g.storage_custom_command('update', 'set_acl_policy', transform=transform_acl_edit)

with self.command_group('storage directory', command_type=directory_client_sdk,
custom_command_type=get_custom_sdk('directory', cf_share_directory_client)) as g:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,27 @@
from azure.cli.core.profiles import ResourceType


def _str_to_datetime(time):
form = '%Y-%m-%d'
evelyn-ys marked this conversation as resolved.
Show resolved Hide resolved
try:
return datetime.strptime(time, form)
except ValueError:
pass
return time


def create_acl_policy(cmd, client, policy_name, start=None, expiry=None, permission=None, **kwargs):
"""Create a stored access policy on the containing object"""
t_access_policy = cmd.get_models('_models#AccessPolicy', resource_type=ResourceType.DATA_STORAGE_BLOB)
acl = _get_acl(cmd, client, **kwargs)
if _get_service_container_type(cmd, client) == 'share':
signed_identifiers = {}
for identifier in acl["signed_identifiers"]:
signed_identifiers[identifier.id] = identifier.access_policy
acl = signed_identifiers
acl[policy_name] = t_access_policy(permission if permission else '',
expiry if expiry else datetime.max,
start if start else datetime.utcnow())
_str_to_datetime(expiry) if expiry else datetime.max,
evelyn-ys marked this conversation as resolved.
Show resolved Hide resolved
_str_to_datetime(start) if start else datetime.utcnow())
if hasattr(acl, 'public_access'):
kwargs['public_access'] = getattr(acl, 'public_access')

Expand All @@ -23,7 +37,12 @@ def create_acl_policy(cmd, client, policy_name, start=None, expiry=None, permiss
def get_acl_policy(cmd, client, policy_name, **kwargs):
"""Show a stored access policy on a containing object"""
acl = _get_acl(cmd, client, **kwargs)
return acl.get(policy_name)
if _get_service_container_type(cmd, client) == 'share':
for identifier in acl['signed_identifiers']:
if identifier.id == policy_name:
return identifier.access_policy
else:
return acl.get(policy_name)


def list_acl_policies(cmd, client, **kwargs):
Expand All @@ -39,9 +58,21 @@ def set_acl_policy(cmd, client, policy_name, start=None, expiry=None, permission

acl = _get_acl(cmd, client, **kwargs)
try:
policy = acl[policy_name]
policy.start = start or policy.start
policy.expiry = expiry or policy.expiry
if _get_service_container_type(cmd, client) == 'share':
signed_identifiers = {}
found = False
for identifier in acl["signed_identifiers"]:
signed_identifiers[identifier.id] = identifier.access_policy
if identifier.id == policy_name:
policy = identifier.access_policy
found = True
acl = signed_identifiers
if not found:
raise KeyError()
else:
policy = acl[policy_name]
policy.start = _str_to_datetime(start) if start else policy.start
policy.expiry = _str_to_datetime(expiry) if expiry else policy.expiry
policy.permission = permission or policy.permission
if hasattr(acl, 'public_access'):
kwargs['public_access'] = getattr(acl, 'public_access')
Expand All @@ -55,7 +86,20 @@ def set_acl_policy(cmd, client, policy_name, start=None, expiry=None, permission
def delete_acl_policy(cmd, client, policy_name, **kwargs):
""" Delete a stored access policy on a containing object """
acl = _get_acl(cmd, client, **kwargs)
del acl[policy_name]
if _get_service_container_type(cmd, client) == 'share':
signed_identifiers = {}
found = False
for identifier in acl["signed_identifiers"]:
if identifier.id == policy_name:
found = True
continue
signed_identifiers[identifier.id] = identifier.access_policy
acl = signed_identifiers
if not found:
from knack.util import CLIError
raise CLIError('ACL does not contain {}'.format(policy_name))
else:
del acl[policy_name]
if hasattr(acl, 'public_access'):
kwargs['public_access'] = getattr(acl, 'public_access')

Expand Down Expand Up @@ -93,6 +137,8 @@ def _get_acl(cmd, client, **kwargs):
def convert_acl_permissions(result):
if result is None:
return None
if 'signed_identifiers' in result:
return result
for policy in sorted(result.keys()):
if getattr(result[policy], 'permission') is None:
setattr(result[policy], 'permission', '')
Expand Down
Loading