 3d1225cbb0
			
		
	
	3d1225cbb0
	
	
	
		
			
			We have a gap in the microversions implemented in the cinderclient and the MAX version being reported by the client. One of those is the addition of "user_id" in the snapshot list response. This patch adds that with the appropriate version checking. Note that the Max version has already been updated, but there are a few implementations missing. Change-Id: Ia8bdb46b46091a89996e404825466430b8906d18 Partial-Bug: #1715759
		
			
				
	
	
		
			2089 lines
		
	
	
		
			75 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			2089 lines
		
	
	
		
			75 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # Copyright (c) 2013-2014 OpenStack Foundation
 | |
| # All Rights Reserved.
 | |
| #
 | |
| # Licensed under the Apache License, Version 2.0 (the "License");
 | |
| # you may not use this file except in compliance with the License.
 | |
| # You may obtain a copy of the License at
 | |
| #
 | |
| #    http://www.apache.org/licenses/LICENSE-2.0
 | |
| #
 | |
| # Unless required by applicable law or agreed to in writing, software
 | |
| # distributed under the License is distributed on an "AS IS" BASIS,
 | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 | |
| # implied.
 | |
| # See the License for the specific language governing permissions and
 | |
| # limitations under the License.
 | |
| 
 | |
| from __future__ import print_function
 | |
| 
 | |
| import argparse
 | |
| import collections
 | |
| import os
 | |
| import sys
 | |
| 
 | |
| from oslo_utils import strutils
 | |
| import six
 | |
| 
 | |
| import cinderclient
 | |
| from cinderclient import api_versions
 | |
| from cinderclient import base
 | |
| from cinderclient import exceptions
 | |
| from cinderclient import shell_utils
 | |
| from cinderclient import utils
 | |
| 
 | |
| from cinderclient.v2.shell import *  # flake8: noqa
 | |
| 
 | |
| FILTER_DEPRECATED = ("This option is deprecated and will be removed in "
 | |
|                      "newer release. Please use '--filters' option which "
 | |
|                      "is introduced since 3.33 instead.")
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.33')
 | |
| @utils.arg('--resource',
 | |
|            metavar='<resource>',
 | |
|            default=None,
 | |
|            help='Show enabled filters for specified resource. Default=None.')
 | |
| def do_list_filters(cs, args):
 | |
|         """List enabled filters.
 | |
| 
 | |
|         Symbol '~' after filter key means it supports inexact filtering.
 | |
|         """
 | |
|         filters = cs.resource_filters.list(resource=args.resource)
 | |
|         shell_utils.print_resource_filter_list(filters)
 | |
| 
 | |
| 
 | |
| @utils.arg('--all-tenants',
 | |
|            metavar='<all_tenants>',
 | |
|            nargs='?',
 | |
|            type=int,
 | |
|            const=1,
 | |
|            default=0,
 | |
|            help='Shows details for all tenants. Admin only.')
 | |
| @utils.arg('--all_tenants',
 | |
|            nargs='?',
 | |
|            type=int,
 | |
|            const=1,
 | |
|            help=argparse.SUPPRESS)
 | |
| @utils.arg('--name',
 | |
|            metavar='<name>',
 | |
|            default=None,
 | |
|            help="Filters results by a name. Default=None. "
 | |
|                 "%s" % FILTER_DEPRECATED)
 | |
| @utils.arg('--status',
 | |
|            metavar='<status>',
 | |
|            default=None,
 | |
|            help="Filters results by a status. Default=None. "
 | |
|                 "%s" % FILTER_DEPRECATED)
 | |
| @utils.arg('--volume-id',
 | |
|            metavar='<volume-id>',
 | |
|            default=None,
 | |
|            help="Filters results by a volume ID. Default=None. "
 | |
|                 "%s" % FILTER_DEPRECATED)
 | |
| @utils.arg('--volume_id',
 | |
|            help=argparse.SUPPRESS)
 | |
| @utils.arg('--marker',
 | |
|            metavar='<marker>',
 | |
|            default=None,
 | |
|            help='Begin returning backups that appear later in the backup '
 | |
|                 'list than that represented by this id. '
 | |
|                 'Default=None.')
 | |
| @utils.arg('--limit',
 | |
|            metavar='<limit>',
 | |
|            default=None,
 | |
|            help='Maximum number of backups to return. Default=None.')
 | |
| @utils.arg('--sort',
 | |
|            metavar='<key>[:<direction>]',
 | |
|            default=None,
 | |
|            help=(('Comma-separated list of sort keys and directions in the '
 | |
|                   'form of <key>[:<asc|desc>]. '
 | |
|                   'Valid keys: %s. '
 | |
|                   'Default=None.') % ', '.join(base.SORT_KEY_VALUES)))
 | |
| @utils.arg('--filters',
 | |
|            type=six.text_type,
 | |
|            nargs='*',
 | |
|            start_version='3.33',
 | |
|            metavar='<key=value>',
 | |
|            default=None,
 | |
|            help="Filter key and value pairs. Please use 'cinder list-filters' "
 | |
|                 "to check enabled filters from server. Use 'key~=value' for "
 | |
|                 "inexact filtering if the key supports. Default=None.")
 | |
| def do_backup_list(cs, args):
 | |
|     """Lists all backups."""
 | |
|     # pylint: disable=function-redefined
 | |
| 
 | |
|     search_opts = {
 | |
|         'all_tenants': args.all_tenants,
 | |
|         'name': args.name,
 | |
|         'status': args.status,
 | |
|         'volume_id': args.volume_id,
 | |
|     }
 | |
| 
 | |
|     # Update search option with `filters`
 | |
|     if hasattr(args, 'filters') and args.filters is not None:
 | |
|         search_opts.update(shell_utils.extract_filters(args.filters))
 | |
| 
 | |
|     backups = cs.backups.list(search_opts=search_opts,
 | |
|                               marker=args.marker,
 | |
|                               limit=args.limit,
 | |
|                               sort=args.sort)
 | |
|     shell_utils.translate_volume_snapshot_keys(backups)
 | |
|     columns = ['ID', 'Volume ID', 'Status', 'Name', 'Size', 'Object Count',
 | |
|                'Container']
 | |
|     if args.sort:
 | |
|         sortby_index = None
 | |
|     else:
 | |
|         sortby_index = 0
 | |
|     utils.print_list(backups, columns, sortby_index=sortby_index)
 | |
| 
 | |
| 
 | |
| @utils.arg('--detail',
 | |
|            action='store_true',
 | |
|            help='Show detailed information about pools.')
 | |
| @utils.arg('--filters',
 | |
|            type=six.text_type,
 | |
|            nargs='*',
 | |
|            start_version='3.33',
 | |
|            metavar='<key=value>',
 | |
|            default=None,
 | |
|            help="Filter key and value pairs. Please use 'cinder list-filters' "
 | |
|                 "to check enabled filters from server, Default=None.")
 | |
| def do_get_pools(cs, args):
 | |
|     """Show pool information for backends. Admin only."""
 | |
|     # pylint: disable=function-redefined
 | |
|     search_opts = {}
 | |
|     # Update search option with `filters`
 | |
|     if hasattr(args, 'filters') and args.filters is not None:
 | |
|         search_opts.update(shell_utils.extract_filters(args.filters))
 | |
|     if cs.api_version >= api_versions.APIVersion("3.33"):
 | |
|         pools = cs.volumes.get_pools(args.detail, search_opts)
 | |
|     else:
 | |
|         pools = cs.volumes.get_pools(args.detail)
 | |
|     infos = dict()
 | |
|     infos.update(pools._info)
 | |
| 
 | |
|     for info in infos['pools']:
 | |
|         backend = dict()
 | |
|         backend['name'] = info['name']
 | |
|         if args.detail:
 | |
|             backend.update(info['capabilities'])
 | |
|         utils.print_dict(backend)
 | |
| 
 | |
| 
 | |
| RESET_STATE_RESOURCES = {'volume': utils.find_volume,
 | |
|                          'backup': shell_utils.find_backup,
 | |
|                          'snapshot': shell_utils.find_volume_snapshot,
 | |
|                          'group': shell_utils.find_group,
 | |
|                          'group-snapshot': shell_utils.find_group_snapshot}
 | |
| 
 | |
| 
 | |
| @utils.arg('--group_id',
 | |
|            metavar='<group_id>',
 | |
|            default=None,
 | |
|            help="Filters results by a group_id. Default=None."
 | |
|                 "%s" % FILTER_DEPRECATED,
 | |
|            start_version='3.10')
 | |
| @utils.arg('--all-tenants',
 | |
|            dest='all_tenants',
 | |
|            metavar='<0|1>',
 | |
|            nargs='?',
 | |
|            type=int,
 | |
|            const=1,
 | |
|            default=0,
 | |
|            help='Shows details for all tenants. Admin only.')
 | |
| @utils.arg('--all_tenants',
 | |
|            nargs='?',
 | |
|            type=int,
 | |
|            const=1,
 | |
|            help=argparse.SUPPRESS)
 | |
| @utils.arg('--name',
 | |
|            metavar='<name>',
 | |
|            default=None,
 | |
|            help="Filters results by a name. Default=None. "
 | |
|                 "%s" % FILTER_DEPRECATED)
 | |
| @utils.arg('--display-name',
 | |
|            help=argparse.SUPPRESS)
 | |
| @utils.arg('--status',
 | |
|            metavar='<status>',
 | |
|            default=None,
 | |
|            help="Filters results by a status. Default=None. "
 | |
|                 "%s" % FILTER_DEPRECATED)
 | |
| @utils.arg('--bootable',
 | |
|            metavar='<True|true|False|false>',
 | |
|            const=True,
 | |
|            nargs='?',
 | |
|            choices=['True', 'true', 'False', 'false'],
 | |
|            help="Filters results by bootable status. Default=None. "
 | |
|                 "%s" % FILTER_DEPRECATED)
 | |
| @utils.arg('--migration_status',
 | |
|            metavar='<migration_status>',
 | |
|            default=None,
 | |
|            help="Filters results by a migration status. Default=None. "
 | |
|                 "Admin only. "
 | |
|                 "%s" % FILTER_DEPRECATED)
 | |
| @utils.arg('--metadata',
 | |
|            nargs='*',
 | |
|            metavar='<key=value>',
 | |
|            default=None,
 | |
|            help="Filters results by a metadata key and value pair. "
 | |
|                 "Default=None. "
 | |
|                 "%s" % FILTER_DEPRECATED)
 | |
| @utils.arg('--image_metadata',
 | |
|            nargs='*',
 | |
|            metavar='<key=value>',
 | |
|            default=None,
 | |
|            start_version='3.4',
 | |
|            help="Filters results by a image metadata key and value pair. "
 | |
|                 "Require volume api version >=3.4. Default=None."
 | |
|                 "%s" % FILTER_DEPRECATED)
 | |
| @utils.arg('--marker',
 | |
|            metavar='<marker>',
 | |
|            default=None,
 | |
|            help='Begin returning volumes that appear later in the volume '
 | |
|                 'list than that represented by this volume id. '
 | |
|                 'Default=None.')
 | |
| @utils.arg('--limit',
 | |
|            metavar='<limit>',
 | |
|            default=None,
 | |
|            help='Maximum number of volumes to return. Default=None.')
 | |
| @utils.arg('--fields',
 | |
|            default=None,
 | |
|            metavar='<fields>',
 | |
|            help='Comma-separated list of fields to display. '
 | |
|                 'Use the show command to see which fields are available. '
 | |
|                 'Unavailable/non-existent fields will be ignored. '
 | |
|                 'Default=None.')
 | |
| @utils.arg('--sort_key',
 | |
|            metavar='<sort_key>',
 | |
|            default=None,
 | |
|            help=argparse.SUPPRESS)
 | |
| @utils.arg('--sort_dir',
 | |
|            metavar='<sort_dir>',
 | |
|            default=None,
 | |
|            help=argparse.SUPPRESS)
 | |
| @utils.arg('--sort',
 | |
|            metavar='<key>[:<direction>]',
 | |
|            default=None,
 | |
|            help=(('Comma-separated list of sort keys and directions in the '
 | |
|                   'form of <key>[:<asc|desc>]. '
 | |
|                   'Valid keys: %s. '
 | |
|                   'Default=None.') % ', '.join(base.SORT_KEY_VALUES)))
 | |
| @utils.arg('--tenant',
 | |
|            type=str,
 | |
|            dest='tenant',
 | |
|            nargs='?',
 | |
|            metavar='<tenant>',
 | |
|            help='Display information from single tenant (Admin only).')
 | |
| @utils.arg('--filters',
 | |
|            type=six.text_type,
 | |
|            nargs='*',
 | |
|            start_version='3.33',
 | |
|            metavar='<key=value>',
 | |
|            default=None,
 | |
|            help="Filter key and value pairs. Please use 'cinder list-filters' "
 | |
|                 "to check enabled filters from server. Use 'key~=value' "
 | |
|                 "for inexact filtering if the key supports. Default=None.")
 | |
| def do_list(cs, args):
 | |
|     """Lists all volumes."""
 | |
|     # pylint: disable=function-redefined
 | |
|     # NOTE(thingee): Backwards-compatibility with v1 args
 | |
|     if args.display_name is not None:
 | |
|         args.name = args.display_name
 | |
| 
 | |
|     all_tenants = 1 if args.tenant else \
 | |
|         int(os.environ.get("ALL_TENANTS", args.all_tenants))
 | |
|     search_opts = {
 | |
|         'all_tenants': all_tenants,
 | |
|         'project_id': args.tenant,
 | |
|         'name': args.name,
 | |
|         'status': args.status,
 | |
|         'bootable': args.bootable,
 | |
|         'migration_status': args.migration_status,
 | |
|         'metadata': shell_utils.extract_metadata(args)
 | |
|         if args.metadata else None,
 | |
|         'glance_metadata': shell_utils.extract_metadata(args,
 | |
|                                                         type='image_metadata')
 | |
|         if hasattr(args, 'image_metadata') and args.image_metadata else None,
 | |
|         'group_id': getattr(args, 'group_id', None),
 | |
|     }
 | |
|     # Update search option with `filters`
 | |
|     if hasattr(args, 'filters') and args.filters is not None:
 | |
|         search_opts.update(shell_utils.extract_filters(args.filters))
 | |
| 
 | |
|     # If unavailable/non-existent fields are specified, these fields will
 | |
|     # be removed from key_list at the print_list() during key validation.
 | |
|     field_titles = []
 | |
|     if args.fields:
 | |
|         for field_title in args.fields.split(','):
 | |
|             field_titles.append(field_title)
 | |
| 
 | |
|     # --sort_key and --sort_dir deprecated in kilo and is not supported
 | |
|     # with --sort
 | |
|     if args.sort and (args.sort_key or args.sort_dir):
 | |
|         raise exceptions.CommandError(
 | |
|             'The --sort_key and --sort_dir arguments are deprecated and are '
 | |
|             'not supported with --sort.')
 | |
| 
 | |
|     volumes = cs.volumes.list(search_opts=search_opts, marker=args.marker,
 | |
|                               limit=args.limit, sort_key=args.sort_key,
 | |
|                               sort_dir=args.sort_dir, sort=args.sort)
 | |
|     shell_utils.translate_volume_keys(volumes)
 | |
| 
 | |
|     # Create a list of servers to which the volume is attached
 | |
|     for vol in volumes:
 | |
|         servers = [s.get('server_id') for s in vol.attachments]
 | |
|         setattr(vol, 'attached_to', ','.join(map(str, servers)))
 | |
| 
 | |
|     if field_titles:
 | |
|         # Remove duplicate fields
 | |
|         key_list = ['ID']
 | |
|         unique_titles = [k for k in collections.OrderedDict.fromkeys(
 | |
|             [x.title().strip() for x in field_titles]) if k != 'Id']
 | |
|         key_list.extend(unique_titles)
 | |
|     else:
 | |
|         key_list = ['ID', 'Status', 'Name', 'Size', 'Volume Type',
 | |
|                     'Bootable', 'Attached to']
 | |
|         # If all_tenants is specified, print
 | |
|         # Tenant ID as well.
 | |
|         if search_opts['all_tenants']:
 | |
|             key_list.insert(1, 'Tenant ID')
 | |
| 
 | |
|     if args.sort_key or args.sort_dir or args.sort:
 | |
|         sortby_index = None
 | |
|     else:
 | |
|         sortby_index = 0
 | |
|     utils.print_list(volumes, key_list, exclude_unavailable=True,
 | |
|                      sortby_index=sortby_index)
 | |
| 
 | |
| 
 | |
| @utils.arg('entity', metavar='<entity>', nargs='+',
 | |
|            help='Name or ID of entity to update.')
 | |
| @utils.arg('--type', metavar='<type>', default='volume',
 | |
|            choices=RESET_STATE_RESOURCES.keys(),
 | |
|            help="Type of entity to update. Available resources "
 | |
|                 "are: 'volume', 'snapshot', 'backup', "
 | |
|                 "'group' (since 3.20) and "
 | |
|                 "'group-snapshot' (since 3.19), Default=volume.")
 | |
| @utils.arg('--state', metavar='<state>', default=None,
 | |
|            help=("The state to assign to the entity. "
 | |
|                  "NOTE: This command simply changes the state of the "
 | |
|                  "entity in the database with no regard to actual status, "
 | |
|                  "exercise caution when using. Default=None, that means the "
 | |
|                  "state is unchanged."))
 | |
| @utils.arg('--attach-status', metavar='<attach-status>', default=None,
 | |
|            help=('This is only used for a volume entity. The attach status '
 | |
|                  'to assign to the volume in the database, with no regard '
 | |
|                  'to the actual status. Valid values are "attached" and '
 | |
|                  '"detached". Default=None, that means the status '
 | |
|                  'is unchanged.'))
 | |
| @utils.arg('--reset-migration-status',
 | |
|            action='store_true',
 | |
|            help=('This is only used for a volume entity. Clears the migration '
 | |
|                  'status of the volume in the DataBase that indicates the '
 | |
|                  'volume is source or destination of volume migration, '
 | |
|                  'with no regard to the actual status.'))
 | |
| def do_reset_state(cs, args):
 | |
|     """Explicitly updates the entity state in the Cinder database.
 | |
| 
 | |
|     Being a database change only, this has no impact on the true state of the
 | |
|     entity and may not match the actual state. This can render a entity
 | |
|     unusable in the case of changing to the 'available' state.
 | |
|     """
 | |
|     # pylint: disable=function-redefined
 | |
|     failure_count = 0
 | |
|     single = (len(args.entity) == 1)
 | |
| 
 | |
|     migration_status = 'none' if args.reset_migration_status else None
 | |
|     collector = RESET_STATE_RESOURCES[args.type]
 | |
|     argument = (args.state,)
 | |
|     if args.type == 'volume':
 | |
|         argument += (args.attach_status, migration_status)
 | |
| 
 | |
|     for entity in args.entity:
 | |
|         try:
 | |
|             collector(cs, entity).reset_state(*argument)
 | |
|         except Exception as e:
 | |
|             print(e)
 | |
|             failure_count += 1
 | |
|             msg = "Reset state for entity %s failed: %s" % (entity, e)
 | |
|             if not single:
 | |
|                 print(msg)
 | |
| 
 | |
|     if failure_count == len(args.entity):
 | |
|         msg = "Unable to reset the state for the specified entity(s)."
 | |
|         raise exceptions.CommandError(msg)
 | |
| 
 | |
| 
 | |
| @utils.arg('size',
 | |
|            metavar='<size>',
 | |
|            nargs='?',
 | |
|            type=int,
 | |
|            action=CheckSizeArgForCreate,
 | |
|            help='Size of volume, in GiBs. (Required unless '
 | |
|                 'snapshot-id/source-volid is specified).')
 | |
| @utils.arg('--consisgroup-id',
 | |
|            metavar='<consistencygroup-id>',
 | |
|            default=None,
 | |
|            help='ID of a consistency group where the new volume belongs to. '
 | |
|                 'Default=None.')
 | |
| @utils.arg('--group-id',
 | |
|            metavar='<group-id>',
 | |
|            default=None,
 | |
|            help='ID of a group where the new volume belongs to. '
 | |
|                 'Default=None.',
 | |
|            start_version='3.13')
 | |
| @utils.arg('--snapshot-id',
 | |
|            metavar='<snapshot-id>',
 | |
|            default=None,
 | |
|            help='Creates volume from snapshot ID. Default=None.')
 | |
| @utils.arg('--snapshot_id',
 | |
|            help=argparse.SUPPRESS)
 | |
| @utils.arg('--source-volid',
 | |
|            metavar='<source-volid>',
 | |
|            default=None,
 | |
|            help='Creates volume from volume ID. Default=None.')
 | |
| @utils.arg('--source_volid',
 | |
|            help=argparse.SUPPRESS)
 | |
| @utils.arg('--source-replica',
 | |
|            metavar='<source-replica>',
 | |
|            default=None,
 | |
|            help='Creates volume from replicated volume ID. Default=None.')
 | |
| @utils.arg('--image-id',
 | |
|            metavar='<image-id>',
 | |
|            default=None,
 | |
|            help='Creates volume from image ID. Default=None.')
 | |
| @utils.arg('--image_id',
 | |
|            help=argparse.SUPPRESS)
 | |
| @utils.arg('--image',
 | |
|            metavar='<image>',
 | |
|            default=None,
 | |
|            help='Creates a volume from image (ID or name). Default=None.')
 | |
| @utils.arg('--image_ref',
 | |
|            help=argparse.SUPPRESS)
 | |
| @utils.arg('--name',
 | |
|            metavar='<name>',
 | |
|            default=None,
 | |
|            help='Volume name. Default=None.')
 | |
| @utils.arg('--display-name',
 | |
|            help=argparse.SUPPRESS)
 | |
| @utils.arg('--display_name',
 | |
|            help=argparse.SUPPRESS)
 | |
| @utils.arg('--description',
 | |
|            metavar='<description>',
 | |
|            default=None,
 | |
|            help='Volume description. Default=None.')
 | |
| @utils.arg('--display-description',
 | |
|            help=argparse.SUPPRESS)
 | |
| @utils.arg('--display_description',
 | |
|            help=argparse.SUPPRESS)
 | |
| @utils.arg('--volume-type',
 | |
|            metavar='<volume-type>',
 | |
|            default=None,
 | |
|            help='Volume type. Default=None.')
 | |
| @utils.arg('--volume_type',
 | |
|            help=argparse.SUPPRESS)
 | |
| @utils.arg('--availability-zone',
 | |
|            metavar='<availability-zone>',
 | |
|            default=None,
 | |
|            help='Availability zone for volume. Default=None.')
 | |
| @utils.arg('--availability_zone',
 | |
|            help=argparse.SUPPRESS)
 | |
| @utils.arg('--metadata',
 | |
|            nargs='*',
 | |
|            metavar='<key=value>',
 | |
|            default=None,
 | |
|            help='Metadata key and value pairs. Default=None.')
 | |
| @utils.arg('--hint',
 | |
|            metavar='<key=value>',
 | |
|            dest='scheduler_hints',
 | |
|            action='append',
 | |
|            default=[],
 | |
|            help='Scheduler hint, like in nova.')
 | |
| @utils.arg('--allow-multiattach',
 | |
|            dest='multiattach',
 | |
|            action="store_true",
 | |
|            help=('Allow volume to be attached more than once.'
 | |
|                  ' Default=False'),
 | |
|            default=False)
 | |
| @utils.arg('--poll',
 | |
|            action="store_true",
 | |
|            help=('Wait for volume creation until it completes.'))
 | |
| def do_create(cs, args):
 | |
|     """Creates a volume."""
 | |
| 
 | |
|     # NOTE(thingee): Backwards-compatibility with v1 args
 | |
|     if args.display_name is not None:
 | |
|         args.name = args.display_name
 | |
| 
 | |
|     if args.display_description is not None:
 | |
|         args.description = args.display_description
 | |
| 
 | |
|     volume_metadata = None
 | |
|     if args.metadata is not None:
 | |
|         volume_metadata = shell_utils.extract_metadata(args)
 | |
| 
 | |
|     # NOTE(N.S.): take this piece from novaclient
 | |
|     hints = {}
 | |
|     if args.scheduler_hints:
 | |
|         for hint in args.scheduler_hints:
 | |
|             key, _sep, value = hint.partition('=')
 | |
|             # NOTE(vish): multiple copies of same hint will
 | |
|             #             result in a list of values
 | |
|             if key in hints:
 | |
|                 if isinstance(hints[key], six.string_types):
 | |
|                     hints[key] = [hints[key]]
 | |
|                 hints[key] += [value]
 | |
|             else:
 | |
|                 hints[key] = value
 | |
|     # NOTE(N.S.): end of taken piece
 | |
| 
 | |
|     # Keep backward compatibility with image_id, favoring explicit ID
 | |
|     image_ref = args.image_id or args.image or args.image_ref
 | |
| 
 | |
|     try:
 | |
|         group_id = args.group_id
 | |
|     except AttributeError:
 | |
|         group_id = None
 | |
| 
 | |
|     volume = cs.volumes.create(args.size,
 | |
|                                args.consisgroup_id,
 | |
|                                group_id,
 | |
|                                args.snapshot_id,
 | |
|                                args.source_volid,
 | |
|                                args.name,
 | |
|                                args.description,
 | |
|                                args.volume_type,
 | |
|                                availability_zone=args.availability_zone,
 | |
|                                imageRef=image_ref,
 | |
|                                metadata=volume_metadata,
 | |
|                                scheduler_hints=hints,
 | |
|                                source_replica=args.source_replica,
 | |
|                                multiattach=args.multiattach)
 | |
| 
 | |
|     info = dict()
 | |
|     volume = cs.volumes.get(volume.id)
 | |
|     info.update(volume._info)
 | |
| 
 | |
|     if 'readonly' in info['metadata']:
 | |
|         info['readonly'] = info['metadata']['readonly']
 | |
| 
 | |
|     info.pop('links', None)
 | |
| 
 | |
|     if args.poll:
 | |
|         timeout_period = os.environ.get("POLL_TIMEOUT_PERIOD", 3600)
 | |
|         shell_utils._poll_for_status(cs.volumes.get, volume.id, info, 'creating', ['available'],
 | |
|                 timeout_period, cs.client.global_request_id, cs.messages)
 | |
| 
 | |
|     utils.print_dict(info)
 | |
| 
 | |
| 
 | |
| @utils.arg('volume',
 | |
|            metavar='<volume>',
 | |
|            help='Name or ID of volume for which to update metadata.')
 | |
| @utils.arg('action',
 | |
|            metavar='<action>',
 | |
|            choices=['set', 'unset'],
 | |
|            help='The action. Valid values are "set" or "unset."')
 | |
| @utils.arg('metadata',
 | |
|            metavar='<key=value>',
 | |
|            nargs='+',
 | |
|            default=[],
 | |
|            end_version='3.14',
 | |
|            help='Metadata key and value pair to set or unset. '
 | |
|                 'For unset, specify only the key.')
 | |
| @utils.arg('metadata',
 | |
|            metavar='<key=value>',
 | |
|            nargs='+',
 | |
|            default=[],
 | |
|            start_version='3.15',
 | |
|            help='Metadata key and value pair to set or unset. '
 | |
|                 'For unset, specify only the key(s): <key key>')
 | |
| def do_metadata(cs, args):
 | |
|     """Sets or deletes volume metadata."""
 | |
|     volume = utils.find_volume(cs, args.volume)
 | |
|     metadata = shell_utils.extract_metadata(args)
 | |
| 
 | |
|     if args.action == 'set':
 | |
|         cs.volumes.set_metadata(volume, metadata)
 | |
|     elif args.action == 'unset':
 | |
|         # NOTE(zul): Make sure py2/py3 sorting is the same
 | |
|         cs.volumes.delete_metadata(volume, sorted(metadata.keys(),
 | |
|                                    reverse=True))
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.12')
 | |
| @utils.arg('--all-tenants',
 | |
|            dest='all_tenants',
 | |
|            metavar='<0|1>',
 | |
|            nargs='?',
 | |
|            type=int,
 | |
|            const=1,
 | |
|            default=utils.env('ALL_TENANTS', default=0),
 | |
|            help='Shows details for all tenants. Admin only.')
 | |
| def do_summary(cs, args):
 | |
|     """Get volumes summary."""
 | |
|     all_tenants = args.all_tenants
 | |
|     info = cs.volumes.summary(all_tenants)
 | |
| 
 | |
|     formatters = ['total_size', 'total_count']
 | |
|     if cs.api_version >= api_versions.APIVersion("3.36"):
 | |
|         formatters.append('metadata')
 | |
| 
 | |
|     utils.print_dict(info['volume-summary'], formatters=formatters)
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.11')
 | |
| def do_group_type_list(cs, args):
 | |
|     """Lists available 'group types'. (Admin only will see private types)"""
 | |
|     gtypes = cs.group_types.list()
 | |
|     shell_utils.print_group_type_list(gtypes)
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.11')
 | |
| def do_group_type_default(cs, args):
 | |
|     """List the default group type."""
 | |
|     gtype = cs.group_types.default()
 | |
|     shell_utils.print_group_type_list([gtype])
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.11')
 | |
| @utils.arg('group_type',
 | |
|            metavar='<group_type>',
 | |
|            help='Name or ID of the group type.')
 | |
| def do_group_type_show(cs, args):
 | |
|     """Show group type details."""
 | |
|     gtype = shell_utils.find_gtype(cs, args.group_type)
 | |
|     info = dict()
 | |
|     info.update(gtype._info)
 | |
| 
 | |
|     info.pop('links', None)
 | |
|     utils.print_dict(info, formatters=['group_specs'])
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.11')
 | |
| @utils.arg('id',
 | |
|            metavar='<id>',
 | |
|            help='ID of the group type.')
 | |
| @utils.arg('--name',
 | |
|            metavar='<name>',
 | |
|            help='Name of the group type.')
 | |
| @utils.arg('--description',
 | |
|            metavar='<description>',
 | |
|            help='Description of the group type.')
 | |
| @utils.arg('--is-public',
 | |
|            metavar='<is-public>',
 | |
|            help='Make type accessible to the public or not.')
 | |
| def do_group_type_update(cs, args):
 | |
|     """Updates group type name, description, and/or is_public."""
 | |
|     is_public = strutils.bool_from_string(args.is_public)
 | |
|     gtype = cs.group_types.update(args.id, args.name, args.description,
 | |
|                                   is_public)
 | |
|     shell_utils.print_group_type_list([gtype])
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.11')
 | |
| def do_group_specs_list(cs, args):
 | |
|     """Lists current group types and specs."""
 | |
|     gtypes = cs.group_types.list()
 | |
|     utils.print_list(gtypes, ['ID', 'Name', 'group_specs'])
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.11')
 | |
| @utils.arg('name',
 | |
|            metavar='<name>',
 | |
|            help='Name of new group type.')
 | |
| @utils.arg('--description',
 | |
|            metavar='<description>',
 | |
|            help='Description of new group type.')
 | |
| @utils.arg('--is-public',
 | |
|            metavar='<is-public>',
 | |
|            default=True,
 | |
|            help='Make type accessible to the public (default true).')
 | |
| def do_group_type_create(cs, args):
 | |
|     """Creates a group type."""
 | |
|     is_public = strutils.bool_from_string(args.is_public)
 | |
|     gtype = cs.group_types.create(args.name, args.description, is_public)
 | |
|     shell_utils.print_group_type_list([gtype])
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.11')
 | |
| @utils.arg('group_type',
 | |
|            metavar='<group_type>', nargs='+',
 | |
|            help='Name or ID of group type or types to delete.')
 | |
| def do_group_type_delete(cs, args):
 | |
|     """Deletes group type or types."""
 | |
|     failure_count = 0
 | |
|     for group_type in args.group_type:
 | |
|         try:
 | |
|             gtype = shell_utils.find_group_type(cs, group_type)
 | |
|             cs.group_types.delete(gtype)
 | |
|             print("Request to delete group type %s has been accepted."
 | |
|                   % group_type)
 | |
|         except Exception as e:
 | |
|             failure_count += 1
 | |
|             print("Delete for group type %s failed: %s" % (group_type, e))
 | |
|     if failure_count == len(args.group_type):
 | |
|         raise exceptions.CommandError("Unable to delete any of the "
 | |
|                                       "specified types.")
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.11')
 | |
| @utils.arg('gtype',
 | |
|            metavar='<gtype>',
 | |
|            help='Name or ID of group type.')
 | |
| @utils.arg('action',
 | |
|            metavar='<action>',
 | |
|            choices=['set', 'unset'],
 | |
|            help='The action. Valid values are "set" or "unset."')
 | |
| @utils.arg('metadata',
 | |
|            metavar='<key=value>',
 | |
|            nargs='+',
 | |
|            default=[],
 | |
|            help='The group specs key and value pair to set or unset. '
 | |
|                 'For unset, specify only the key.')
 | |
| def do_group_type_key(cs, args):
 | |
|     """Sets or unsets group_spec for a group type."""
 | |
|     gtype = shell_utils.find_group_type(cs, args.gtype)
 | |
|     keypair = shell_utils.extract_metadata(args)
 | |
| 
 | |
|     if args.action == 'set':
 | |
|         gtype.set_keys(keypair)
 | |
|     elif args.action == 'unset':
 | |
|         gtype.unset_keys(list(keypair))
 | |
| 
 | |
| 
 | |
| @utils.arg('tenant',
 | |
|            metavar='<tenant_id>',
 | |
|            help='ID of tenant for which to set quotas.')
 | |
| @utils.arg('--volumes',
 | |
|            metavar='<volumes>',
 | |
|            type=int, default=None,
 | |
|            help='The new "volumes" quota value. Default=None.')
 | |
| @utils.arg('--snapshots',
 | |
|            metavar='<snapshots>',
 | |
|            type=int, default=None,
 | |
|            help='The new "snapshots" quota value. Default=None.')
 | |
| @utils.arg('--gigabytes',
 | |
|            metavar='<gigabytes>',
 | |
|            type=int, default=None,
 | |
|            help='The new "gigabytes" quota value. Default=None.')
 | |
| @utils.arg('--backups',
 | |
|            metavar='<backups>',
 | |
|            type=int, default=None,
 | |
|            help='The new "backups" quota value. Default=None.')
 | |
| @utils.arg('--backup-gigabytes',
 | |
|            metavar='<backup_gigabytes>',
 | |
|            type=int, default=None,
 | |
|            help='The new "backup_gigabytes" quota value. Default=None.')
 | |
| @utils.arg('--groups',
 | |
|            metavar='<groups>',
 | |
|            type=int, default=None,
 | |
|            help='The new "groups" quota value. Default=None.',
 | |
|            start_version='3.13')
 | |
| @utils.arg('--volume-type',
 | |
|            metavar='<volume_type_name>',
 | |
|            default=None,
 | |
|            help='Volume type. Default=None.')
 | |
| @utils.arg('--per-volume-gigabytes',
 | |
|            metavar='<per_volume_gigabytes>',
 | |
|            type=int, default=None,
 | |
|            help='Set max volume size limit. Default=None.')
 | |
| @utils.arg('--skip-validation',
 | |
|            metavar='<skip_validation>',
 | |
|            default=False,
 | |
|            help='Skip validate the existing resource quota. Default=False.')
 | |
| def do_quota_update(cs, args):
 | |
|     """Updates quotas for a tenant."""
 | |
| 
 | |
|     shell_utils.quota_update(cs.quotas, args.tenant, args)
 | |
| 
 | |
| 
 | |
| @utils.arg('volume',
 | |
|            metavar='<volume>',
 | |
|            help='Name or ID of volume to snapshot.')
 | |
| @utils.arg('--force',
 | |
|            metavar='<True|False>',
 | |
|            const=True,
 | |
|            nargs='?',
 | |
|            default=False,
 | |
|            help='Enables or disables upload of '
 | |
|            'a volume that is attached to an instance. '
 | |
|            'Default=False. '
 | |
|            'This option may not be supported by your cloud.')
 | |
| @utils.arg('--container-format',
 | |
|            metavar='<container-format>',
 | |
|            default='bare',
 | |
|            help='Container format type. '
 | |
|                 'Default is bare.')
 | |
| @utils.arg('--container_format',
 | |
|            help=argparse.SUPPRESS)
 | |
| @utils.arg('--disk-format',
 | |
|            metavar='<disk-format>',
 | |
|            default='raw',
 | |
|            help='Disk format type. '
 | |
|                 'Default is raw.')
 | |
| @utils.arg('--disk_format',
 | |
|            help=argparse.SUPPRESS)
 | |
| @utils.arg('image_name',
 | |
|            metavar='<image-name>',
 | |
|            help='The new image name.')
 | |
| @utils.arg('--image_name',
 | |
|            help=argparse.SUPPRESS)
 | |
| @utils.arg('--visibility',
 | |
|            metavar='<public|private|community|shared>',
 | |
|            help='Set image visibility to public, private, community or '
 | |
|                 'shared. Default=private.',
 | |
|            default='private',
 | |
|            start_version='3.1')
 | |
| @utils.arg('--protected',
 | |
|            metavar='<True|False>',
 | |
|            help='Prevents image from being deleted. Default=False.',
 | |
|            default=False,
 | |
|            start_version='3.1')
 | |
| def do_upload_to_image(cs, args):
 | |
|     """Uploads volume to Image Service as an image."""
 | |
|     volume = utils.find_volume(cs, args.volume)
 | |
|     if cs.api_version >= api_versions.APIVersion("3.1"):
 | |
|         shell_utils.print_volume_image(
 | |
|             volume.upload_to_image(args.force,
 | |
|                                    args.image_name,
 | |
|                                    args.container_format,
 | |
|                                    args.disk_format,
 | |
|                                    args.visibility,
 | |
|                                    args.protected))
 | |
|     else:
 | |
|         shell_utils.print_volume_image(
 | |
|             volume.upload_to_image(args.force,
 | |
|                                    args.image_name,
 | |
|                                    args.container_format,
 | |
|                                    args.disk_format))
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.9', '3.43')
 | |
| @utils.arg('backup', metavar='<backup>',
 | |
|            help='Name or ID of backup to rename.')
 | |
| @utils.arg('--name', nargs='?', metavar='<name>',
 | |
|            help='New name for backup.')
 | |
| @utils.arg('--description', metavar='<description>',
 | |
|            help='Backup description. Default=None.')
 | |
| @utils.arg('--metadata',
 | |
|            nargs='*',
 | |
|            metavar='<key=value>',
 | |
|            default=None,
 | |
|            help='Metadata key and value pairs. Default=None.',
 | |
|            start_version='3.43')
 | |
| def do_backup_update(cs, args):
 | |
|     """Renames a backup."""
 | |
|     kwargs = {}
 | |
| 
 | |
|     if args.name is not None:
 | |
|         kwargs['name'] = args.name
 | |
| 
 | |
|     if args.description is not None:
 | |
|         kwargs['description'] = args.description
 | |
| 
 | |
|     if cs.api_version >= api_versions.APIVersion("3.43"):
 | |
|         if args.metadata is not None:
 | |
|             kwargs['metadata'] = args.metadata
 | |
| 
 | |
|     if not kwargs:
 | |
|         msg = 'Must supply either name or description.'
 | |
|         raise exceptions.ClientException(code=1, message=msg)
 | |
| 
 | |
|     shell_utils.find_backup(cs, args.backup).update(**kwargs)
 | |
|     print("Request to update backup '%s' has been accepted." % args.backup)
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.7')
 | |
| @utils.arg('--name', metavar='<name>', default=None,
 | |
|            help='Filter by cluster name, without backend will list all '
 | |
|                 'clustered services from the same cluster. Default=None.')
 | |
| @utils.arg('--binary', metavar='<binary>', default=None,
 | |
|            help='Cluster binary. Default=None.')
 | |
| @utils.arg('--is-up', metavar='<True|true|False|false>', default=None,
 | |
|            choices=('True', 'true', 'False', 'false'),
 | |
|            help='Filter by up/dow status. Default=None.')
 | |
| @utils.arg('--disabled', metavar='<True|true|False|false>', default=None,
 | |
|            choices=('True', 'true', 'False', 'false'),
 | |
|            help='Filter by disabled status. Default=None.')
 | |
| @utils.arg('--num-hosts', metavar='<num-hosts>', default=None,
 | |
|            help='Filter by number of hosts in the cluster.')
 | |
| @utils.arg('--num-down-hosts', metavar='<num-down-hosts>', default=None,
 | |
|            help='Filter by number of hosts that are down.')
 | |
| @utils.arg('--detailed', dest='detailed', default=False,
 | |
|            help='Get detailed clustered service information (Default=False).',
 | |
|            action='store_true')
 | |
| def do_cluster_list(cs, args):
 | |
|     """Lists clustered services with optional filtering."""
 | |
|     clusters = cs.clusters.list(name=args.name, binary=args.binary,
 | |
|                                 is_up=args.is_up, disabled=args.disabled,
 | |
|                                 num_hosts=args.num_hosts,
 | |
|                                 num_down_hosts=args.num_down_hosts,
 | |
|                                 detailed=args.detailed)
 | |
| 
 | |
|     columns = ['Name', 'Binary', 'State', 'Status']
 | |
|     if args.detailed:
 | |
|         columns.extend(('Num Hosts', 'Num Down Hosts', 'Last Heartbeat',
 | |
|                         'Disabled Reason', 'Created At', 'Updated at'))
 | |
|     utils.print_list(clusters, columns)
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.7')
 | |
| @utils.arg('binary', metavar='<binary>', nargs='?', default='cinder-volume',
 | |
|            help='Binary to filter by.  Default: cinder-volume.')
 | |
| @utils.arg('name', metavar='<cluster-name>',
 | |
|            help='Name of the clustered service to show.')
 | |
| def do_cluster_show(cs, args):
 | |
|     """Show detailed information on a clustered service."""
 | |
|     cluster = cs.clusters.show(args.name, args.binary)
 | |
|     utils.print_dict(cluster.to_dict())
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.7')
 | |
| @utils.arg('binary', metavar='<binary>', nargs='?', default='cinder-volume',
 | |
|            help='Binary to filter by.  Default: cinder-volume.')
 | |
| @utils.arg('name', metavar='<cluster-name>',
 | |
|            help='Name of the clustered services to update.')
 | |
| def do_cluster_enable(cs, args):
 | |
|     """Enables clustered services."""
 | |
|     cluster = cs.clusters.update(args.name, args.binary, disabled=False)
 | |
|     utils.print_dict(cluster.to_dict())
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.7')
 | |
| @utils.arg('binary', metavar='<binary>', nargs='?', default='cinder-volume',
 | |
|            help='Binary to filter by.  Default: cinder-volume.')
 | |
| @utils.arg('name', metavar='<cluster-name>',
 | |
|            help='Name of the clustered services to update.')
 | |
| @utils.arg('--reason', metavar='<reason>', default=None,
 | |
|            help='Reason for disabling clustered service.')
 | |
| def do_cluster_disable(cs, args):
 | |
|     """Disables clustered services."""
 | |
|     cluster = cs.clusters.update(args.name, args.binary, disabled=True,
 | |
|                                  disabled_reason=args.reason)
 | |
|     utils.print_dict(cluster.to_dict())
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.8')
 | |
| @utils.arg('host',
 | |
|            metavar='<host>',
 | |
|            help='Cinder host on which to list manageable volumes; '
 | |
|                 'takes the form: host@backend-name#pool')
 | |
| @utils.arg('--detailed',
 | |
|            metavar='<detailed>',
 | |
|            default=True,
 | |
|            help='Returned detailed information (default true).')
 | |
| @utils.arg('--marker',
 | |
|            metavar='<marker>',
 | |
|            default=None,
 | |
|            help='Begin returning volumes that appear later in the volume '
 | |
|                 'list than that represented by this reference. This reference '
 | |
|                 'should be json like. '
 | |
|                 'Default=None.')
 | |
| @utils.arg('--limit',
 | |
|            metavar='<limit>',
 | |
|            default=None,
 | |
|            help='Maximum number of volumes to return. Default=None.')
 | |
| @utils.arg('--offset',
 | |
|            metavar='<offset>',
 | |
|            default=None,
 | |
|            help='Number of volumes to skip after marker. Default=None.')
 | |
| @utils.arg('--sort',
 | |
|            metavar='<key>[:<direction>]',
 | |
|            default=None,
 | |
|            help=(('Comma-separated list of sort keys and directions in the '
 | |
|                   'form of <key>[:<asc|desc>]. '
 | |
|                   'Valid keys: %s. '
 | |
|                   'Default=None.'
 | |
|                   ) % ', '.join(base.SORT_MANAGEABLE_KEY_VALUES)))
 | |
| def do_manageable_list(cs, args):
 | |
|     """Lists all manageable volumes."""
 | |
|     # pylint: disable=function-redefined
 | |
|     detailed = strutils.bool_from_string(args.detailed)
 | |
|     volumes = cs.volumes.list_manageable(host=args.host, detailed=detailed,
 | |
|                                          marker=args.marker, limit=args.limit,
 | |
|                                          offset=args.offset, sort=args.sort)
 | |
|     columns = ['reference', 'size', 'safe_to_manage']
 | |
|     if detailed:
 | |
|         columns.extend(['reason_not_safe', 'cinder_id', 'extra_info'])
 | |
|     utils.print_list(volumes, columns, sortby_index=None)
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.13')
 | |
| @utils.arg('--all-tenants',
 | |
|            dest='all_tenants',
 | |
|            metavar='<0|1>',
 | |
|            nargs='?',
 | |
|            type=int,
 | |
|            const=1,
 | |
|            default=utils.env('ALL_TENANTS', default=0),
 | |
|            help='Shows details for all tenants. Admin only.')
 | |
| @utils.arg('--filters',
 | |
|            type=six.text_type,
 | |
|            nargs='*',
 | |
|            start_version='3.33',
 | |
|            metavar='<key=value>',
 | |
|            default=None,
 | |
|            help="Filter key and value pairs. Please use 'cinder list-filters' "
 | |
|                 "to check enabled filters from server. Use 'key~=value' "
 | |
|                 "for inexact filtering if the key supports. Default=None.")
 | |
| def do_group_list(cs, args):
 | |
|     """Lists all groups."""
 | |
|     search_opts = {'all_tenants': args.all_tenants}
 | |
| 
 | |
|     # Update search option with `filters`
 | |
|     if hasattr(args, 'filters') and args.filters is not None:
 | |
|         search_opts.update(shell_utils.extract_filters(args.filters))
 | |
| 
 | |
|     groups = cs.groups.list(search_opts=search_opts)
 | |
| 
 | |
|     columns = ['ID', 'Status', 'Name']
 | |
|     utils.print_list(groups, columns)
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.13')
 | |
| @utils.arg('--list-volume',
 | |
|            dest='list_volume',
 | |
|            metavar='<False|True>',
 | |
|            nargs='?',
 | |
|            type=bool,
 | |
|            const=True,
 | |
|            default=False,
 | |
|            help='Shows volumes included in the group.',
 | |
|            start_version='3.25')
 | |
| @utils.arg('group',
 | |
|            metavar='<group>',
 | |
|            help='Name or ID of a group.')
 | |
| def do_group_show(cs, args):
 | |
|     """Shows details of a group."""
 | |
|     info = dict()
 | |
|     if getattr(args, 'list_volume', None):
 | |
|         group = shell_utils.find_group(cs, args.group,
 | |
|                                        list_volume=args.list_volume)
 | |
|     else:
 | |
|         group = shell_utils.find_group(cs, args.group)
 | |
|     info.update(group._info)
 | |
| 
 | |
|     info.pop('links', None)
 | |
|     utils.print_dict(info)
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.13')
 | |
| @utils.arg('grouptype',
 | |
|            metavar='<group-type>',
 | |
|            help='Group type.')
 | |
| @utils.arg('volumetypes',
 | |
|            metavar='<volume-types>',
 | |
|            help='Comma-separated list of volume types.')
 | |
| @utils.arg('--name',
 | |
|            metavar='<name>',
 | |
|            help='Name of a group.')
 | |
| @utils.arg('--description',
 | |
|            metavar='<description>',
 | |
|            default=None,
 | |
|            help='Description of a group. Default=None.')
 | |
| @utils.arg('--availability-zone',
 | |
|            metavar='<availability-zone>',
 | |
|            default=None,
 | |
|            help='Availability zone for group. Default=None.')
 | |
| def do_group_create(cs, args):
 | |
|     """Creates a group."""
 | |
| 
 | |
|     group = cs.groups.create(
 | |
|         args.grouptype,
 | |
|         args.volumetypes,
 | |
|         args.name,
 | |
|         args.description,
 | |
|         availability_zone=args.availability_zone)
 | |
| 
 | |
|     info = dict()
 | |
|     group = cs.groups.get(group.id)
 | |
|     info.update(group._info)
 | |
| 
 | |
|     info.pop('links', None)
 | |
|     utils.print_dict(info)
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.14')
 | |
| @utils.arg('--group-snapshot',
 | |
|            metavar='<group-snapshot>',
 | |
|            help='Name or ID of a group snapshot. Default=None.')
 | |
| @utils.arg('--source-group',
 | |
|            metavar='<source-group>',
 | |
|            help='Name or ID of a source group. Default=None.')
 | |
| @utils.arg('--name',
 | |
|            metavar='<name>',
 | |
|            help='Name of a group. Default=None.')
 | |
| @utils.arg('--description',
 | |
|            metavar='<description>',
 | |
|            help='Description of a group. Default=None.')
 | |
| def do_group_create_from_src(cs, args):
 | |
|     """Creates a group from a group snapshot or a source group."""
 | |
|     if not args.group_snapshot and not args.source_group:
 | |
|         msg = ('Cannot create group because neither '
 | |
|                'group snapshot nor source group is provided.')
 | |
|         raise exceptions.ClientException(code=1, message=msg)
 | |
|     if args.group_snapshot and args.source_group:
 | |
|         msg = ('Cannot create group because both '
 | |
|                'group snapshot and source group are provided.')
 | |
|         raise exceptions.ClientException(code=1, message=msg)
 | |
|     group_snapshot = None
 | |
|     if args.group_snapshot:
 | |
|         group_snapshot = shell_utils.find_group_snapshot(cs,
 | |
|                                                          args.group_snapshot)
 | |
|     source_group = None
 | |
|     if args.source_group:
 | |
|         source_group = shell_utils.find_group(cs, args.source_group)
 | |
|     info = cs.groups.create_from_src(
 | |
|         group_snapshot.id if group_snapshot else None,
 | |
|         source_group.id if source_group else None,
 | |
|         args.name,
 | |
|         args.description)
 | |
| 
 | |
|     info.pop('links', None)
 | |
|     utils.print_dict(info)
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.13')
 | |
| @utils.arg('group',
 | |
|            metavar='<group>', nargs='+',
 | |
|            help='Name or ID of one or more groups '
 | |
|                 'to be deleted.')
 | |
| @utils.arg('--delete-volumes',
 | |
|            action='store_true',
 | |
|            default=False,
 | |
|            help='Allows or disallows groups to be deleted '
 | |
|                 'if they are not empty. If the group is empty, '
 | |
|                 'it can be deleted without the delete-volumes flag. '
 | |
|                 'If the group is not empty, the delete-volumes '
 | |
|                 'flag is required for it to be deleted. If True, '
 | |
|                 'all volumes in the group will also be deleted.')
 | |
| def do_group_delete(cs, args):
 | |
|     """Removes one or more groups."""
 | |
|     failure_count = 0
 | |
|     for group in args.group:
 | |
|         try:
 | |
|             shell_utils.find_group(cs, group).delete(args.delete_volumes)
 | |
|         except Exception as e:
 | |
|             failure_count += 1
 | |
|             print("Delete for group %s failed: %s" %
 | |
|                   (group, e))
 | |
|     if failure_count == len(args.group):
 | |
|         raise exceptions.CommandError("Unable to delete any of the specified "
 | |
|                                       "groups.")
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.13')
 | |
| @utils.arg('group',
 | |
|            metavar='<group>',
 | |
|            help='Name or ID of a group.')
 | |
| @utils.arg('--name', metavar='<name>',
 | |
|            help='New name for group. Default=None.')
 | |
| @utils.arg('--description', metavar='<description>',
 | |
|            help='New description for group. Default=None.')
 | |
| @utils.arg('--add-volumes',
 | |
|            metavar='<uuid1,uuid2,......>',
 | |
|            help='UUID of one or more volumes '
 | |
|                 'to be added to the group, '
 | |
|                 'separated by commas. Default=None.')
 | |
| @utils.arg('--remove-volumes',
 | |
|            metavar='<uuid3,uuid4,......>',
 | |
|            help='UUID of one or more volumes '
 | |
|                 'to be removed from the group, '
 | |
|                 'separated by commas. Default=None.')
 | |
| def do_group_update(cs, args):
 | |
|     """Updates a group."""
 | |
|     kwargs = {}
 | |
| 
 | |
|     if args.name is not None:
 | |
|         kwargs['name'] = args.name
 | |
| 
 | |
|     if args.description is not None:
 | |
|         kwargs['description'] = args.description
 | |
| 
 | |
|     if args.add_volumes is not None:
 | |
|         kwargs['add_volumes'] = args.add_volumes
 | |
| 
 | |
|     if args.remove_volumes is not None:
 | |
|         kwargs['remove_volumes'] = args.remove_volumes
 | |
| 
 | |
|     if not kwargs:
 | |
|         msg = ('At least one of the following args must be supplied: '
 | |
|                'name, description, add-volumes, remove-volumes.')
 | |
|         raise exceptions.ClientException(code=1, message=msg)
 | |
| 
 | |
|     shell_utils.find_group(cs, args.group).update(**kwargs)
 | |
|     print("Request to update group '%s' has been accepted." % args.group)
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.38')
 | |
| @utils.arg('group',
 | |
|            metavar='<group>',
 | |
|            help='Name or ID of the group.')
 | |
| def do_group_enable_replication(cs, args):
 | |
|     """Enables replication for group."""
 | |
| 
 | |
|     shell_utils.find_group(cs, args.group).enable_replication()
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.38')
 | |
| @utils.arg('group',
 | |
|            metavar='<group>',
 | |
|            help='Name or ID of the group.')
 | |
| def do_group_disable_replication(cs, args):
 | |
|     """Disables replication for group."""
 | |
| 
 | |
|     shell_utils.find_group(cs, args.group).disable_replication()
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.38')
 | |
| @utils.arg('group',
 | |
|            metavar='<group>',
 | |
|            help='Name or ID of the group.')
 | |
| @utils.arg('--allow-attached-volume',
 | |
|            action='store_true',
 | |
|            default=False,
 | |
|            help='Allows or disallows group with '
 | |
|                 'attached volumes to be failed over.')
 | |
| @utils.arg('--secondary-backend-id',
 | |
|            metavar='<secondary_backend_id>',
 | |
|            help='Secondary backend id. Default=None.')
 | |
| def do_group_failover_replication(cs, args):
 | |
|     """Fails over replication for group."""
 | |
| 
 | |
|     shell_utils.find_group(cs, args.group).failover_replication(
 | |
|         allow_attached_volume=args.allow_attached_volume,
 | |
|         secondary_backend_id=args.secondary_backend_id)
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.38')
 | |
| @utils.arg('group',
 | |
|            metavar='<group>',
 | |
|            help='Name or ID of the group.')
 | |
| def do_group_list_replication_targets(cs, args):
 | |
|     """Lists replication targets for group.
 | |
| 
 | |
|     Example value for replication_targets:
 | |
| 
 | |
|     .. code-block: json
 | |
| 
 | |
|         {
 | |
|             'replication_targets': [{'backend_id': 'vendor-id-1',
 | |
|                                      'unique_key': 'val1',
 | |
|                                      ......},
 | |
|                                     {'backend_id': 'vendor-id-2',
 | |
|                                      'unique_key': 'val2',
 | |
|                                      ......}]
 | |
|         }
 | |
|     """
 | |
| 
 | |
|     rc, replication_targets = shell_utils.find_group(
 | |
|         cs, args.group).list_replication_targets()
 | |
|     rep_targets = replication_targets.get('replication_targets')
 | |
|     if rep_targets and len(rep_targets) > 0:
 | |
|         utils.print_list(rep_targets, [key for key in rep_targets[0].keys()])
 | |
| 
 | |
| 
 | |
| @utils.arg('--all-tenants',
 | |
|            dest='all_tenants',
 | |
|            metavar='<0|1>',
 | |
|            nargs='?',
 | |
|            type=int,
 | |
|            const=1,
 | |
|            default=0,
 | |
|            help='Shows details for all tenants. Admin only.')
 | |
| @utils.arg('--status',
 | |
|            metavar='<status>',
 | |
|            default=None,
 | |
|            help="Filters results by a status. Default=None. "
 | |
|                 "%s" % FILTER_DEPRECATED)
 | |
| @utils.arg('--group-id',
 | |
|            metavar='<group_id>',
 | |
|            default=None,
 | |
|            help="Filters results by a group ID. Default=None. "
 | |
|                 "%s" % FILTER_DEPRECATED)
 | |
| @utils.arg('--filters',
 | |
|            type=six.text_type,
 | |
|            nargs='*',
 | |
|            start_version='3.33',
 | |
|            metavar='<key=value>',
 | |
|            default=None,
 | |
|            help="Filter key and value pairs. Please use 'cinder list-filters' "
 | |
|                 "to check enabled filters from server. Use 'key~=value' "
 | |
|                 "for inexact filtering if the key supports. Default=None.")
 | |
| def do_group_snapshot_list(cs, args):
 | |
|     """Lists all group snapshots."""
 | |
| 
 | |
|     all_tenants = int(os.environ.get("ALL_TENANTS", args.all_tenants))
 | |
| 
 | |
|     search_opts = {
 | |
|         'all_tenants': all_tenants,
 | |
|         'status': args.status,
 | |
|         'group_id': args.group_id,
 | |
|     }
 | |
|     # Update search option with `filters`
 | |
|     if hasattr(args, 'filters') and args.filters is not None:
 | |
|         search_opts.update(shell_utils.extract_filters(args.filters))
 | |
| 
 | |
|     group_snapshots = cs.group_snapshots.list(search_opts=search_opts)
 | |
| 
 | |
|     columns = ['ID', 'Status', 'Name']
 | |
|     utils.print_list(group_snapshots, columns)
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.14')
 | |
| @utils.arg('group_snapshot',
 | |
|            metavar='<group_snapshot>',
 | |
|            help='Name or ID of group snapshot.')
 | |
| def do_group_snapshot_show(cs, args):
 | |
|     """Shows group snapshot details."""
 | |
|     info = dict()
 | |
|     group_snapshot = shell_utils.find_group_snapshot(cs, args.group_snapshot)
 | |
|     info.update(group_snapshot._info)
 | |
| 
 | |
|     info.pop('links', None)
 | |
|     utils.print_dict(info)
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.14')
 | |
| @utils.arg('group',
 | |
|            metavar='<group>',
 | |
|            help='Name or ID of a group.')
 | |
| @utils.arg('--name',
 | |
|            metavar='<name>',
 | |
|            default=None,
 | |
|            help='Group snapshot name. Default=None.')
 | |
| @utils.arg('--description',
 | |
|            metavar='<description>',
 | |
|            default=None,
 | |
|            help='Group snapshot description. Default=None.')
 | |
| def do_group_snapshot_create(cs, args):
 | |
|     """Creates a group snapshot."""
 | |
|     group = shell_utils.find_group(cs, args.group)
 | |
|     group_snapshot = cs.group_snapshots.create(
 | |
|         group.id,
 | |
|         args.name,
 | |
|         args.description)
 | |
| 
 | |
|     info = dict()
 | |
|     group_snapshot = cs.group_snapshots.get(group_snapshot.id)
 | |
|     info.update(group_snapshot._info)
 | |
| 
 | |
|     info.pop('links', None)
 | |
|     utils.print_dict(info)
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.14')
 | |
| @utils.arg('group_snapshot',
 | |
|            metavar='<group_snapshot>', nargs='+',
 | |
|            help='Name or ID of one or more group snapshots to be deleted.')
 | |
| def do_group_snapshot_delete(cs, args):
 | |
|     """Removes one or more group snapshots."""
 | |
|     failure_count = 0
 | |
|     for group_snapshot in args.group_snapshot:
 | |
|         try:
 | |
|             shell_utils.find_group_snapshot(cs, group_snapshot).delete()
 | |
|         except Exception as e:
 | |
|             failure_count += 1
 | |
|             print("Delete for group snapshot %s failed: %s" %
 | |
|                   (group_snapshot, e))
 | |
|     if failure_count == len(args.group_snapshot):
 | |
|         raise exceptions.CommandError("Unable to delete any of the specified "
 | |
|                                       "group snapshots.")
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.0')
 | |
| @utils.arg('--host', metavar='<hostname>', default=None,
 | |
|            help='Host name. Default=None.')
 | |
| @utils.arg('--binary', metavar='<binary>', default=None,
 | |
|            help='Service binary. Default=None.')
 | |
| @utils.arg('--withreplication',
 | |
|            metavar='<True|False>',
 | |
|            const=True,
 | |
|            nargs='?',
 | |
|            default=False,
 | |
|            start_version='3.7',
 | |
|            help='Enables or disables display of '
 | |
|                 'Replication info for c-vol services. Default=False.')
 | |
| def do_service_list(cs, args):
 | |
|     """Lists all services. Filter by host and service binary."""
 | |
|     if hasattr(args, 'withreplication'):
 | |
|         replication = strutils.bool_from_string(args.withreplication,
 | |
|                                                 strict=True)
 | |
|     else:
 | |
|         replication = False
 | |
| 
 | |
|     result = cs.services.list(host=args.host, binary=args.binary)
 | |
|     columns = ["Binary", "Host", "Zone", "Status", "State", "Updated_at"]
 | |
|     if cs.api_version.matches('3.7'):
 | |
|         columns.append('Cluster')
 | |
|     if replication:
 | |
|         columns.extend(["Replication Status", "Active Backend ID", "Frozen"])
 | |
|     # NOTE(jay-lau-513): we check if the response has disabled_reason
 | |
|     # so as not to add the column when the extended ext is not enabled.
 | |
|     if result and hasattr(result[0], 'disabled_reason'):
 | |
|         columns.append("Disabled Reason")
 | |
|     utils.print_list(result, columns)
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.8')
 | |
| @utils.arg('host',
 | |
|            metavar='<host>',
 | |
|            help='Cinder host on which to list manageable snapshots; '
 | |
|                 'takes the form: host@backend-name#pool')
 | |
| @utils.arg('--detailed',
 | |
|            metavar='<detailed>',
 | |
|            default=True,
 | |
|            help='Returned detailed information (default true).')
 | |
| @utils.arg('--marker',
 | |
|            metavar='<marker>',
 | |
|            default=None,
 | |
|            help='Begin returning volumes that appear later in the volume '
 | |
|                 'list than that represented by this reference. This reference '
 | |
|                 'should be json like. '
 | |
|                 'Default=None.')
 | |
| @utils.arg('--limit',
 | |
|            metavar='<limit>',
 | |
|            default=None,
 | |
|            help='Maximum number of volumes to return. Default=None.')
 | |
| @utils.arg('--offset',
 | |
|            metavar='<offset>',
 | |
|            default=None,
 | |
|            help='Number of volumes to skip after marker. Default=None.')
 | |
| @utils.arg('--sort',
 | |
|            metavar='<key>[:<direction>]',
 | |
|            default=None,
 | |
|            help=(('Comma-separated list of sort keys and directions in the '
 | |
|                   'form of <key>[:<asc|desc>]. '
 | |
|                   'Valid keys: %s. '
 | |
|                   'Default=None.'
 | |
|                   ) % ', '.join(base.SORT_MANAGEABLE_KEY_VALUES)))
 | |
| def do_snapshot_manageable_list(cs, args):
 | |
|     """Lists all manageable snapshots."""
 | |
|     # pylint: disable=function-redefined
 | |
|     detailed = strutils.bool_from_string(args.detailed)
 | |
|     snapshots = cs.volume_snapshots.list_manageable(host=args.host,
 | |
|                                                     detailed=detailed,
 | |
|                                                     marker=args.marker,
 | |
|                                                     limit=args.limit,
 | |
|                                                     offset=args.offset,
 | |
|                                                     sort=args.sort)
 | |
|     columns = ['reference', 'size', 'safe_to_manage', 'source_reference']
 | |
|     if detailed:
 | |
|         columns.extend(['reason_not_safe', 'cinder_id', 'extra_info'])
 | |
|     utils.print_list(snapshots, columns, sortby_index=None)
 | |
| 
 | |
| 
 | |
| @api_versions.wraps("3.0")
 | |
| def do_api_version(cs, args):
 | |
|     """Display the server API version information."""
 | |
|     columns = ['ID', 'Status', 'Version', 'Min_version']
 | |
|     response = cs.services.server_api_version()
 | |
|     utils.print_list(response, columns)
 | |
| 
 | |
| 
 | |
| @api_versions.wraps("3.40")
 | |
| @utils.arg(
 | |
|     'snapshot',
 | |
|     metavar='<snapshot>',
 | |
|     help='Name or ID of the snapshot to restore. The snapshot must be the '
 | |
|          'most recent one known to cinder.')
 | |
| def do_revert_to_snapshot(cs, args):
 | |
|     """Revert a volume to the specified snapshot."""
 | |
|     snapshot = shell_utils.find_volume_snapshot(cs, args.snapshot)
 | |
|     volume = utils.find_volume(cs, snapshot.volume_id)
 | |
|     volume.revert_to_snapshot(snapshot)
 | |
| 
 | |
| 
 | |
| @api_versions.wraps("3.3")
 | |
| @utils.arg('--marker',
 | |
|            metavar='<marker>',
 | |
|            default=None,
 | |
|            start_version='3.5',
 | |
|            help='Begin returning message that appear later in the message '
 | |
|                 'list than that represented by this id. '
 | |
|                 'Default=None.')
 | |
| @utils.arg('--limit',
 | |
|            metavar='<limit>',
 | |
|            default=None,
 | |
|            start_version='3.5',
 | |
|            help='Maximum number of messages to return. Default=None.')
 | |
| @utils.arg('--sort',
 | |
|            metavar='<key>[:<direction>]',
 | |
|            default=None,
 | |
|            start_version='3.5',
 | |
|            help=(('Comma-separated list of sort keys and directions in the '
 | |
|                   'form of <key>[:<asc|desc>]. '
 | |
|                   'Valid keys: %s. '
 | |
|                   'Default=None.') % ', '.join(base.SORT_KEY_VALUES)))
 | |
| @utils.arg('--resource_uuid',
 | |
|            metavar='<resource_uuid>',
 | |
|            default=None,
 | |
|            help="Filters results by a resource uuid. Default=None. "
 | |
|                 "%s" % FILTER_DEPRECATED)
 | |
| @utils.arg('--resource_type',
 | |
|            metavar='<type>',
 | |
|            default=None,
 | |
|            help="Filters results by a resource type. Default=None. "
 | |
|                 "%s" % FILTER_DEPRECATED)
 | |
| @utils.arg('--event_id',
 | |
|            metavar='<id>',
 | |
|            default=None,
 | |
|            help="Filters results by event id. Default=None. "
 | |
|                 "%s" % FILTER_DEPRECATED)
 | |
| @utils.arg('--request_id',
 | |
|            metavar='<request_id>',
 | |
|            default=None,
 | |
|            help="Filters results by request id. Default=None. "
 | |
|                 "%s" % FILTER_DEPRECATED)
 | |
| @utils.arg('--level',
 | |
|            metavar='<level>',
 | |
|            default=None,
 | |
|            help="Filters results by the message level. Default=None. "
 | |
|                 "%s" % FILTER_DEPRECATED)
 | |
| @utils.arg('--filters',
 | |
|            type=six.text_type,
 | |
|            nargs='*',
 | |
|            start_version='3.33',
 | |
|            metavar='<key=value>',
 | |
|            default=None,
 | |
|            help="Filter key and value pairs. Please use 'cinder list-filters' "
 | |
|                 "to check enabled filters from server. Use 'key~=value' "
 | |
|                 "for inexact filtering if the key supports. Default=None.")
 | |
| def do_message_list(cs, args):
 | |
|     """Lists all messages."""
 | |
|     search_opts = {
 | |
|         'resource_uuid': args.resource_uuid,
 | |
|         'event_id': args.event_id,
 | |
|         'request_id': args.request_id,
 | |
|     }
 | |
|     # Update search option with `filters`
 | |
|     if hasattr(args, 'filters') and args.filters is not None:
 | |
|         search_opts.update(shell_utils.extract_filters(args.filters))
 | |
|     if args.resource_type:
 | |
|         search_opts['resource_type'] = args.resource_type.upper()
 | |
|     if args.level:
 | |
|         search_opts['message_level'] = args.level.upper()
 | |
| 
 | |
|     marker = args.marker if hasattr(args, 'marker') else None
 | |
|     limit = args.limit if hasattr(args, 'limit') else None
 | |
|     sort = args.sort if hasattr(args, 'sort') else None
 | |
| 
 | |
|     messages = cs.messages.list(search_opts=search_opts,
 | |
|                                 marker=marker,
 | |
|                                 limit=limit,
 | |
|                                 sort=sort)
 | |
| 
 | |
|     columns = ['ID', 'Resource Type', 'Resource UUID', 'Event ID',
 | |
|                'User Message']
 | |
|     if sort:
 | |
|         sortby_index = None
 | |
|     else:
 | |
|         sortby_index = 0
 | |
|     utils.print_list(messages, columns, sortby_index=sortby_index)
 | |
| 
 | |
| 
 | |
| @api_versions.wraps("3.3")
 | |
| @utils.arg('message',
 | |
|            metavar='<message>',
 | |
|            help='ID of message.')
 | |
| def do_message_show(cs, args):
 | |
|     """Shows message details."""
 | |
|     info = dict()
 | |
|     message = shell_utils.find_message(cs, args.message)
 | |
|     info.update(message._info)
 | |
|     info.pop('links', None)
 | |
|     utils.print_dict(info)
 | |
| 
 | |
| 
 | |
| @api_versions.wraps("3.3")
 | |
| @utils.arg('message',
 | |
|            metavar='<message>', nargs='+',
 | |
|            help='ID of one or more message to be deleted.')
 | |
| def do_message_delete(cs, args):
 | |
|     """Removes one or more messages."""
 | |
|     failure_count = 0
 | |
|     for message in args.message:
 | |
|         try:
 | |
|             shell_utils.find_message(cs, message).delete()
 | |
|         except Exception as e:
 | |
|             failure_count += 1
 | |
|             print("Delete for message %s failed: %s" % (message, e))
 | |
|     if failure_count == len(args.message):
 | |
|         raise exceptions.CommandError("Unable to delete any of the specified "
 | |
|                                       "messages.")
 | |
| 
 | |
| 
 | |
| @utils.arg('--all-tenants',
 | |
|            dest='all_tenants',
 | |
|            metavar='<0|1>',
 | |
|            nargs='?',
 | |
|            type=int,
 | |
|            const=1,
 | |
|            default=0,
 | |
|            help='Shows details for all tenants. Admin only.')
 | |
| @utils.arg('--all_tenants',
 | |
|            nargs='?',
 | |
|            type=int,
 | |
|            const=1,
 | |
|            help=argparse.SUPPRESS)
 | |
| @utils.arg('--name',
 | |
|            metavar='<name>',
 | |
|            default=None,
 | |
|            help="Filters results by a name. Default=None. "
 | |
|                 "%s" % FILTER_DEPRECATED)
 | |
| @utils.arg('--display-name',
 | |
|            help=argparse.SUPPRESS)
 | |
| @utils.arg('--display_name',
 | |
|            help=argparse.SUPPRESS)
 | |
| @utils.arg('--status',
 | |
|            metavar='<status>',
 | |
|            default=None,
 | |
|            help="Filters results by a status. Default=None. "
 | |
|                 "%s" % FILTER_DEPRECATED)
 | |
| @utils.arg('--volume-id',
 | |
|            metavar='<volume-id>',
 | |
|            default=None,
 | |
|            help="Filters results by a volume ID. Default=None. "
 | |
|                 "%s" % FILTER_DEPRECATED)
 | |
| @utils.arg('--volume_id',
 | |
|            help=argparse.SUPPRESS)
 | |
| @utils.arg('--marker',
 | |
|            metavar='<marker>',
 | |
|            default=None,
 | |
|            help='Begin returning snapshots that appear later in the snapshot '
 | |
|                 'list than that represented by this id. '
 | |
|                 'Default=None.')
 | |
| @utils.arg('--limit',
 | |
|            metavar='<limit>',
 | |
|            default=None,
 | |
|            help='Maximum number of snapshots to return. Default=None.')
 | |
| @utils.arg('--sort',
 | |
|            metavar='<key>[:<direction>]',
 | |
|            default=None,
 | |
|            help=(('Comma-separated list of sort keys and directions in the '
 | |
|                   'form of <key>[:<asc|desc>]. '
 | |
|                   'Valid keys: %s. '
 | |
|                   'Default=None.') % ', '.join(base.SORT_KEY_VALUES)))
 | |
| @utils.arg('--tenant',
 | |
|            type=str,
 | |
|            dest='tenant',
 | |
|            nargs='?',
 | |
|            metavar='<tenant>',
 | |
|            help='Display information from single tenant (Admin only).')
 | |
| @utils.arg('--metadata',
 | |
|            nargs='*',
 | |
|            metavar='<key=value>',
 | |
|            default=None,
 | |
|            start_version='3.22',
 | |
|            help="Filters results by a metadata key and value pair. Require "
 | |
|                 "volume api version >=3.22. Default=None. "
 | |
|                 "%s" % FILTER_DEPRECATED)
 | |
| @utils.arg('--filters',
 | |
|            type=six.text_type,
 | |
|            nargs='*',
 | |
|            start_version='3.33',
 | |
|            metavar='<key=value>',
 | |
|            default=None,
 | |
|            help="Filter key and value pairs. Please use 'cinder list-filters' "
 | |
|                 "to check enabled filters from server. Use 'key~=value' "
 | |
|                 "for inexact filtering if the key supports. Default=None.")
 | |
| def do_snapshot_list(cs, args):
 | |
|     """Lists all snapshots."""
 | |
|     # pylint: disable=function-redefined
 | |
|     all_tenants = (1 if args.tenant else
 | |
|                    int(os.environ.get("ALL_TENANTS", args.all_tenants)))
 | |
| 
 | |
|     if args.display_name is not None:
 | |
|         args.name = args.display_name
 | |
| 
 | |
|     metadata = None
 | |
|     try:
 | |
|         if args.metadata:
 | |
|             metadata = shell_utils.extract_metadata(args)
 | |
|     except AttributeError:
 | |
|         pass
 | |
| 
 | |
|     search_opts = {
 | |
|         'all_tenants': all_tenants,
 | |
|         'name': args.name,
 | |
|         'status': args.status,
 | |
|         'volume_id': args.volume_id,
 | |
|         'project_id': args.tenant,
 | |
|         'metadata': metadata
 | |
|     }
 | |
| 
 | |
|     # Update search option with `filters`
 | |
|     if hasattr(args, 'filters') and args.filters is not None:
 | |
|         search_opts.update(shell_utils.extract_filters(args.filters))
 | |
| 
 | |
|     snapshots = cs.volume_snapshots.list(search_opts=search_opts,
 | |
|                                          marker=args.marker,
 | |
|                                          limit=args.limit,
 | |
|                                          sort=args.sort)
 | |
|     shell_utils.translate_volume_snapshot_keys(snapshots)
 | |
|     sortby_index = None if args.sort else 0
 | |
|     if cs.api_version >= api_versions.APIVersion("3.41"):
 | |
|         utils.print_list(snapshots,
 | |
|                          ['ID', 'Volume ID', 'Status',
 | |
|                           'Name', 'Size', 'User ID'],
 | |
|                          sortby_index=sortby_index)
 | |
|     else:
 | |
|         utils.print_list(snapshots,
 | |
|                          ['ID', 'Volume ID', 'Status', 'Name', 'Size'],
 | |
|                          sortby_index=sortby_index)
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.27')
 | |
| @utils.arg('--all-tenants',
 | |
|            dest='all_tenants',
 | |
|            metavar='<0|1>',
 | |
|            nargs='?',
 | |
|            type=int,
 | |
|            const=1,
 | |
|            default=utils.env('ALL_TENANTS', default=0),
 | |
|            help='Shows details for all tenants. Admin only.')
 | |
| @utils.arg('--volume-id',
 | |
|            metavar='<volume-id>',
 | |
|            default=None,
 | |
|            help="Filters results by a volume ID. Default=None. "
 | |
|                 "%s" % FILTER_DEPRECATED)
 | |
| @utils.arg('--status',
 | |
|            metavar='<status>',
 | |
|            default=None,
 | |
|            help="Filters results by a status. Default=None. "
 | |
|                 "%s" % FILTER_DEPRECATED)
 | |
| @utils.arg('--marker',
 | |
|            metavar='<marker>',
 | |
|            default=None,
 | |
|            help='Begin returning attachments that appear later in '
 | |
|                 'attachment list than that represented by this id. '
 | |
|                 'Default=None.')
 | |
| @utils.arg('--limit',
 | |
|            metavar='<limit>',
 | |
|            default=None,
 | |
|            help='Maximum number of attachments to return. Default=None.')
 | |
| @utils.arg('--sort',
 | |
|            metavar='<key>[:<direction>]',
 | |
|            default=None,
 | |
|            help=(('Comma-separated list of sort keys and directions in the '
 | |
|                   'form of <key>[:<asc|desc>]. '
 | |
|                   'Valid keys: %s. '
 | |
|                   'Default=None.') % ', '.join(base.SORT_KEY_VALUES)))
 | |
| @utils.arg('--tenant',
 | |
|            type=str,
 | |
|            dest='tenant',
 | |
|            nargs='?',
 | |
|            metavar='<tenant>',
 | |
|            help='Display information from single tenant (Admin only).')
 | |
| @utils.arg('--filters',
 | |
|            type=six.text_type,
 | |
|            nargs='*',
 | |
|            start_version='3.33',
 | |
|            metavar='<key=value>',
 | |
|            default=None,
 | |
|            help="Filter key and value pairs. Please use 'cinder list-filters' "
 | |
|                 "to check enabled filters from server. Use 'key~=value' "
 | |
|                 "for inexact filtering if the key supports. Default=None.")
 | |
| def do_attachment_list(cs, args):
 | |
|     """Lists all attachments."""
 | |
|     search_opts = {
 | |
|         'all_tenants': 1 if args.tenant else args.all_tenants,
 | |
|         'project_id': args.tenant,
 | |
|         'status': args.status,
 | |
|         'volume_id': args.volume_id,
 | |
|     }
 | |
|     # Update search option with `filters`
 | |
|     if hasattr(args, 'filters') and args.filters is not None:
 | |
|         search_opts.update(shell_utils.extract_filters(args.filters))
 | |
| 
 | |
|     attachments = cs.attachments.list(search_opts=search_opts,
 | |
|                                       marker=args.marker,
 | |
|                                       limit=args.limit,
 | |
|                                       sort=args.sort)
 | |
|     columns = ['ID', 'Volume ID', 'Status', 'Server ID']
 | |
|     if args.sort:
 | |
|         sortby_index = None
 | |
|     else:
 | |
|         sortby_index = 0
 | |
|     utils.print_list(attachments, columns, sortby_index=sortby_index)
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.27')
 | |
| @utils.arg('attachment',
 | |
|            metavar='<attachment>',
 | |
|            help='ID of attachment.')
 | |
| def do_attachment_show(cs, args):
 | |
|     """Show detailed information for attachment."""
 | |
|     attachment = cs.attachments.show(args.attachment)
 | |
|     attachment_dict = attachment.to_dict()
 | |
|     connection_dict = attachment_dict.pop('connection_info', {})
 | |
|     utils.print_dict(attachment_dict)
 | |
| 
 | |
|     # TODO(jdg): Need to add checks here like admin/policy for displaying the
 | |
|     # connection_info, this is still experimental so we'll leave it enabled for
 | |
|     # now
 | |
|     if connection_dict:
 | |
|         utils.print_dict(connection_dict)
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.27')
 | |
| @utils.arg('volume',
 | |
|            metavar='<volume>',
 | |
|            help='Name or ID of volume or volumes to attach.')
 | |
| @utils.arg('server_id',
 | |
|            metavar='<server_id>',
 | |
|            help='ID of server attaching to.')
 | |
| @utils.arg('--connect',
 | |
|            metavar='<connect>',
 | |
|            default=False,
 | |
|            help='Make an active connection using provided connector info '
 | |
|                 '(True or False).')
 | |
| @utils.arg('--initiator',
 | |
|            metavar='<initiator>',
 | |
|            default=None,
 | |
|            help='iqn of the initiator attaching to.  Default=None.')
 | |
| @utils.arg('--ip',
 | |
|            metavar='<ip>',
 | |
|            default=None,
 | |
|            help='ip of the system attaching to.  Default=None.')
 | |
| @utils.arg('--host',
 | |
|            metavar='<host>',
 | |
|            default=None,
 | |
|            help='Name of the host attaching to. Default=None.')
 | |
| @utils.arg('--platform',
 | |
|            metavar='<platform>',
 | |
|            default='x86_64',
 | |
|            help='Platform type. Default=x86_64.')
 | |
| @utils.arg('--ostype',
 | |
|            metavar='<ostype>',
 | |
|            default='linux2',
 | |
|            help='OS type. Default=linux2.')
 | |
| @utils.arg('--multipath',
 | |
|            metavar='<multipath>',
 | |
|            default=False,
 | |
|            help='Use multipath. Default=False.')
 | |
| @utils.arg('--mountpoint',
 | |
|            metavar='<mountpoint>',
 | |
|            default=None,
 | |
|            help='Mountpoint volume will be attached at. Default=None.')
 | |
| def do_attachment_create(cs, args):
 | |
|     """Create an attachment for a cinder volume."""
 | |
| 
 | |
|     connector = {}
 | |
|     if strutils.bool_from_string(args.connect, strict=True):
 | |
|         # FIXME(jdg): Add in all the options when they're finalized
 | |
|         connector = {'initiator': args.initiator,
 | |
|                      'ip': args.ip,
 | |
|                      'platform': args.platform,
 | |
|                      'host': args.host,
 | |
|                      'os_type': args.ostype,
 | |
|                      'multipath': args.multipath,
 | |
|                      'mountpoint': args.mountpoint}
 | |
|     volume = utils.find_volume(cs, args.volume)
 | |
|     attachment = cs.attachments.create(volume.id,
 | |
|                                        connector,
 | |
|                                        args.server_id)
 | |
|     connector_dict = attachment.pop('connection_info', None)
 | |
|     utils.print_dict(attachment)
 | |
|     if connector_dict:
 | |
|         utils.print_dict(connector_dict)
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.27')
 | |
| @utils.arg('attachment',
 | |
|            metavar='<attachment>',
 | |
|            help='ID of attachment.')
 | |
| @utils.arg('--initiator',
 | |
|            metavar='<initiator>',
 | |
|            default=None,
 | |
|            help='iqn of the initiator attaching to.  Default=None.')
 | |
| @utils.arg('--ip',
 | |
|            metavar='<ip>',
 | |
|            default=None,
 | |
|            help='ip of the system attaching to.  Default=None.')
 | |
| @utils.arg('--host',
 | |
|            metavar='<host>',
 | |
|            default=None,
 | |
|            help='Name of the host attaching to. Default=None.')
 | |
| @utils.arg('--platform',
 | |
|            metavar='<platform>',
 | |
|            default='x86_64',
 | |
|            help='Platform type. Default=x86_64.')
 | |
| @utils.arg('--ostype',
 | |
|            metavar='<ostype>',
 | |
|            default='linux2',
 | |
|            help='OS type. Default=linux2.')
 | |
| @utils.arg('--multipath',
 | |
|            metavar='<multipath>',
 | |
|            default=False,
 | |
|            help='Use multipath. Default=False.')
 | |
| @utils.arg('--mountpoint',
 | |
|            metavar='<mountpoint>',
 | |
|            default=None,
 | |
|            help='Mountpoint volume will be attached at. Default=None.')
 | |
| def do_attachment_update(cs, args):
 | |
|     """Update an attachment for a cinder volume.
 | |
|     This call is designed to be more of an attachment completion than anything
 | |
|     else.  It expects the value of a connector object to notify the driver that
 | |
|     the volume is going to be connected and where it's being connected to.
 | |
|     """
 | |
|     connector = {'initiator': args.initiator,
 | |
|                  'ip': args.ip,
 | |
|                  'platform': args.platform,
 | |
|                  'host': args.host,
 | |
|                  'os_type': args.ostype,
 | |
|                  'multipath': args.multipath,
 | |
|                  'mountpoint': args.mountpoint}
 | |
|     attachment = cs.attachments.update(args.attachment,
 | |
|                                        connector)
 | |
|     attachment_dict = attachment.to_dict()
 | |
|     connector_dict = attachment_dict.pop('connection_info', None)
 | |
|     utils.print_dict(attachment_dict)
 | |
|     if connector_dict:
 | |
|         utils.print_dict(connector_dict)
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.27')
 | |
| @utils.arg('attachment',
 | |
|            metavar='<attachment>', nargs='+',
 | |
|            help='ID of attachment or attachments to delete.')
 | |
| def do_attachment_delete(cs, args):
 | |
|     """Delete an attachment for a cinder volume."""
 | |
|     for attachment in args.attachment:
 | |
|         cs.attachments.delete(attachment)
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.44')
 | |
| @utils.arg('attachment',
 | |
|            metavar='<attachment>', nargs='+',
 | |
|            help='ID of attachment or attachments to delete.')
 | |
| def do_attachment_complete(cs, args):
 | |
|     """Complete an attachment for a cinder volume."""
 | |
|     for attachment in args.attachment:
 | |
|         cs.attachments.complete(attachment)
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.0')
 | |
| def do_version_list(cs, args):
 | |
|     """List all API versions."""
 | |
|     result = cs.services.server_api_version()
 | |
|     if 'min_version' in dir(result[0]):
 | |
|         columns = ["Id", "Status", "Updated", "Min Version", "Version"]
 | |
|     else:
 | |
|         columns = ["Id", "Status", "Updated"]
 | |
| 
 | |
|     print("Client supported API versions:")
 | |
|     print("Minimum version %(v)s" %
 | |
|           {'v': api_versions.MIN_VERSION})
 | |
|     print("Maximum version %(v)s" %
 | |
|           {'v': api_versions.MAX_VERSION})
 | |
| 
 | |
|     print("\nServer supported API versions:")
 | |
|     utils.print_list(result, columns)
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.32')
 | |
| @utils.arg('level',
 | |
|            metavar='<log-level>',
 | |
|            choices=('INFO', 'WARNING', 'ERROR', 'DEBUG',
 | |
|                     'info', 'warning', 'error', 'debug'),
 | |
|            help='Desired log level.')
 | |
| @utils.arg('--binary',
 | |
|            choices=('', '*', 'cinder-api', 'cinder-volume', 'cinder-scheduler',
 | |
|                     'cinder-backup'),
 | |
|            default='',
 | |
|            help='Binary to change.')
 | |
| @utils.arg('--server',
 | |
|            default='',
 | |
|            help='Host or cluster value for service.')
 | |
| @utils.arg('--prefix',
 | |
|            default='',
 | |
|            help='Prefix for the log. ie: "cinder.volume.drivers.".')
 | |
| def do_service_set_log(cs, args):
 | |
|     cs.services.set_log_levels(args.level, args.binary, args.server,
 | |
|                                args.prefix)
 | |
| 
 | |
| 
 | |
| @api_versions.wraps('3.32')
 | |
| @utils.arg('--binary',
 | |
|            choices=('', '*', 'cinder-api', 'cinder-volume', 'cinder-scheduler',
 | |
|                     'cinder-backup'),
 | |
|            default='',
 | |
|            help='Binary to query.')
 | |
| @utils.arg('--server',
 | |
|            default='',
 | |
|            help='Host or cluster value for service.')
 | |
| @utils.arg('--prefix',
 | |
|            default='',
 | |
|            help='Prefix for the log. ie: "sqlalchemy.".')
 | |
| def do_service_get_log(cs, args):
 | |
|     log_levels = cs.services.get_log_levels(args.binary, args.server,
 | |
|                                             args.prefix)
 | |
|     columns = ('Binary', 'Host', 'Prefix', 'Level')
 | |
|     utils.print_list(log_levels, columns)
 | |
| 
 | |
| @api_versions.wraps('3.43')
 | |
| @utils.arg('volume', metavar='<volume>',
 | |
|            help='Name or ID of volume to backup.')
 | |
| @utils.arg('--container', metavar='<container>',
 | |
|            default=None,
 | |
|            help='Backup container name. Default=None.')
 | |
| @utils.arg('--display-name',
 | |
|            help=argparse.SUPPRESS)
 | |
| @utils.arg('--name', metavar='<name>',
 | |
|            default=None,
 | |
|            help='Backup name. Default=None.')
 | |
| @utils.arg('--display-description',
 | |
|            help=argparse.SUPPRESS)
 | |
| @utils.arg('--description',
 | |
|            metavar='<description>',
 | |
|            default=None,
 | |
|            help='Backup description. Default=None.')
 | |
| @utils.arg('--incremental',
 | |
|            action='store_true',
 | |
|            help='Incremental backup. Default=False.',
 | |
|            default=False)
 | |
| @utils.arg('--force',
 | |
|            action='store_true',
 | |
|            help='Allows or disallows backup of a volume '
 | |
|            'when the volume is attached to an instance. '
 | |
|            'If set to True, backs up the volume whether '
 | |
|            'its status is "available" or "in-use". The backup '
 | |
|            'of an "in-use" volume means your data is crash '
 | |
|            'consistent. Default=False.',
 | |
|            default=False)
 | |
| @utils.arg('--snapshot-id',
 | |
|            metavar='<snapshot-id>',
 | |
|            default=None,
 | |
|            help='ID of snapshot to backup. Default=None.')
 | |
| @utils.arg('--metadata',
 | |
|            nargs='*',
 | |
|            metavar='<key=value>',
 | |
|            default=None,
 | |
|            help='Metadata key and value pairs. Default=None.')
 | |
| def do_backup_create(cs, args):
 | |
|     """Creates a volume backup."""
 | |
|     if args.display_name is not None:
 | |
|         args.name = args.display_name
 | |
| 
 | |
|     if args.display_description is not None:
 | |
|         args.description = args.display_description
 | |
| 
 | |
|     volume = utils.find_volume(cs, args.volume)
 | |
|     backup = cs.backups.create(volume.id,
 | |
|                                args.container,
 | |
|                                args.name,
 | |
|                                args.description,
 | |
|                                args.incremental,
 | |
|                                args.force,
 | |
|                                args.snapshot_id,
 | |
|                                args.metadata)
 | |
| 
 | |
|     info = {"volume_id": volume.id}
 | |
|     info.update(backup._info)
 | |
| 
 | |
|     if 'links' in info:
 | |
|         info.pop('links')
 | |
| 
 | |
|     utils.print_dict(info)
 |