diff options
author | Jenkins <jenkins@review.openstack.org> | 2014-02-28 15:19:22 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2014-02-28 15:19:22 +0000 |
commit | 06582e0c1d411d0beb51b24eee9ae02a3c2cecf5 (patch) | |
tree | b7d8cfe105c733247aa834bb0714335fbdc676b9 | |
parent | eef94a62484a21f748eec2c655f3d062c3af7465 (diff) | |
parent | 64043442bbafa48f9042b669d30292b1db00db4f (diff) | |
download | python-novaclient-06582e0c1d411d0beb51b24eee9ae02a3c2cecf5.tar.gz |
Merge "oslo sync apiclient and cliutils"
-rw-r--r-- | novaclient/openstack/common/apiclient/__init__.py | 14 | ||||
-rw-r--r-- | novaclient/openstack/common/apiclient/auth.py | 6 | ||||
-rw-r--r-- | novaclient/openstack/common/apiclient/base.py | 15 | ||||
-rw-r--r-- | novaclient/openstack/common/apiclient/exceptions.py | 24 | ||||
-rw-r--r-- | novaclient/openstack/common/apiclient/fake_client.py | 7 | ||||
-rw-r--r-- | novaclient/openstack/common/cliutils.py | 102 |
6 files changed, 137 insertions, 31 deletions
diff --git a/novaclient/openstack/common/apiclient/__init__.py b/novaclient/openstack/common/apiclient/__init__.py index f3d0cdef..e69de29b 100644 --- a/novaclient/openstack/common/apiclient/__init__.py +++ b/novaclient/openstack/common/apiclient/__init__.py @@ -1,14 +0,0 @@ -# Copyright 2013 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. diff --git a/novaclient/openstack/common/apiclient/auth.py b/novaclient/openstack/common/apiclient/auth.py index 81af9aa0..ee1348af 100644 --- a/novaclient/openstack/common/apiclient/auth.py +++ b/novaclient/openstack/common/apiclient/auth.py @@ -19,7 +19,6 @@ import abc import argparse -import logging import os import six @@ -28,9 +27,6 @@ from stevedore import extension from novaclient.openstack.common.apiclient import exceptions -logger = logging.getLogger(__name__) - - _discovered_plugins = {} @@ -80,7 +76,7 @@ def load_plugin_from_args(args): alphabetical order. :type args: argparse.Namespace - :raises: AuthorizationFailure + :raises: AuthPluginOptionsMissing """ auth_system = args.os_auth_system if auth_system: diff --git a/novaclient/openstack/common/apiclient/base.py b/novaclient/openstack/common/apiclient/base.py index dcb4a000..647f4a72 100644 --- a/novaclient/openstack/common/apiclient/base.py +++ b/novaclient/openstack/common/apiclient/base.py @@ -24,11 +24,12 @@ Base utilities to build API operation managers and objects on top of. # pylint: disable=E1102 import abc +import copy import six +from six.moves.urllib import parse from novaclient.openstack.common.apiclient import exceptions -from novaclient.openstack.common.py3kcompat import urlutils from novaclient.openstack.common import strutils @@ -327,7 +328,7 @@ class CrudManager(BaseManager): return self._list( '%(base_url)s%(query)s' % { 'base_url': self.build_url(base_url=base_url, **kwargs), - 'query': '?%s' % urlutils.urlencode(kwargs) if kwargs else '', + 'query': '?%s' % parse.urlencode(kwargs) if kwargs else '', }, self.collection_key) @@ -366,7 +367,7 @@ class CrudManager(BaseManager): rl = self._list( '%(base_url)s%(query)s' % { 'base_url': self.build_url(base_url=base_url, **kwargs), - 'query': '?%s' % urlutils.urlencode(kwargs) if kwargs else '', + 'query': '?%s' % parse.urlencode(kwargs) if kwargs else '', }, self.collection_key) num = len(rl) @@ -465,6 +466,11 @@ class Resource(object): return self.__dict__[k] def get(self): + """Support for lazy loading details. + + Some clients, such as novaclient have the option to lazy load the + details, details which can be loaded with this function. + """ # set_loaded() first ... so if we have to bail, we know we tried. self.set_loaded(True) if not hasattr(self.manager, 'get'): @@ -489,3 +495,6 @@ class Resource(object): def set_loaded(self, val): self._loaded = val + + def to_dict(self): + return copy.deepcopy(self._info) diff --git a/novaclient/openstack/common/apiclient/exceptions.py b/novaclient/openstack/common/apiclient/exceptions.py index 45a70e0a..ada1344f 100644 --- a/novaclient/openstack/common/apiclient/exceptions.py +++ b/novaclient/openstack/common/apiclient/exceptions.py @@ -60,6 +60,11 @@ class AuthorizationFailure(ClientException): pass +class ConnectionRefused(ClientException): + """Cannot connect to API service.""" + pass + + class AuthPluginOptionsMissing(AuthorizationFailure): """Auth plugin misses some options.""" def __init__(self, opt_names): @@ -122,6 +127,11 @@ class HttpError(ClientException): super(HttpError, self).__init__(formatted_string) +class HTTPRedirection(HttpError): + """HTTP Redirection.""" + message = "HTTP Redirection" + + class HTTPClientError(HttpError): """Client-side HTTP error. @@ -139,6 +149,16 @@ class HttpServerError(HttpError): message = "HTTP Server Error" +class MultipleChoices(HTTPRedirection): + """HTTP 300 - Multiple Choices. + + Indicates multiple options for the resource that the client may follow. + """ + + http_status = 300 + message = "Multiple Choices" + + class BadRequest(HTTPClientError): """HTTP 400 - Bad Request. @@ -420,8 +440,8 @@ def from_response(response, method, url): except ValueError: pass else: - if hasattr(body, "keys"): - error = body[body.keys()[0]] + if isinstance(body, dict): + error = list(body.values())[0] kwargs["message"] = error.get("message") kwargs["details"] = error.get("details") elif content_type.startswith("text/"): diff --git a/novaclient/openstack/common/apiclient/fake_client.py b/novaclient/openstack/common/apiclient/fake_client.py index 05f550b9..cdb3cc1c 100644 --- a/novaclient/openstack/common/apiclient/fake_client.py +++ b/novaclient/openstack/common/apiclient/fake_client.py @@ -28,10 +28,9 @@ import json import requests import six +from six.moves.urllib import parse from novaclient.openstack.common.apiclient import client -from novaclient.openstack.common.py3kcompat import urlutils -from novaclient.openstack.common import strutils def assert_has_keys(dct, required=[], optional=[]): @@ -64,7 +63,7 @@ class TestResponse(requests.Response): self._content = text default_headers = {} if six.PY3 and isinstance(self._content, six.string_types): - self._content = strutils.safe_encode(self._content) + self._content = self._content.encode('utf-8', 'strict') self.headers = data.get('headers') or default_headers else: self.status_code = data @@ -148,7 +147,7 @@ class FakeHTTPClient(client.HTTPClient): "text": fixture[1]}) # Call the method - args = urlutils.parse_qsl(urlutils.urlparse(url)[4]) + args = parse.parse_qsl(parse.urlparse(url)[4]) kwargs.update(args) munged_url = url.rsplit('?', 1)[0] munged_url = munged_url.strip('/').replace('/', '_').replace('.', '_') diff --git a/novaclient/openstack/common/cliutils.py b/novaclient/openstack/common/cliutils.py index 710f8f8f..6a96da57 100644 --- a/novaclient/openstack/common/cliutils.py +++ b/novaclient/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 novaclient.openstack.common.apiclient import exceptions +from novaclient.openstack.common.gettextutils import _ from novaclient.openstack.common import strutils +from novaclient.openstack.common import uuidutils def validate_args(fn, *args, **kwargs): @@ -176,9 +180,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 +203,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 +215,95 @@ 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: + + 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: + tmp_id = strutils.safe_encode(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: + @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) |