diff options
Diffstat (limited to 'openstackclient/volume/v3/volume_group.py')
-rw-r--r-- | openstackclient/volume/v3/volume_group.py | 182 |
1 files changed, 148 insertions, 34 deletions
diff --git a/openstackclient/volume/v3/volume_group.py b/openstackclient/volume/v3/volume_group.py index db4e9a94..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,17 +80,72 @@ class CreateVolumeGroup(command.ShowOne): def get_parser(self, prog_name): parser = super().get_parser(prog_name) - parser.add_argument( - 'volume_group_type', + # 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_legacy', metavar='<volume_group_type>', - help=_('Name or ID of volume group type to use.'), + nargs='?', + 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=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>', - nargs='+', + dest='volume_types', + action='append', default=[], - help=_('Name or ID of volume type(s) to use.'), + 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', @@ -107,44 +160,105 @@ class CreateVolumeGroup(command.ShowOne): parser.add_argument( '--availability-zone', metavar='<availability-zone>', - help=_('Availability zone for volume group.'), + 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 volume_client.api_version < api_versions.APIVersion('3.13'): + if parsed_args.volume_group_type_legacy: msg = _( - "--os-volume-api-version 3.13 or greater is required to " - "support the 'volume group create' command" + "Passing volume group type and volume types as positional " + "arguments is deprecated. Use the --volume-group-type and " + "--volume-type option arguments instead." ) - raise exceptions.CommandError(msg) + self.log.warning(msg) - volume_group_type = utils.find_resource( - volume_client.group_types, - parsed_args.volume_group_type, - ) + 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) - volume_types = [] - for volume_type in parsed_args.volume_types: - volume_types.append( - utils.find_resource( - volume_client.volume_types, - volume_type, + 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 volume_types: + msg = _( + "--volume-types is a required argument when creating a " + "group from group type." + ) + raise exceptions.CommandError(msg) - group = volume_client.groups.create( - volume_group_type.id, - ','.join(x.id for x in volume_types), - parsed_args.name, - parsed_args.description, - availability_zone=parsed_args.availability_zone) + volume_group_type_id = utils.find_resource( + volume_client.group_types, + 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.get(group.id) + group = volume_client.groups.create( + volume_group_type_id, + ','.join(volume_types_ids), + parsed_args.name, + parsed_args.description, + availability_zone=parsed_args.availability_zone, + ) - return _format_group(group) + group = volume_client.groups.get(group.id) + return _format_group(group) + + else: + if volume_client.api_version < api_versions.APIVersion('3.14'): + msg = _( + "--os-volume-api-version 3.14 or greater is required to " + "support the 'volume group create " + "[--source-group|--group-snapshot]' command" + ) + raise exceptions.CommandError(msg) + if (parsed_args.source_group is None and + parsed_args.group_snapshot is None): + msg = _( + "Either --source-group <source_group> or " + "'--group-snapshot <group_snapshot>' needs to be " + "provided to run the 'volume group create " + "[--source-group|--group-snapshot]' command" + ) + raise exceptions.CommandError(msg) + if parsed_args.availability_zone: + msg = _("'--availability-zone' option will not work " + "if creating group from source.") + self.log.warning(msg) + + source_group = None + if parsed_args.source_group: + source_group = utils.find_resource(volume_client.groups, + parsed_args.source_group) + group_snapshot = None + if parsed_args.group_snapshot: + group_snapshot = utils.find_resource( + volume_client.group_snapshots, + parsed_args.group_snapshot) + group = volume_client.groups.create_from_src( + group_snapshot.id if group_snapshot else None, + source_group.id if source_group else None, + parsed_args.name, + parsed_args.description) + group = volume_client.groups.get(group.id) + return _format_group(group) class DeleteVolumeGroup(command.Command): |