 2d7ae2cd38
			
		
	
	2d7ae2cd38
	
	
	
		
			
			Move more code to shell_utils that is only used for shell operations. The benefit of this is that the cinderclient library becomes lighter-weight, because users of the lib no longer have to import prettytable and extra code. Change-Id: I7bf6bd91ee5746d1ad4bd4504f3a056d03ae86a9
		
			
				
	
	
		
			420 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			420 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # 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.
 | |
| 
 | |
| import sys
 | |
| import time
 | |
| 
 | |
| import prettytable
 | |
| 
 | |
| from cinderclient import exceptions
 | |
| from cinderclient import utils
 | |
| 
 | |
| _quota_resources = ['volumes', 'snapshots', 'gigabytes',
 | |
|                     'backups', 'backup_gigabytes',
 | |
|                     'per_volume_gigabytes', 'groups', ]
 | |
| _quota_infos = ['Type', 'In_use', 'Reserved', 'Limit', 'Allocated']
 | |
| 
 | |
| 
 | |
| def _print(pt, order):
 | |
|     print(pt.get_string(sortby=order))
 | |
| 
 | |
| 
 | |
| def _pretty_format_dict(data_dict):
 | |
|     formatted_data = []
 | |
| 
 | |
|     for k in sorted(data_dict):
 | |
|         formatted_data.append("%s : %s" % (k, data_dict[k]))
 | |
| 
 | |
|     return "\n".join(formatted_data)
 | |
| 
 | |
| 
 | |
| def print_list(objs, fields, exclude_unavailable=False, formatters=None,
 | |
|                sortby_index=0):
 | |
|     '''Prints a list of objects.
 | |
| 
 | |
|     @param objs: Objects to print
 | |
|     @param fields: Fields on each object to be printed
 | |
|     @param exclude_unavailable: Boolean to decide if unavailable fields are
 | |
|                                 removed
 | |
|     @param formatters: Custom field formatters
 | |
|     @param sortby_index: Results sorted against the key in the fields list at
 | |
|                          this index; if None then the object order is not
 | |
|                          altered
 | |
|     '''
 | |
|     formatters = formatters or {}
 | |
|     mixed_case_fields = ['serverId']
 | |
|     removed_fields = []
 | |
|     rows = []
 | |
| 
 | |
|     for o in objs:
 | |
|         row = []
 | |
|         for field in fields:
 | |
|             if field in removed_fields:
 | |
|                 continue
 | |
|             if field in formatters:
 | |
|                 row.append(formatters[field](o))
 | |
|             else:
 | |
|                 if field in mixed_case_fields:
 | |
|                     field_name = field.replace(' ', '_')
 | |
|                 else:
 | |
|                     field_name = field.lower().replace(' ', '_')
 | |
|                 if isinstance(o, dict) and field in o:
 | |
|                     data = o[field]
 | |
|                 else:
 | |
|                     if not hasattr(o, field_name) and exclude_unavailable:
 | |
|                         removed_fields.append(field)
 | |
|                         continue
 | |
|                     else:
 | |
|                         data = getattr(o, field_name, '')
 | |
|                 if data is None:
 | |
|                     data = '-'
 | |
|                 if isinstance(data, str) and "\r" in data:
 | |
|                     data = data.replace("\r", " ")
 | |
|                 row.append(data)
 | |
|         rows.append(row)
 | |
| 
 | |
|     for f in removed_fields:
 | |
|         fields.remove(f)
 | |
| 
 | |
|     pt = prettytable.PrettyTable((f for f in fields), caching=False)
 | |
|     pt.align = 'l'
 | |
|     for row in rows:
 | |
|         count = 0
 | |
|         # Converts unicode values in dictionary to string
 | |
|         for part in row:
 | |
|             count = count + 1
 | |
|             if isinstance(part, dict):
 | |
|                 row[count - 1] = part
 | |
|         pt.add_row(row)
 | |
| 
 | |
|     if sortby_index is None:
 | |
|         order_by = None
 | |
|     else:
 | |
|         order_by = fields[sortby_index]
 | |
|     _print(pt, order_by)
 | |
| 
 | |
| 
 | |
| def print_dict(d, property="Property", formatters=None):
 | |
|     pt = prettytable.PrettyTable([property, 'Value'], caching=False)
 | |
|     pt.align = 'l'
 | |
|     formatters = formatters or {}
 | |
| 
 | |
|     for r in d.items():
 | |
|         r = list(r)
 | |
| 
 | |
|         if r[0] in formatters:
 | |
|             if isinstance(r[1], dict):
 | |
|                 r[1] = _pretty_format_dict(r[1])
 | |
|         if isinstance(r[1], str) and "\r" in r[1]:
 | |
|             r[1] = r[1].replace("\r", " ")
 | |
|         pt.add_row(r)
 | |
|     _print(pt, property)
 | |
| 
 | |
| 
 | |
| def print_volume_image(image_resp_tuple):
 | |
|     # image_resp_tuple = tuple (response, body)
 | |
|     image = image_resp_tuple[1]
 | |
|     vt = image['os-volume_upload_image'].get('volume_type')
 | |
|     if vt is not None:
 | |
|         image['os-volume_upload_image']['volume_type'] = vt.get('name')
 | |
|     print_dict(image['os-volume_upload_image'])
 | |
| 
 | |
| 
 | |
| def poll_for_status(poll_fn, obj_id, action, final_ok_states,
 | |
|                     poll_period=5, show_progress=True):
 | |
|     """Blocks while an action occurs. Periodically shows progress."""
 | |
|     def print_progress(progress):
 | |
|         if show_progress:
 | |
|             msg = ('\rInstance %(action)s... %(progress)s%% complete'
 | |
|                    % dict(action=action, progress=progress))
 | |
|         else:
 | |
|             msg = '\rInstance %(action)s...' % dict(action=action)
 | |
| 
 | |
|         sys.stdout.write(msg)
 | |
|         sys.stdout.flush()
 | |
| 
 | |
|     print()
 | |
|     while True:
 | |
|         obj = poll_fn(obj_id)
 | |
|         status = obj.status.lower()
 | |
|         progress = getattr(obj, 'progress', None) or 0
 | |
|         if status in final_ok_states:
 | |
|             print_progress(100)
 | |
|             print("\nFinished")
 | |
|             break
 | |
|         elif status == "error":
 | |
|             print("\nError %(action)s instance" % {'action': action})
 | |
|             break
 | |
|         else:
 | |
|             print_progress(progress)
 | |
|             time.sleep(poll_period)
 | |
| 
 | |
| 
 | |
| def find_volume_snapshot(cs, snapshot):
 | |
|     """Gets a volume snapshot by name or ID."""
 | |
|     return utils.find_resource(cs.volume_snapshots, snapshot)
 | |
| 
 | |
| 
 | |
| def find_vtype(cs, vtype):
 | |
|     """Gets a volume type by name or ID."""
 | |
|     return utils.find_resource(cs.volume_types, vtype)
 | |
| 
 | |
| 
 | |
| def find_gtype(cs, gtype):
 | |
|     """Gets a group type by name or ID."""
 | |
|     return utils.find_resource(cs.group_types, gtype)
 | |
| 
 | |
| 
 | |
| def find_backup(cs, backup):
 | |
|     """Gets a backup by name or ID."""
 | |
|     return utils.find_resource(cs.backups, backup)
 | |
| 
 | |
| 
 | |
| def find_consistencygroup(cs, consistencygroup):
 | |
|     """Gets a consistency group by name or ID."""
 | |
|     return utils.find_resource(cs.consistencygroups, consistencygroup)
 | |
| 
 | |
| 
 | |
| def find_group(cs, group, **kwargs):
 | |
|     """Gets a group by name or ID."""
 | |
|     kwargs['is_group'] = True
 | |
|     return utils.find_resource(cs.groups, group, **kwargs)
 | |
| 
 | |
| 
 | |
| def find_cgsnapshot(cs, cgsnapshot):
 | |
|     """Gets a cgsnapshot by name or ID."""
 | |
|     return utils.find_resource(cs.cgsnapshots, cgsnapshot)
 | |
| 
 | |
| 
 | |
| def find_group_snapshot(cs, group_snapshot):
 | |
|     """Gets a group_snapshot by name or ID."""
 | |
|     return utils.find_resource(cs.group_snapshots, group_snapshot)
 | |
| 
 | |
| 
 | |
| def find_transfer(cs, transfer):
 | |
|     """Gets a transfer by name or ID."""
 | |
|     return utils.find_resource(cs.transfers, transfer)
 | |
| 
 | |
| 
 | |
| def find_qos_specs(cs, qos_specs):
 | |
|     """Gets a qos specs by ID."""
 | |
|     return utils.find_resource(cs.qos_specs, qos_specs)
 | |
| 
 | |
| 
 | |
| def find_message(cs, message):
 | |
|     """Gets a message by ID."""
 | |
|     return utils.find_resource(cs.messages, message)
 | |
| 
 | |
| 
 | |
| def print_volume_snapshot(snapshot):
 | |
|     print_dict(snapshot._info)
 | |
| 
 | |
| 
 | |
| def translate_keys(collection, convert):
 | |
|     for item in collection:
 | |
|         keys = item.__dict__
 | |
|         for from_key, to_key in convert:
 | |
|             if from_key in keys and to_key not in keys:
 | |
|                 setattr(item, to_key, item._info[from_key])
 | |
| 
 | |
| 
 | |
| def translate_volume_keys(collection):
 | |
|     convert = [('volumeType', 'volume_type'),
 | |
|                ('os-vol-tenant-attr:tenant_id', 'tenant_id')]
 | |
|     translate_keys(collection, convert)
 | |
| 
 | |
| 
 | |
| def translate_volume_snapshot_keys(collection):
 | |
|     convert = [('volumeId', 'volume_id')]
 | |
|     translate_keys(collection, convert)
 | |
| 
 | |
| 
 | |
| def translate_availability_zone_keys(collection):
 | |
|     convert = [('zoneName', 'name'), ('zoneState', 'status')]
 | |
|     translate_keys(collection, convert)
 | |
| 
 | |
| 
 | |
| def extract_filters(args):
 | |
|     filters = {}
 | |
|     for f in args:
 | |
|         if '=' in f:
 | |
|             (key, value) = f.split('=', 1)
 | |
|             if value.startswith('{') and value.endswith('}'):
 | |
|                 value = _build_internal_dict(value[1:-1])
 | |
|             filters[key] = value
 | |
|         else:
 | |
|             print("WARNING: Ignoring the filter %s while showing result." % f)
 | |
| 
 | |
|     return filters
 | |
| 
 | |
| 
 | |
| def _build_internal_dict(content):
 | |
|     result = {}
 | |
|     for pair in content.split(','):
 | |
|         k, v = pair.split(':', 1)
 | |
|         result.update({k.strip(): v.strip()})
 | |
|     return result
 | |
| 
 | |
| 
 | |
| def extract_metadata(args, type='user_metadata'):
 | |
|     metadata = {}
 | |
|     if type == 'image_metadata':
 | |
|         args_metadata = args.image_metadata
 | |
|     else:
 | |
|         args_metadata = args.metadata
 | |
|     for metadatum in args_metadata:
 | |
|         # unset doesn't require a val, so we have the if/else
 | |
|         if '=' in metadatum:
 | |
|             (key, value) = metadatum.split('=', 1)
 | |
|         else:
 | |
|             key = metadatum
 | |
|             value = None
 | |
| 
 | |
|         metadata[key] = value
 | |
|     return metadata
 | |
| 
 | |
| 
 | |
| def print_volume_type_list(vtypes):
 | |
|     print_list(vtypes, ['ID', 'Name', 'Description', 'Is_Public'])
 | |
| 
 | |
| 
 | |
| def print_group_type_list(gtypes):
 | |
|     print_list(gtypes, ['ID', 'Name', 'Description'])
 | |
| 
 | |
| 
 | |
| def print_resource_filter_list(filters):
 | |
|     formatter = {'Filters': lambda resource: ', '.join(resource.filters)}
 | |
|     print_list(filters, ['Resource', 'Filters'], formatters=formatter)
 | |
| 
 | |
| 
 | |
| def quota_show(quotas):
 | |
|     quotas_info_dict = quotas._info
 | |
|     quota_dict = {}
 | |
|     for resource in quotas_info_dict.keys():
 | |
|         good_name = False
 | |
|         for name in _quota_resources:
 | |
|             if resource.startswith(name):
 | |
|                 good_name = True
 | |
|         if not good_name:
 | |
|             continue
 | |
|         quota_dict[resource] = getattr(quotas, resource, None)
 | |
|     print_dict(quota_dict)
 | |
| 
 | |
| 
 | |
| def quota_usage_show(quotas):
 | |
|     quota_list = []
 | |
|     quotas_info_dict = quotas._info
 | |
|     for resource in quotas_info_dict.keys():
 | |
|         good_name = False
 | |
|         for name in _quota_resources:
 | |
|             if resource.startswith(name):
 | |
|                 good_name = True
 | |
|         if not good_name:
 | |
|             continue
 | |
|         quota_info = getattr(quotas, resource, None)
 | |
|         quota_info['Type'] = resource
 | |
|         quota_info = dict((k.capitalize(), v) for k, v in quota_info.items())
 | |
|         quota_list.append(quota_info)
 | |
|     print_list(quota_list, _quota_infos)
 | |
| 
 | |
| 
 | |
| def quota_update(manager, identifier, args):
 | |
|     updates = {}
 | |
|     for resource in _quota_resources:
 | |
|         val = getattr(args, resource, None)
 | |
|         if val is not None:
 | |
|             if args.volume_type:
 | |
|                 resource = resource + '_%s' % args.volume_type
 | |
|             updates[resource] = val
 | |
| 
 | |
|     if updates:
 | |
|         skip_validation = getattr(args, 'skip_validation', True)
 | |
|         if not skip_validation:
 | |
|             updates['skip_validation'] = skip_validation
 | |
|         quota_show(manager.update(identifier, **updates))
 | |
|     else:
 | |
|         msg = 'Must supply at least one quota field to update.'
 | |
|         raise exceptions.ClientException(code=1, message=msg)
 | |
| 
 | |
| 
 | |
| def find_volume_type(cs, vtype):
 | |
|     """Gets a volume type by name or ID."""
 | |
|     return utils.find_resource(cs.volume_types, vtype)
 | |
| 
 | |
| 
 | |
| def find_group_type(cs, gtype):
 | |
|     """Gets a group type by name or ID."""
 | |
|     return utils.find_resource(cs.group_types, gtype)
 | |
| 
 | |
| 
 | |
| def print_volume_encryption_type_list(encryption_types):
 | |
|     """
 | |
|     Lists volume encryption types.
 | |
| 
 | |
|     :param encryption_types: a list of :class: VolumeEncryptionType instances
 | |
|     """
 | |
|     print_list(encryption_types, ['Volume Type ID', 'Provider',
 | |
|                                   'Cipher', 'Key Size',
 | |
|                                   'Control Location'])
 | |
| 
 | |
| 
 | |
| def print_qos_specs(qos_specs):
 | |
|     # formatters defines field to be converted from unicode to string
 | |
|     print_dict(qos_specs._info, formatters=['specs'])
 | |
| 
 | |
| 
 | |
| def print_qos_specs_list(q_specs):
 | |
|     print_list(q_specs, ['ID', 'Name', 'Consumer', 'specs'])
 | |
| 
 | |
| 
 | |
| def print_qos_specs_and_associations_list(q_specs):
 | |
|     print_list(q_specs, ['ID', 'Name', 'Consumer', 'specs'])
 | |
| 
 | |
| 
 | |
| def print_associations_list(associations):
 | |
|     print_list(associations, ['Association_Type', 'Name', 'ID'])
 | |
| 
 | |
| 
 | |
| def _poll_for_status(poll_fn, obj_id, info, action, final_ok_states,
 | |
|                      timeout_period, global_request_id=None, messages=None,
 | |
|                      poll_period=2, status_field="status"):
 | |
|     """Block while an action is being performed."""
 | |
|     time_elapsed = 0
 | |
|     while True:
 | |
|         time.sleep(poll_period)
 | |
|         time_elapsed += poll_period
 | |
|         obj = poll_fn(obj_id)
 | |
|         status = getattr(obj, status_field)
 | |
|         info[status_field] = status
 | |
|         if status:
 | |
|             status = status.lower()
 | |
| 
 | |
|         if status in final_ok_states:
 | |
|             break
 | |
|         elif status == "error":
 | |
|             print_dict(info)
 | |
|             if global_request_id:
 | |
|                 search_opts = {
 | |
|                     'request_id': global_request_id
 | |
|                     }
 | |
|                 message_list = messages.list(search_opts=search_opts)
 | |
|                 try:
 | |
|                     fault_msg = message_list[0].user_message
 | |
|                 except IndexError:
 | |
|                     fault_msg = "Unknown error. Operation failed."
 | |
|                 raise exceptions.ResourceInErrorState(obj, fault_msg)
 | |
|         elif time_elapsed == timeout_period:
 | |
|             print_dict(info)
 | |
|             raise exceptions.TimeoutException(obj, action)
 |