Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
32 changes: 13 additions & 19 deletions src/azure-cli/azure/cli/command_modules/storage/_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
"""Table transformer for storage commands"""

from azure.cli.core.commands.transform import build_table_output
from azure.cli.core.profiles import get_sdk, ResourceType
from knack.log import get_logger

logger = get_logger(__name__)
Expand Down Expand Up @@ -104,28 +103,23 @@ def transform_boolean_for_table(result):
return result


def transform_file_directory_result(cli_ctx):
def transform_file_directory_result(result):
"""
Transform a the result returned from file and directory listing API.

This transformer add and remove properties from File and Directory objects in the given list
in order to align the object's properties so as to offer a better view to the file and dir
list.
"""
def transformer(result):
if getattr(result, 'next_marker', None):
logger.warning('Next Marker:')
logger.warning(result.next_marker)

t_file, t_dir = get_sdk(cli_ctx, ResourceType.DATA_STORAGE, 'File', 'Directory', mod='file.models')
return_list = []
for each in result:
if isinstance(each, t_file):
delattr(each, 'content')
setattr(each, 'type', 'file')
elif isinstance(each, t_dir):
setattr(each, 'type', 'dir')
return_list.append(each)

return return_list
return transformer
from ._transformers import transform_share_directory_json_output, transform_share_file_json_output
return_list = []
for each in result:
if getattr(each, 'is_directory', None):
setattr(each, 'type', 'dir')
each = transform_share_directory_json_output(each)
else:
setattr(each, 'type', 'file')
each = transform_share_file_json_output(each)
return_list.append(each)

return return_list
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

from knack.log import get_logger
from azure.cli.core.profiles import get_sdk, ResourceType

logger = get_logger(__name__)


def transform_file_directory_result(cli_ctx):
"""
Transform a the result returned from file and directory listing API.
This transformer add and remove properties from File and Directory objects in the given list
in order to align the object's properties so as to offer a better view to the file and dir
list.
"""
def transformer(result):
if getattr(result, 'next_marker', None):
logger.warning('Next Marker:')
logger.warning(result.next_marker)

t_file, t_dir = get_sdk(cli_ctx, ResourceType.DATA_STORAGE, 'File', 'Directory', mod='file.models')
return_list = []
for each in result:
if isinstance(each, t_file):
delattr(each, 'content')
setattr(each, 'type', 'file')
elif isinstance(each, t_dir):
setattr(each, 'type', 'dir')
return_list.append(each)

return return_list
return transformer
25 changes: 25 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 @@ -1654,6 +1654,21 @@
short-summary: Manage file storage directories.
"""

helps['storage directory create'] = """
type: command
short-summary: Create a new directory under the specified share or parent directory.
"""

helps['storage directory delete'] = """
type: command
short-summary: Delete the specified empty directory.
"""

helps['storage directory show'] = """
type: command
short-summary: Get all user-defined metadata and system properties for the specified directory
"""

helps['storage directory exists'] = """
type: command
short-summary: Check for the existence of a storage directory.
Expand All @@ -1679,6 +1694,16 @@
short-summary: Manage file storage directory metadata.
"""

helps['storage directory metadata show'] = """
type: command
short-summary: Get all user-defined metadata for the specified directory.
"""

helps['storage directory metadata update'] = """
type: command
short-summary: Set one or more user-defined name-value pairs for the specified directory.
"""

helps['storage entity'] = """
type: group
short-summary: Manage table storage entities.
Expand Down
31 changes: 26 additions & 5 deletions src/azure-cli/azure/cli/command_modules/storage/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -1737,12 +1737,28 @@ def load_arguments(self, _): # pylint: disable=too-many-locals, too-many-statem
"Astrix (‘*’) is a wildcard that specifies all handles.")
c.argument('snapshot', help="A string that represents the snapshot version, if applicable.")

with self.argument_context('storage directory') as c:
c.argument('directory_name', directory_type, options_list=('--name', '-n'))
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('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('directory_path', directory_type, options_list=('--name', '-n'))
c.argument('exclude_extended_info',
help='Specify to exclude "timestamps", "Etag", "Attributes", "PermissionKey" info from response')
c.extra('timeout', help='Request timeout in seconds. Applies to each call to the service.', type=int)

with self.argument_context('storage directory create') as c:
c.argument('fail_on_exist', help='Throw an exception if the directory already exists.')

with self.argument_context('storage directory exists') as c:
c.ignore('file_name')
c.argument('directory_name', required=True)
with self.argument_context('storage directory delete') as c:
c.argument('fail_not_exist', help='Throw an exception if the directory does not exist.')

with self.argument_context('storage directory metadata update') as c:
c.argument('metadata', required=False)

with self.argument_context('storage file') as c:
c.argument('file_name', file_name_type, options_list=('--name', '-n'))
Expand Down Expand Up @@ -1790,9 +1806,14 @@ 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('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)
c.argument('num_results', arg_type=num_results_type)
c.argument('marker', arg_type=marker_type)
c.argument('exclude_extended_info',
help='Specify to exclude "timestamps", "Etag", "Attributes", "PermissionKey" info from response')

with self.argument_context('storage file metadata show') as c:
c.register_path_argument()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -391,3 +391,37 @@ def transform_file_share_json_output(result):
}
new_result.update(result)
return new_result


def transform_share_directory_json_output(result):
result = todict(result)
new_result = {
"metadata": result.pop('metadata', None),
"name": result.pop('name', None),
"properties": {
"etag": result.pop('etag', None),
"lastModified": result.pop('lastModified', None),
"serverEncrypted": result.pop('serverEncrypted', None)
}
}
new_result.update(result)
return new_result


def transform_share_file_json_output(result):
result = todict(result)
new_result = {
"metadata": result.pop('metadata', None),
"name": result.pop('name', None),
"properties": {
"etag": result.pop('etag', None),
"lastModified": result.pop('lastModified', None),
"serverEncrypted": result.pop('serverEncrypted', None),
"contentLength": result.pop('size', None),
"contentRange": result.pop('contentRange', None),
"contentSettings": result.pop('contentSettings', None),
"copy": result.pop("copy", None)
}
}
new_result.update(result)
return new_result
59 changes: 38 additions & 21 deletions src/azure-cli/azure/cli/command_modules/storage/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
cf_queue_service, cf_table_service, cf_table_client,
cf_sa_blob_inventory, cf_blob_service, cf_queue_client,
cf_share_client, cf_share_service,
cf_share_file_client, cf_share_directory_client,
cf_container_lease_client)

from azure.cli.core.commands import CliCommandType
Expand Down Expand Up @@ -585,6 +586,16 @@ def get_custom_sdk(custom_module, client_factory, resource_type=ResourceType.DAT
client_factory=cf_share_service,
resource_type=ResourceType.DATA_STORAGE_FILESHARE)

directory_client_sdk = CliCommandType(
operations_tmpl='azure.multiapi.storagev2.fileshare._directory_client#ShareDirectoryClient.{}',
client_factory=cf_share_directory_client,
resource_type=ResourceType.DATA_STORAGE_FILESHARE)

file_client_sdk = CliCommandType(
operations_tmpl='azure.multiapi.storagev2.fileshare._file_client#ShareFileClient.{}',
client_factory=cf_share_file_client,
resource_type=ResourceType.DATA_STORAGE_FILESHARE)

with self.command_group('storage share-rm', command_type=file_shares_mgmt_sdk,
custom_command_type=get_custom_sdk('file',
cf_mgmt_file_shares,
Expand Down Expand Up @@ -651,35 +662,35 @@ def get_custom_sdk(custom_module, client_factory, resource_type=ResourceType.DAT
'list', 'list_acl_policies', table_transformer=transform_acl_list_output)
g.storage_custom_command('update', 'set_acl_policy')

with self.command_group('storage directory', command_type=file_sdk,
custom_command_type=get_custom_sdk('directory', file_data_service_factory)) as g:
with self.command_group('storage directory', command_type=directory_client_sdk,
custom_command_type=get_custom_sdk('directory', cf_share_directory_client)) as g:
from ._transformers import transform_share_directory_json_output
from ._format import transform_file_directory_result, transform_file_output

g.storage_command('create', 'create_directory', transform=create_boolean_result_output_transformer('created'),
table_transformer=transform_boolean_for_table)
g.storage_command('delete', 'delete_directory', transform=create_boolean_result_output_transformer('deleted'),
table_transformer=transform_boolean_for_table)
g.storage_command('show', 'get_directory_properties', table_transformer=transform_file_output,
exception_handler=show_exception_handler)
g.storage_command(
'exists', 'exists', transform=create_boolean_result_output_transformer('exists'))
g.storage_command('metadata show', 'get_directory_metadata',
exception_handler=show_exception_handler)
g.storage_custom_command('create', 'create_directory',
transform=create_boolean_result_output_transformer('created'),
table_transformer=transform_boolean_for_table)
g.storage_custom_command('delete', 'delete_directory',
transform=create_boolean_result_output_transformer('deleted'),
table_transformer=transform_boolean_for_table)
g.storage_custom_command('show', 'get_directory_properties',
transform=transform_share_directory_json_output,
table_transformer=transform_file_output,
exception_handler=show_exception_handler)
g.storage_command('exists', 'exists',
transform=create_boolean_result_output_transformer('exists'))
g.storage_command('metadata show', 'get_directory_properties',
exception_handler=show_exception_handler,
transform=lambda x: getattr(x, 'metadata', x))
g.storage_command('metadata update', 'set_directory_metadata')
g.storage_custom_command('list', 'list_share_directories',
transform=transform_file_directory_result(
self.cli_ctx),
table_transformer=transform_file_output,
doc_string_source='file#FileService.list_directories_and_files')
transform=transform_file_directory_result,
table_transformer=transform_file_output)

with self.command_group('storage file', command_type=file_sdk,
custom_command_type=get_custom_sdk('file', file_data_service_factory)) as g:
from ._format import transform_file_directory_result, transform_boolean_for_table, transform_file_output
from ._format import transform_boolean_for_table, transform_file_output
from ._transformers import transform_url
from ._exception_handler import file_related_exception_handler
g.storage_custom_command('list', 'list_share_files', transform=transform_file_directory_result(self.cli_ctx),
table_transformer=transform_file_output,
doc_string_source='file#FileService.list_directories_and_files')
g.storage_command('delete', 'delete_file', transform=create_boolean_result_output_transformer('deleted'),
table_transformer=transform_boolean_for_table)
g.storage_command('resize', 'resize_file')
Expand All @@ -705,6 +716,12 @@ def get_custom_sdk(custom_module, client_factory, resource_type=ResourceType.DAT
g.storage_custom_command('delete-batch', 'storage_file_delete_batch')
g.storage_custom_command('copy start-batch', 'storage_file_copy_batch')

with self.command_group('storage file', command_type=file_client_sdk,
custom_command_type=get_custom_sdk('file', cf_share_file_client)) as g:
g.storage_custom_command('list', 'list_share_files', client_factory=cf_share_client,
transform=transform_file_directory_result,
table_transformer=transform_file_output)

with self.command_group('storage cors', get_custom_sdk('cors', multi_service_properties_factory)) as g:
from ._transformers import transform_cors_list_output

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,8 @@ def get_custom_sdk(custom_module, client_factory, resource_type=ResourceType.DAT
with self.command_group('storage directory', command_type=file_sdk,
custom_command_type=get_custom_sdk('directory_azure_stack',
file_data_service_factory)) as g:
from ._format import transform_file_directory_result, transform_file_output
from ._format import transform_file_output
from ._format_azure_stack import transform_file_directory_result

g.storage_command('create', 'create_directory', transform=create_boolean_result_output_transformer('created'),
table_transformer=transform_boolean_for_table)
Expand All @@ -492,7 +493,7 @@ def get_custom_sdk(custom_module, client_factory, resource_type=ResourceType.DAT

with self.command_group('storage file', command_type=file_sdk,
custom_command_type=get_custom_sdk('file_azure_stack', file_data_service_factory)) as g:
from ._format import transform_file_directory_result, transform_boolean_for_table, transform_file_output
from ._format import transform_boolean_for_table, transform_file_output
from ._transformers_azure_stack import transform_url
g.storage_custom_command('list', 'list_share_files', transform=transform_file_directory_result(self.cli_ctx),
table_transformer=transform_file_output,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,42 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
from azure.cli.core.profiles import ResourceType


def list_share_directories(cmd, client, share_name, directory_name=None, timeout=None):
t_dir_properties = cmd.get_models('file.models#DirectoryProperties')
def create_directory(client, metadata=None, fail_on_exist=False, **kwargs):
from azure.core.exceptions import ResourceExistsError
try:
client.create_directory(metadata=metadata, **kwargs)
return True
except ResourceExistsError as ex:
if not fail_on_exist:
return False
raise ex

generator = client.list_directories_and_files(share_name, directory_name, timeout=timeout)
return list(f for f in generator if isinstance(f.properties, t_dir_properties))

def delete_directory(client, fail_not_exist=False, **kwargs):
from azure.core.exceptions import ResourceNotFoundError
try:
client.delete_directory(**kwargs)
return True
except ResourceNotFoundError as ex:
if not fail_not_exist:
return False
raise ex


def list_share_directories(cmd, client, exclude_extended_info=False, **kwargs):
from ..track2_util import list_generator
kwargs['include'] = [] if exclude_extended_info else ["timestamps", "Etag", "Attributes", "PermissionKey"]
generator = client.list_directories_and_files(**kwargs)
results = list_generator(pages=generator.by_page(), num_results=None)
t_dir_properties = cmd.get_models('_models#DirectoryProperties', resource_type=ResourceType.DATA_STORAGE_FILESHARE)
return list(f for f in results if isinstance(f, t_dir_properties))


def get_directory_properties(client, **kwargs):
directory = client.get_directory_properties(**kwargs)
if hasattr(directory, 'name'):
setattr(directory, 'name', client.directory_path)
return directory
Loading