summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Gordon <joe.gordon0@gmail.com>2014-02-26 21:00:23 -0800
committerJoe Gordon <joe.gordon0@gmail.com>2014-02-27 13:30:34 -0800
commit64043442bbafa48f9042b669d30292b1db00db4f (patch)
treee1ffc72f2f15ad181958c5492ee2a123774874ed
parente0272b0578d2a4f5bd75e68baee1b56f49931266 (diff)
downloadpython-novaclient-64043442bbafa48f9042b669d30292b1db00db4f.tar.gz
oslo sync apiclient and cliutils
Generated with: ./update.sh --base novaclient --config-file ../python-novaclient/openstack-common.conf --dest-dir ../python-novaclient/ Synced patches: apiclient: 04a1abe Revert "Removed set_loaded() method from Resource class" 5e76477 Merge "Handle 300 status code in common HTTPClient" 492fe2c Merge "py3kcompat: remove" 466ad64 Merge "Fix usage of dict.keys in apiclient.exceptions" 8630a44 Merge "Removed set_loaded() method from Resource class" 41fbfea Merge "Add to_dict() method to apiclient Resource" 6650435 Fix usage of dict.keys in apiclient.exceptions 35dc1d7 py3kcompat: remove 9f1e7eb Correct docstring in load_plugin_from_args 0c4d2c7 Removed set_loaded() method from Resource class 3b248dd Add to_dict() method to apiclient Resource 71c22e9 Handle 300 status code in common HTTPClient cliutils: 9a7f2f8 Merge "Deleted duplicated method in cliutils." 8f2effd Use `six.text_type` instead of `str` in cliutils 885828a Deleted duplicated method in cliutils. 71a2d90 Add common methods to cliutils Change-Id: I0c8849d8d5dd71f34aa5dbcd2c0875c164706d70
-rw-r--r--novaclient/openstack/common/apiclient/__init__.py14
-rw-r--r--novaclient/openstack/common/apiclient/auth.py6
-rw-r--r--novaclient/openstack/common/apiclient/base.py15
-rw-r--r--novaclient/openstack/common/apiclient/exceptions.py24
-rw-r--r--novaclient/openstack/common/apiclient/fake_client.py7
-rw-r--r--novaclient/openstack/common/cliutils.py102
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)