diff options
Diffstat (limited to 'ceilometerclient/openstack/common/cliutils.py')
-rw-r--r-- | ceilometerclient/openstack/common/cliutils.py | 128 |
1 files changed, 120 insertions, 8 deletions
diff --git a/ceilometerclient/openstack/common/cliutils.py b/ceilometerclient/openstack/common/cliutils.py index 96725ed..c690028 100644 --- a/ceilometerclient/openstack/common/cliutils.py +++ b/ceilometerclient/openstack/common/cliutils.py @@ -16,6 +16,8 @@ # W0621: Redefining name %s from outer scope # pylint: disable=W0603,W0621 +from __future__ import print_function + import getpass import inspect import os @@ -27,7 +29,9 @@ import six from six import moves from ceilometerclient.openstack.common.apiclient import exceptions +from ceilometerclient.openstack.common.gettextutils import _ from ceilometerclient.openstack.common import strutils +from ceilometerclient.openstack.common import uuidutils def validate_args(fn, *args, **kwargs): @@ -52,7 +56,7 @@ def validate_args(fn, *args, **kwargs): required_args = argspec.args[:len(argspec.args) - num_defaults] def isbound(method): - return getattr(method, 'im_self', None) is not None + return getattr(method, '__self__', None) is not None if isbound(fn): required_args.pop(0) @@ -84,7 +88,7 @@ def env(*args, **kwargs): If all are empty, defaults to '' or keyword arg `default`. """ for arg in args: - value = os.environ.get(arg, None) + value = os.environ.get(arg) if value: return value return kwargs.get('default', '') @@ -128,7 +132,7 @@ def isunauthenticated(func): def print_list(objs, fields, formatters=None, sortby_index=0, - mixed_case_fields=None): + mixed_case_fields=None, field_labels=None): """Print a list or objects as a table, one row per object. :param objs: iterable of :class:`Resource` @@ -137,14 +141,22 @@ def print_list(objs, fields, formatters=None, sortby_index=0, :param sortby_index: index of the field for sorting table rows :param mixed_case_fields: fields corresponding to object attributes that have mixed case names (e.g., 'serverId') + :param field_labels: Labels to use in the heading of the table, default to + fields. """ formatters = formatters or {} mixed_case_fields = mixed_case_fields or [] + field_labels = field_labels or fields + if len(field_labels) != len(fields): + raise ValueError(_("Field labels list %(labels)s has different number " + "of elements than fields list %(fields)s"), + {'labels': field_labels, 'fields': fields}) + if sortby_index is None: kwargs = {} else: - kwargs = {'sortby': fields[sortby_index]} - pt = prettytable.PrettyTable(fields, caching=False) + kwargs = {'sortby': field_labels[sortby_index]} + pt = prettytable.PrettyTable(field_labels, caching=False) pt.align = 'l' for o in objs: @@ -176,9 +188,9 @@ def print_dict(dct, dict_property="Property", wrap=0): for k, v in six.iteritems(dct): # convert dict to str to check length if isinstance(v, dict): - v = str(v) + v = six.text_type(v) if wrap > 0: - v = textwrap.fill(str(v), wrap) + v = textwrap.fill(six.text_type(v), wrap) # if value has a newline, add in multiple rows # e.g. fault with stacktrace if v and isinstance(v, six.string_types) and r'\n' in v: @@ -199,7 +211,7 @@ def get_password(max_password_prompts=3): if hasattr(sys.stdin, "isatty") and sys.stdin.isatty(): # Check for Ctrl-D try: - for _ in moves.range(max_password_prompts): + for __ in moves.range(max_password_prompts): pw1 = getpass.getpass("OS Password: ") if verify: pw2 = getpass.getpass("Please verify: ") @@ -211,3 +223,103 @@ def get_password(max_password_prompts=3): except EOFError: pass return pw + + +def find_resource(manager, name_or_id, **find_args): + """Look for resource in a given manager. + + Used as a helper for the _find_* methods. + Example: + + .. code-block:: python + + def _find_hypervisor(cs, hypervisor): + #Get a hypervisor by name or ID. + return cliutils.find_resource(cs.hypervisors, hypervisor) + """ + # first try to get entity as integer id + try: + return manager.get(int(name_or_id)) + except (TypeError, ValueError, exceptions.NotFound): + pass + + # now try to get entity as uuid + try: + if six.PY2: + tmp_id = strutils.safe_encode(name_or_id) + else: + tmp_id = strutils.safe_decode(name_or_id) + + if uuidutils.is_uuid_like(tmp_id): + return manager.get(tmp_id) + except (TypeError, ValueError, exceptions.NotFound): + pass + + # for str id which is not uuid + if getattr(manager, 'is_alphanum_id_allowed', False): + try: + return manager.get(name_or_id) + except exceptions.NotFound: + pass + + try: + try: + return manager.find(human_id=name_or_id, **find_args) + except exceptions.NotFound: + pass + + # finally try to find entity by name + try: + resource = getattr(manager, 'resource_class', None) + name_attr = resource.NAME_ATTR if resource else 'name' + kwargs = {name_attr: name_or_id} + kwargs.update(find_args) + return manager.find(**kwargs) + except exceptions.NotFound: + msg = _("No %(name)s with a name or " + "ID of '%(name_or_id)s' exists.") % \ + { + "name": manager.resource_class.__name__.lower(), + "name_or_id": name_or_id + } + raise exceptions.CommandError(msg) + except exceptions.NoUniqueMatch: + msg = _("Multiple %(name)s matches found for " + "'%(name_or_id)s', use an ID to be more specific.") % \ + { + "name": manager.resource_class.__name__.lower(), + "name_or_id": name_or_id + } + raise exceptions.CommandError(msg) + + +def service_type(stype): + """Adds 'service_type' attribute to decorated function. + + Usage: + + .. code-block:: python + + @service_type('volume') + def mymethod(f): + ... + """ + def inner(f): + f.service_type = stype + return f + return inner + + +def get_service_type(f): + """Retrieves service type from function.""" + return getattr(f, 'service_type', None) + + +def pretty_choice_list(l): + return ', '.join("'%s'" % i for i in l) + + +def exit(msg=''): + if msg: + print (msg, file=sys.stderr) + sys.exit(1) |