diff options
| author | Akihiro Motoki <amotoki@gmail.com> | 2017-05-15 10:19:07 +0000 |
|---|---|---|
| committer | Dean Troyer <dtroyer@gmail.com> | 2019-06-22 14:56:10 -0500 |
| commit | 4cd614305fbe8b90d45ad6803bfa8b7978f19318 (patch) | |
| tree | 07fe89ab1115ba759a1ee91dd9f8158568a74115 /openstackclient/volume | |
| parent | 1a21f02bc7507120f3a4fe2af12ba7a27b002b44 (diff) | |
| download | python-openstackclient-4cd614305fbe8b90d45ad6803bfa8b7978f19318.tar.gz | |
Use cliff formattable columns in volume v2 commands
Partial-Bug: #1687955
Partially implement blueprint osc-formattable-columns
Change-Id: I761ccac126208927594ad0d98a3cf5ad8b44bd48
Diffstat (limited to 'openstackclient/volume')
| -rw-r--r-- | openstackclient/volume/v2/consistency_group.py | 3 | ||||
| -rw-r--r-- | openstackclient/volume/v2/qos_specs.py | 13 | ||||
| -rw-r--r-- | openstackclient/volume/v2/volume.py | 62 | ||||
| -rw-r--r-- | openstackclient/volume/v2/volume_backup.py | 45 | ||||
| -rw-r--r-- | openstackclient/volume/v2/volume_snapshot.py | 54 | ||||
| -rw-r--r-- | openstackclient/volume/v2/volume_type.py | 61 |
6 files changed, 169 insertions, 69 deletions
diff --git a/openstackclient/volume/v2/consistency_group.py b/openstackclient/volume/v2/consistency_group.py index 0a932f84..26dd8ffc 100644 --- a/openstackclient/volume/v2/consistency_group.py +++ b/openstackclient/volume/v2/consistency_group.py @@ -16,6 +16,7 @@ import logging +from osc_lib.cli import format_columns from osc_lib.command import command from osc_lib import exceptions from osc_lib import utils @@ -238,7 +239,7 @@ class ListConsistencyGroup(command.Lister): return (columns, ( utils.get_item_properties( s, columns, - formatters={'Volume Types': utils.format_list}) + formatters={'Volume Types': format_columns.ListColumn}) for s in consistency_groups)) diff --git a/openstackclient/volume/v2/qos_specs.py b/openstackclient/volume/v2/qos_specs.py index c7160581..3037d34a 100644 --- a/openstackclient/volume/v2/qos_specs.py +++ b/openstackclient/volume/v2/qos_specs.py @@ -17,6 +17,7 @@ import logging +from osc_lib.cli import format_columns from osc_lib.cli import parseractions from osc_lib.command import command from osc_lib import exceptions @@ -96,7 +97,8 @@ class CreateQos(command.ShowOne): qos_spec = volume_client.qos_specs.create(parsed_args.name, specs) qos_spec._info.update( - {'properties': utils.format_dict(qos_spec._info.pop('specs'))} + {'properties': + format_columns.DictColumn(qos_spec._info.pop('specs'))} ) return zip(*sorted(six.iteritems(qos_spec._info))) @@ -210,8 +212,8 @@ class ListQos(command.Lister): (utils.get_dict_properties( s._info, columns, formatters={ - 'Specs': utils.format_dict, - 'Associations': utils.format_list + 'Specs': format_columns.DictColumn, + 'Associations': format_columns.ListColumn }, ) for s in qos_specs_list)) @@ -267,10 +269,11 @@ class ShowQos(command.ShowOne): associations = [association.name for association in qos_associations] qos_spec._info.update({ - 'associations': utils.format_list(associations) + 'associations': format_columns.ListColumn(associations) }) qos_spec._info.update( - {'properties': utils.format_dict(qos_spec._info.pop('specs'))}) + {'properties': + format_columns.DictColumn(qos_spec._info.pop('specs'))}) return zip(*sorted(six.iteritems(qos_spec._info))) diff --git a/openstackclient/volume/v2/volume.py b/openstackclient/volume/v2/volume.py index ef65d097..17ccd3d3 100644 --- a/openstackclient/volume/v2/volume.py +++ b/openstackclient/volume/v2/volume.py @@ -16,8 +16,11 @@ import argparse import copy +import functools import logging +from cliff import columns as cliff_columns +from osc_lib.cli import format_columns from osc_lib.cli import parseractions from osc_lib.command import command from osc_lib import exceptions @@ -31,6 +34,37 @@ from openstackclient.identity import common as identity_common LOG = logging.getLogger(__name__) +class AttachmentsColumn(cliff_columns.FormattableColumn): + """Formattable column for attachments column. + + Unlike the parent FormattableColumn class, the initializer of the + class takes server_cache as the second argument. + osc_lib.utils.get_item_properties instantiate cliff FormattableColumn + object with a single parameter "column value", so you need to pass + a partially initialized class like + ``functools.partial(AttachmentsColumn, server_cache)``. + """ + + def __init__(self, value, server_cache=None): + super(AttachmentsColumn, self).__init__(value) + self._server_cache = server_cache or {} + + def human_readable(self): + """Return a formatted string of a volume's attached instances + + :rtype: a string of formatted instances + """ + + msg = '' + for attachment in self._value: + server = attachment['server_id'] + if server in self._server_cache.keys(): + server = self._server_cache[server].name + device = attachment['device'] + msg += 'Attached to %s on %s ' % (server, device) + return msg + + def _check_size_arg(args): """Check whether --size option is required or not. @@ -212,7 +246,8 @@ class CreateVolume(command.ShowOne): # Remove key links from being displayed volume._info.update( { - 'properties': utils.format_dict(volume._info.pop('metadata')), + 'properties': + format_columns.DictColumn(volume._info.pop('metadata')), 'type': volume._info.pop('volume_type') } ) @@ -331,22 +366,6 @@ class ListVolume(command.Lister): compute_client = self.app.client_manager.compute identity_client = self.app.client_manager.identity - def _format_attach(attachments): - """Return a formatted string of a volume's attached instances - - :param attachments: a volume.attachments field - :rtype: a string of formatted instances - """ - - msg = '' - for attachment in attachments: - server = attachment['server_id'] - if server in server_cache: - server = server_cache[server].name - device = attachment['device'] - msg += 'Attached to %s on %s ' % (server, device) - return msg - if parsed_args.long: columns = [ 'ID', @@ -381,6 +400,8 @@ class ListVolume(command.Lister): except Exception: # Just forget it if there's any trouble pass + AttachmentsColumnWithCache = functools.partial( + AttachmentsColumn, server_cache=server_cache) project_id = None if parsed_args.project: @@ -417,8 +438,8 @@ class ListVolume(command.Lister): return (column_headers, (utils.get_item_properties( s, columns, - formatters={'Metadata': utils.format_dict, - 'Attachments': _format_attach}, + formatters={'Metadata': format_columns.DictColumn, + 'Attachments': AttachmentsColumnWithCache}, ) for s in data)) @@ -722,7 +743,8 @@ class ShowVolume(command.ShowOne): # 'volume_type' --> 'type' volume._info.update( { - 'properties': utils.format_dict(volume._info.pop('metadata')), + 'properties': + format_columns.DictColumn(volume._info.pop('metadata')), 'type': volume._info.pop('volume_type'), }, ) diff --git a/openstackclient/volume/v2/volume_backup.py b/openstackclient/volume/v2/volume_backup.py index 1d2b0cde..4d0d54c1 100644 --- a/openstackclient/volume/v2/volume_backup.py +++ b/openstackclient/volume/v2/volume_backup.py @@ -15,8 +15,10 @@ """Volume v2 Backup action implementations""" import copy +import functools import logging +from cliff import columns as cliff_columns from osc_lib.cli import parseractions from osc_lib.command import command from osc_lib import exceptions @@ -29,6 +31,33 @@ from openstackclient.i18n import _ LOG = logging.getLogger(__name__) +class VolumeIdColumn(cliff_columns.FormattableColumn): + """Formattable column for volume ID column. + + Unlike the parent FormattableColumn class, the initializer of the + class takes volume_cache as the second argument. + osc_lib.utils.get_item_properties instantiate cliff FormattableColumn + object with a single parameter "column value", so you need to pass + a partially initialized class like + ``functools.partial(VolumeIdColumn, volume_cache)``. + """ + + def __init__(self, value, volume_cache=None): + super(VolumeIdColumn, self).__init__(value) + self._volume_cache = volume_cache or {} + + def human_readable(self): + """Return a volume name if available + + :rtype: either the volume ID or name + """ + volume_id = self._value + volume = volume_id + if volume_id in self._volume_cache.keys(): + volume = self._volume_cache[volume_id].name + return volume + + class CreateVolumeBackup(command.ShowOne): _description = _("Create new volume backup") @@ -189,18 +218,6 @@ class ListVolumeBackup(command.Lister): def take_action(self, parsed_args): volume_client = self.app.client_manager.volume - def _format_volume_id(volume_id): - """Return a volume name if available - - :param volume_id: a volume ID - :rtype: either the volume ID or name - """ - - volume = volume_id - if volume_id in volume_cache.keys(): - volume = volume_cache[volume_id].name - return volume - if parsed_args.long: columns = ['ID', 'Name', 'Description', 'Status', 'Size', 'Availability Zone', 'Volume ID', 'Container'] @@ -218,6 +235,8 @@ class ListVolumeBackup(command.Lister): except Exception: # Just forget it if there's any trouble pass + _VolumeIdColumn = functools.partial(VolumeIdColumn, + volume_cache=volume_cache) filter_volume_id = None if parsed_args.volume: @@ -242,7 +261,7 @@ class ListVolumeBackup(command.Lister): return (column_headers, (utils.get_item_properties( s, columns, - formatters={'Volume ID': _format_volume_id}, + formatters={'Volume ID': _VolumeIdColumn}, ) for s in data)) diff --git a/openstackclient/volume/v2/volume_snapshot.py b/openstackclient/volume/v2/volume_snapshot.py index fe969410..2b26ae32 100644 --- a/openstackclient/volume/v2/volume_snapshot.py +++ b/openstackclient/volume/v2/volume_snapshot.py @@ -15,8 +15,11 @@ """Volume v2 snapshot action implementations""" import copy +import functools import logging +from cliff import columns as cliff_columns +from osc_lib.cli import format_columns from osc_lib.cli import parseractions from osc_lib.command import command from osc_lib import exceptions @@ -30,6 +33,33 @@ from openstackclient.identity import common as identity_common LOG = logging.getLogger(__name__) +class VolumeIdColumn(cliff_columns.FormattableColumn): + """Formattable column for volume ID column. + + Unlike the parent FormattableColumn class, the initializer of the + class takes volume_cache as the second argument. + osc_lib.utils.get_item_properties instantiate cliff FormattableColumn + object with a single parameter "column value", so you need to pass + a partially initialized class like + ``functools.partial(VolumeIdColumn, volume_cache)``. + """ + + def __init__(self, value, volume_cache=None): + super(VolumeIdColumn, self).__init__(value) + self._volume_cache = volume_cache or {} + + def human_readable(self): + """Return a volume name if available + + :rtype: either the volume ID or name + """ + volume_id = self._value + volume = volume_id + if volume_id in self._volume_cache.keys(): + volume = self._volume_cache[volume_id].name + return volume + + class CreateVolumeSnapshot(command.ShowOne): _description = _("Create new volume snapshot") @@ -107,7 +137,8 @@ class CreateVolumeSnapshot(command.ShowOne): metadata=parsed_args.property, ) snapshot._info.update( - {'properties': utils.format_dict(snapshot._info.pop('metadata'))} + {'properties': + format_columns.DictColumn(snapshot._info.pop('metadata'))} ) return zip(*sorted(six.iteritems(snapshot._info))) @@ -216,18 +247,6 @@ class ListVolumeSnapshot(command.Lister): volume_client = self.app.client_manager.volume identity_client = self.app.client_manager.identity - def _format_volume_id(volume_id): - """Return a volume name if available - - :param volume_id: a volume ID - :rtype: either the volume ID or name - """ - - volume = volume_id - if volume_id in volume_cache.keys(): - volume = volume_cache[volume_id].name - return volume - if parsed_args.long: columns = ['ID', 'Name', 'Description', 'Status', 'Size', 'Created At', 'Volume ID', 'Metadata'] @@ -246,6 +265,8 @@ class ListVolumeSnapshot(command.Lister): except Exception: # Just forget it if there's any trouble pass + _VolumeIdColumn = functools.partial(VolumeIdColumn, + volume_cache=volume_cache) volume_id = None if parsed_args.volume: @@ -279,8 +300,8 @@ class ListVolumeSnapshot(command.Lister): return (column_headers, (utils.get_item_properties( s, columns, - formatters={'Metadata': utils.format_dict, - 'Volume ID': _format_volume_id}, + formatters={'Metadata': format_columns.DictColumn, + 'Volume ID': _VolumeIdColumn}, ) for s in data)) @@ -402,7 +423,8 @@ class ShowVolumeSnapshot(command.ShowOne): snapshot = utils.find_resource( volume_client.volume_snapshots, parsed_args.snapshot) snapshot._info.update( - {'properties': utils.format_dict(snapshot._info.pop('metadata'))} + {'properties': + format_columns.DictColumn(snapshot._info.pop('metadata'))} ) return zip(*sorted(six.iteritems(snapshot._info))) diff --git a/openstackclient/volume/v2/volume_type.py b/openstackclient/volume/v2/volume_type.py index 749d1dd6..54b1f497 100644 --- a/openstackclient/volume/v2/volume_type.py +++ b/openstackclient/volume/v2/volume_type.py @@ -14,8 +14,11 @@ """Volume v2 Type action implementations""" +import functools import logging +from cliff import columns as cliff_columns +from osc_lib.cli import format_columns from osc_lib.cli import parseractions from osc_lib.command import command from osc_lib import exceptions @@ -29,6 +32,36 @@ from openstackclient.identity import common as identity_common LOG = logging.getLogger(__name__) +class EncryptionInfoColumn(cliff_columns.FormattableColumn): + """Formattable column for encryption info column. + + Unlike the parent FormattableColumn class, the initializer of the + class takes encryption_data as the second argument. + osc_lib.utils.get_item_properties instantiate cliff FormattableColumn + object with a single parameter "column value", so you need to pass + a partially initialized class like + ``functools.partial(EncryptionInfoColumn encryption_data)``. + """ + + def __init__(self, value, encryption_data=None): + super(EncryptionInfoColumn, self).__init__(value) + self._encryption_data = encryption_data or {} + + def _get_encryption_info(self): + type_id = self._value + return self._encryption_data.get(type_id) + + def human_readable(self): + encryption_info = self._get_encryption_info() + if encryption_info: + return utils.format_dict(encryption_info) + else: + return '-' + + def machine_readable(self): + return self._get_encryption_info() + + def _create_encryption_type(volume_client, volume_type, parsed_args): if not parsed_args.encryption_provider: msg = _("'--encryption-provider' should be specified while " @@ -183,7 +216,8 @@ class CreateVolumeType(command.ShowOne): LOG.error(msg % {'project': parsed_args.project, 'e': e}) if parsed_args.property: result = volume_type.set_keys(parsed_args.property) - volume_type._info.update({'properties': utils.format_dict(result)}) + volume_type._info.update( + {'properties': format_columns.DictColumn(result)}) if (parsed_args.encryption_provider or parsed_args.encryption_cipher or parsed_args.encryption_key_size or @@ -198,7 +232,7 @@ class CreateVolumeType(command.ShowOne): # add encryption info in result encryption._info.pop("volume_type_id", None) volume_type._info.update( - {'encryption': utils.format_dict(encryption._info)}) + {'encryption': format_columns.DictColumn(encryption._info)}) volume_type._info.pop("os-volume-type-access:is_public", None) return zip(*sorted(six.iteritems(volume_type._info))) @@ -296,12 +330,7 @@ class ListVolumeType(command.Lister): data = volume_client.volume_types.list( is_public=is_public) - def _format_encryption_info(type_id, encryption_data=None): - encryption_data = encryption - encryption_info = '-' - if type_id in encryption_data.keys(): - encryption_info = encryption_data[type_id] - return encryption_info + formatters = {'Extra Specs': format_columns.DictColumn} if parsed_args.encryption_type: encryption = {} @@ -318,18 +347,21 @@ class ListVolumeType(command.Lister): for key in del_key: d._info.pop(key, None) # save the encryption information with their volume type ID - encryption[volume_type_id] = utils.format_dict(d._info) + encryption[volume_type_id] = d._info # We need to get volume type ID, then show encryption # information according to the ID, so use "id" to keep # difference to the real "ID" column. columns += ['id'] column_headers += ['Encryption'] + _EncryptionInfoColumn = functools.partial( + EncryptionInfoColumn, encryption_data=encryption) + formatters['id'] = _EncryptionInfoColumn + return (column_headers, (utils.get_item_properties( s, columns, - formatters={'Extra Specs': utils.format_dict, - 'id': _format_encryption_info}, + formatters=formatters, ) for s in data)) @@ -490,7 +522,7 @@ class ShowVolumeType(command.ShowOne): volume_client = self.app.client_manager.volume volume_type = utils.find_resource( volume_client.volume_types, parsed_args.volume_type) - properties = utils.format_dict( + properties = format_columns.DictColumn( volume_type._info.pop('extra_specs', {})) volume_type._info.update({'properties': properties}) access_project_ids = None @@ -502,7 +534,7 @@ class ShowVolumeType(command.ShowOne): for item in volume_type_access] # TODO(Rui Chen): This format list case can be removed after # patch https://review.opendev.org/#/c/330223/ merged. - access_project_ids = utils.format_list(project_ids) + access_project_ids = format_columns.ListColumn(project_ids) except Exception as e: msg = _('Failed to get access project list for volume type ' '%(type)s: %(e)s') @@ -515,7 +547,8 @@ class ShowVolumeType(command.ShowOne): volume_type.id) encryption._info.pop("volume_type_id", None) volume_type._info.update( - {'encryption': utils.format_dict(encryption._info)}) + {'encryption': + format_columns.DictColumn(encryption._info)}) except Exception as e: LOG.error(_("Failed to display the encryption information " "of this volume type: %s"), e) |
