diff options
Diffstat (limited to 'openstackclient/volume')
| -rw-r--r-- | openstackclient/volume/v1/volume.py | 37 | ||||
| -rw-r--r-- | openstackclient/volume/v2/backup_record.py | 14 | ||||
| -rw-r--r-- | openstackclient/volume/v2/consistency_group.py | 45 | ||||
| -rw-r--r-- | openstackclient/volume/v2/volume.py | 37 | ||||
| -rw-r--r-- | openstackclient/volume/v3/volume_group.py | 127 |
5 files changed, 197 insertions, 63 deletions
diff --git a/openstackclient/volume/v1/volume.py b/openstackclient/volume/v1/volume.py index dfbb0c54..198b890f 100644 --- a/openstackclient/volume/v1/volume.py +++ b/openstackclient/volume/v1/volume.py @@ -224,15 +224,44 @@ class CreateVolume(command.ShowOne): if parsed_args.bootable or parsed_args.non_bootable: try: - volume_client.volumes.set_bootable( - volume.id, parsed_args.bootable) + if utils.wait_for_status( + volume_client.volumes.get, + volume.id, + success_status=['available'], + error_status=['error'], + sleep_time=1 + ): + volume_client.volumes.set_bootable( + volume.id, + parsed_args.bootable + ) + else: + msg = _( + "Volume status is not available for setting boot " + "state" + ) + raise exceptions.CommandError(msg) except Exception as e: LOG.error(_("Failed to set volume bootable property: %s"), e) if parsed_args.read_only or parsed_args.read_write: try: - volume_client.volumes.update_readonly_flag( + if utils.wait_for_status( + volume_client.volumes.get, volume.id, - parsed_args.read_only) + success_status=['available'], + error_status=['error'], + sleep_time=1 + ): + volume_client.volumes.update_readonly_flag( + volume.id, + parsed_args.read_only + ) + else: + msg = _( + "Volume status is not available for setting it" + "read only." + ) + raise exceptions.CommandError(msg) except Exception as e: LOG.error(_("Failed to set volume read-only access " "mode flag: %s"), e) diff --git a/openstackclient/volume/v2/backup_record.py b/openstackclient/volume/v2/backup_record.py index 64ff4f67..0d3af641 100644 --- a/openstackclient/volume/v2/backup_record.py +++ b/openstackclient/volume/v2/backup_record.py @@ -26,9 +26,10 @@ LOG = logging.getLogger(__name__) class ExportBackupRecord(command.ShowOne): - _description = _('Export volume backup details. Backup information can be ' - 'imported into a new service instance to be able to ' - 'restore.') + _description = _("""Export volume backup details. + +Backup information can be imported into a new service instance to be able to +restore.""") def get_parser(self, prog_name): parser = super(ExportBackupRecord, self).get_parser(prog_name) @@ -54,9 +55,10 @@ class ExportBackupRecord(command.ShowOne): class ImportBackupRecord(command.ShowOne): - _description = _('Import volume backup details. Exported backup details ' - 'contain the metadata necessary to restore to a new or ' - 'rebuilt service instance') + _description = _("""Import volume backup details. + +Exported backup details contain the metadata necessary to restore to a new or +rebuilt service instance""") def get_parser(self, prog_name): parser = super(ImportBackupRecord, self).get_parser(prog_name) diff --git a/openstackclient/volume/v2/consistency_group.py b/openstackclient/volume/v2/consistency_group.py index c50a1b5b..77da6f64 100644 --- a/openstackclient/volume/v2/consistency_group.py +++ b/openstackclient/volume/v2/consistency_group.py @@ -14,6 +14,7 @@ """Volume v2 consistency group action implementations""" +import argparse import logging from osc_lib.cli import format_columns @@ -90,35 +91,51 @@ class CreateConsistencyGroup(command.ShowOne): "name", metavar="<name>", nargs="?", - help=_("Name of new consistency group (default to None)") + help=_("Name of new consistency group (default to None)"), ) exclusive_group = parser.add_mutually_exclusive_group(required=True) exclusive_group.add_argument( "--volume-type", metavar="<volume-type>", - help=_("Volume type of this consistency group (name or ID)") + help=_("Volume type of this consistency group (name or ID)"), ) exclusive_group.add_argument( + "--source", + metavar="<consistency-group>", + help=_("Existing consistency group (name or ID)"), + ) + # NOTE(stephenfin): Legacy alias + exclusive_group.add_argument( "--consistency-group-source", metavar="<consistency-group>", - help=_("Existing consistency group (name or ID)") + dest='source', + help=argparse.SUPPRESS, + ) + exclusive_group.add_argument( + "--snapshot", + metavar="<consistency-group-snapshot>", + help=_("Existing consistency group snapshot (name or ID)"), ) + # NOTE(stephenfin): Legacy alias exclusive_group.add_argument( "--consistency-group-snapshot", metavar="<consistency-group-snapshot>", - help=_("Existing consistency group snapshot (name or ID)") + dest='snapshot', + help=argparse.SUPPRESS, ) parser.add_argument( "--description", metavar="<description>", - help=_("Description of this consistency group") + help=_("Description of this consistency group"), ) parser.add_argument( "--availability-zone", metavar="<availability-zone>", - help=_("Availability zone for this consistency group " - "(not available if creating consistency group " - "from source)"), + help=_( + "Availability zone for this consistency group " + "(not available if creating consistency group " + "from source)" + ), ) return parser @@ -142,21 +159,23 @@ class CreateConsistencyGroup(command.ShowOne): consistency_group_id = None consistency_group_snapshot = None - if parsed_args.consistency_group_source: + if parsed_args.source: consistency_group_id = utils.find_resource( volume_client.consistencygroups, - parsed_args.consistency_group_source).id - elif parsed_args.consistency_group_snapshot: + parsed_args.source, + ).id + elif parsed_args.snapshot: consistency_group_snapshot = utils.find_resource( volume_client.cgsnapshots, - parsed_args.consistency_group_snapshot).id + parsed_args.snapshot, + ).id consistency_group = ( volume_client.consistencygroups.create_from_src( consistency_group_snapshot, consistency_group_id, name=parsed_args.name, - description=parsed_args.description + description=parsed_args.description, ) ) diff --git a/openstackclient/volume/v2/volume.py b/openstackclient/volume/v2/volume.py index 7905e097..a5e5a670 100644 --- a/openstackclient/volume/v2/volume.py +++ b/openstackclient/volume/v2/volume.py @@ -257,15 +257,44 @@ class CreateVolume(command.ShowOne): if parsed_args.bootable or parsed_args.non_bootable: try: - volume_client.volumes.set_bootable( - volume.id, parsed_args.bootable) + if utils.wait_for_status( + volume_client.volumes.get, + volume.id, + success_status=['available'], + error_status=['error'], + sleep_time=1 + ): + volume_client.volumes.set_bootable( + volume.id, + parsed_args.bootable + ) + else: + msg = _( + "Volume status is not available for setting boot " + "state" + ) + raise exceptions.CommandError(msg) except Exception as e: LOG.error(_("Failed to set volume bootable property: %s"), e) if parsed_args.read_only or parsed_args.read_write: try: - volume_client.volumes.update_readonly_flag( + if utils.wait_for_status( + volume_client.volumes.get, volume.id, - parsed_args.read_only) + success_status=['available'], + error_status=['error'], + sleep_time=1 + ): + volume_client.volumes.update_readonly_flag( + volume.id, + parsed_args.read_only + ) + else: + msg = _( + "Volume status is not available for setting it" + "read only." + ) + raise exceptions.CommandError(msg) except Exception as e: LOG.error(_("Failed to set volume read-only access " "mode flag: %s"), e) diff --git a/openstackclient/volume/v3/volume_group.py b/openstackclient/volume/v3/volume_group.py index 69b18ceb..242ffcd4 100644 --- a/openstackclient/volume/v3/volume_group.py +++ b/openstackclient/volume/v3/volume_group.py @@ -10,7 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. -import logging +import argparse from cinderclient import api_versions from osc_lib.command import command @@ -19,8 +19,6 @@ from osc_lib import utils from openstackclient.i18n import _ -LOG = logging.getLogger(__name__) - def _format_group(group): columns = ( @@ -82,19 +80,72 @@ class CreateVolumeGroup(command.ShowOne): def get_parser(self, prog_name): parser = super().get_parser(prog_name) + # This is a bit complicated. We accept two patterns: a legacy pattern + # + # volume group create \ + # <volume-group-type> <volume-type> [<volume-type>...] + # + # and the modern approach + # + # volume group create \ + # --volume-group-type <volume-group-type> + # --volume-type <volume-type> + # [--volume-type <volume-type> ...] + # + # Because argparse doesn't properly support nested exclusive groups, we + # use two groups: one to ensure users don't pass <volume-group-type> as + # both a positional and an option argument and another to ensure users + # don't pass <volume-type> this way. It's a bit weird but it catches + # everything we care about. source_parser = parser.add_mutually_exclusive_group() + # we use a different name purely so we can issue a deprecation warning source_parser.add_argument( - 'volume_group_type', + 'volume_group_type_legacy', metavar='<volume_group_type>', nargs='?', - help=_('Name or ID of volume group type to use.'), + help=argparse.SUPPRESS, ) - parser.add_argument( - 'volume_types', + volume_types_parser = parser.add_mutually_exclusive_group() + # We need to use a separate dest + # https://github.com/python/cpython/issues/101990 + volume_types_parser.add_argument( + 'volume_types_legacy', metavar='<volume_type>', nargs='*', default=[], - help=_('Name or ID of volume type(s) to use.'), + help=argparse.SUPPRESS, + ) + source_parser.add_argument( + '--volume-group-type', + metavar='<volume_group_type>', + help=_('Volume group type to use (name or ID)'), + ) + volume_types_parser.add_argument( + '--volume-type', + metavar='<volume_type>', + dest='volume_types', + action='append', + default=[], + help=_( + 'Volume type(s) to use (name or ID) ' + '(required with --volume-group-type)' + ), + ) + source_parser.add_argument( + '--source-group', + metavar='<source-group>', + help=_( + 'Existing volume group to use (name or ID) ' + '(supported by --os-volume-api-version 3.14 or later)' + ), + ) + source_parser.add_argument( + '--group-snapshot', + metavar='<group-snapshot>', + help=_( + 'Existing group snapshot to use (name or ID) ' + '(supported by --os-volume-api-version 3.14 or later)' + ), ) parser.add_argument( '--name', @@ -109,59 +160,63 @@ class CreateVolumeGroup(command.ShowOne): parser.add_argument( '--availability-zone', metavar='<availability-zone>', - help=_('Availability zone for volume group. ' - '(not available if creating group from source)'), - ) - source_parser.add_argument( - '--source-group', - metavar='<source-group>', - help=_('Existing volume group (name or ID) ' - '(supported by --os-volume-api-version 3.14 or later)'), - ) - source_parser.add_argument( - '--group-snapshot', - metavar='<group-snapshot>', - help=_('Existing group snapshot (name or ID) ' - '(supported by --os-volume-api-version 3.14 or later)'), + help=_( + 'Availability zone for volume group. ' + '(not available if creating group from source)' + ), ) return parser def take_action(self, parsed_args): volume_client = self.app.client_manager.volume - if parsed_args.volume_group_type: + if parsed_args.volume_group_type_legacy: + msg = _( + "Passing volume group type and volume types as positional " + "arguments is deprecated. Use the --volume-group-type and " + "--volume-type option arguments instead." + ) + self.log.warning(msg) + + volume_group_type = parsed_args.volume_group_type or \ + parsed_args.volume_group_type_legacy + volume_types = parsed_args.volume_types[:] + volume_types.extend(parsed_args.volume_types_legacy) + + if volume_group_type: if volume_client.api_version < api_versions.APIVersion('3.13'): msg = _( "--os-volume-api-version 3.13 or greater is required to " "support the 'volume group create' command" ) raise exceptions.CommandError(msg) - if not parsed_args.volume_types: + if not volume_types: msg = _( - "<volume_types> is a required argument when creating a " + "--volume-types is a required argument when creating a " "group from group type." ) raise exceptions.CommandError(msg) - volume_group_type = utils.find_resource( + volume_group_type_id = utils.find_resource( volume_client.group_types, - parsed_args.volume_group_type, - ) - volume_types = [] - for volume_type in parsed_args.volume_types: - volume_types.append( + volume_group_type, + ).id + volume_types_ids = [] + for volume_type in volume_types: + volume_types_ids.append( utils.find_resource( volume_client.volume_types, volume_type, - ) + ).id ) group = volume_client.groups.create( - volume_group_type.id, - ','.join(x.id for x in volume_types), + volume_group_type_id, + ','.join(volume_types_ids), parsed_args.name, parsed_args.description, - availability_zone=parsed_args.availability_zone) + availability_zone=parsed_args.availability_zone, + ) group = volume_client.groups.get(group.id) return _format_group(group) @@ -186,7 +241,7 @@ class CreateVolumeGroup(command.ShowOne): if parsed_args.availability_zone: msg = _("'--availability-zone' option will not work " "if creating group from source.") - LOG.warning(msg) + self.log.warning(msg) source_group = None if parsed_args.source_group: |
