summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2015-01-08 20:16:50 +0000
committerGerrit Code Review <review@openstack.org>2015-01-08 20:16:50 +0000
commitaeba1a12170ae51ac52e7f8a5225d5c8dbabd170 (patch)
tree106cbec101358ab781ddc0ebad8c7fe2b33ab2b8
parent368c39b580c98e3a95705277dbf32cd4d2856e8f (diff)
parente0def67dd5be966b0aac3ad5db7448d229bcf09e (diff)
downloadpython-ceilometerclient-aeba1a12170ae51ac52e7f8a5225d5c8dbabd170.tar.gz
Merge "sync to latest oslo-incubator code"
-rw-r--r--ceilometerclient/openstack/common/_i18n.py2
-rw-r--r--ceilometerclient/openstack/common/apiclient/auth.py13
-rw-r--r--ceilometerclient/openstack/common/apiclient/base.py16
-rw-r--r--ceilometerclient/openstack/common/apiclient/client.py27
-rw-r--r--ceilometerclient/openstack/common/apiclient/exceptions.py39
-rw-r--r--ceilometerclient/openstack/common/apiclient/fake_client.py15
-rw-r--r--ceilometerclient/openstack/common/apiclient/utils.py100
-rw-r--r--ceilometerclient/openstack/common/importutils.py73
8 files changed, 195 insertions, 90 deletions
diff --git a/ceilometerclient/openstack/common/_i18n.py b/ceilometerclient/openstack/common/_i18n.py
index 2d613bf..4b0745f 100644
--- a/ceilometerclient/openstack/common/_i18n.py
+++ b/ceilometerclient/openstack/common/_i18n.py
@@ -40,6 +40,6 @@ try:
_LC = _translators.log_critical
except ImportError:
# NOTE(dims): Support for cases where a project wants to use
- # code from ceilometerclient-incubator, but is not ready to be internationalized
+ # code from oslo-incubator, but is not ready to be internationalized
# (like tempest)
_ = _LI = _LW = _LE = _LC = lambda x: x
diff --git a/ceilometerclient/openstack/common/apiclient/auth.py b/ceilometerclient/openstack/common/apiclient/auth.py
index 2d9babe..3cf0e20 100644
--- a/ceilometerclient/openstack/common/apiclient/auth.py
+++ b/ceilometerclient/openstack/common/apiclient/auth.py
@@ -17,6 +17,19 @@
# E0202: An attribute inherited from %s hide this method
# pylint: disable=E0202
+########################################################################
+#
+# THIS MODULE IS DEPRECATED
+#
+# Please refer to
+# https://etherpad.openstack.org/p/kilo-ceilometerclient-library-proposals for
+# the discussion leading to this deprecation.
+#
+# We recommend checking out the python-openstacksdk project
+# (https://launchpad.net/python-openstacksdk) instead.
+#
+########################################################################
+
import abc
import argparse
import os
diff --git a/ceilometerclient/openstack/common/apiclient/base.py b/ceilometerclient/openstack/common/apiclient/base.py
index a090f81..4462e43 100644
--- a/ceilometerclient/openstack/common/apiclient/base.py
+++ b/ceilometerclient/openstack/common/apiclient/base.py
@@ -20,6 +20,20 @@
Base utilities to build API operation managers and objects on top of.
"""
+########################################################################
+#
+# THIS MODULE IS DEPRECATED
+#
+# Please refer to
+# https://etherpad.openstack.org/p/kilo-ceilometerclient-library-proposals for
+# the discussion leading to this deprecation.
+#
+# We recommend checking out the python-openstacksdk project
+# (https://launchpad.net/python-openstacksdk) instead.
+#
+########################################################################
+
+
# E1102: %s is not callable
# pylint: disable=E1102
@@ -495,6 +509,8 @@ class Resource(object):
new = self.manager.get(self.id)
if new:
self._add_details(new._info)
+ self._add_details(
+ {'x_request_id': self.manager.client.last_request_id})
def __eq__(self, other):
if not isinstance(other, Resource):
diff --git a/ceilometerclient/openstack/common/apiclient/client.py b/ceilometerclient/openstack/common/apiclient/client.py
index e17afc4..c5d6528 100644
--- a/ceilometerclient/openstack/common/apiclient/client.py
+++ b/ceilometerclient/openstack/common/apiclient/client.py
@@ -25,6 +25,7 @@ OpenStack Client interface. Handles the REST calls and responses.
# E0202: An attribute inherited from %s hide this method
# pylint: disable=E0202
+import hashlib
import logging
import time
@@ -33,14 +34,15 @@ try:
except ImportError:
import json
+from oslo.utils import encodeutils
from oslo.utils import importutils
import requests
from ceilometerclient.openstack.common._i18n import _
from ceilometerclient.openstack.common.apiclient import exceptions
-
_logger = logging.getLogger(__name__)
+SENSITIVE_HEADERS = ('X-Auth-Token', 'X-Subject-Token',)
class HTTPClient(object):
@@ -98,19 +100,32 @@ class HTTPClient(object):
self.http = http or requests.Session()
self.cached_token = None
+ self.last_request_id = None
+
+ def _safe_header(self, name, value):
+ if name in SENSITIVE_HEADERS:
+ # because in python3 byte string handling is ... ug
+ v = value.encode('utf-8')
+ h = hashlib.sha1(v)
+ d = h.hexdigest()
+ return encodeutils.safe_decode(name), "{SHA1}%s" % d
+ else:
+ return (encodeutils.safe_decode(name),
+ encodeutils.safe_decode(value))
def _http_log_req(self, method, url, kwargs):
if not self.debug:
return
string_parts = [
- "curl -i",
+ "curl -g -i",
"-X '%s'" % method,
"'%s'" % url,
]
for element in kwargs['headers']:
- header = "-H '%s: %s'" % (element, kwargs['headers'][element])
+ header = ("-H '%s: %s'" %
+ self._safe_header(element, kwargs['headers'][element]))
string_parts.append(header)
_logger.debug("REQ: %s" % " ".join(string_parts))
@@ -177,6 +192,8 @@ class HTTPClient(object):
start_time, time.time()))
self._http_log_resp(resp)
+ self.last_request_id = resp.headers.get('x-openstack-request-id')
+
if resp.status_code >= 400:
_logger.debug(
"Request returned failure status: %s",
@@ -327,6 +344,10 @@ class BaseClient(object):
return self.http_client.client_request(
self, method, url, **kwargs)
+ @property
+ def last_request_id(self):
+ return self.http_client.last_request_id
+
def head(self, url, **kwargs):
return self.client_request("HEAD", url, **kwargs)
diff --git a/ceilometerclient/openstack/common/apiclient/exceptions.py b/ceilometerclient/openstack/common/apiclient/exceptions.py
index 7b82ae5..15a830a 100644
--- a/ceilometerclient/openstack/common/apiclient/exceptions.py
+++ b/ceilometerclient/openstack/common/apiclient/exceptions.py
@@ -20,6 +20,19 @@
Exception definitions.
"""
+########################################################################
+#
+# THIS MODULE IS DEPRECATED
+#
+# Please refer to
+# https://etherpad.openstack.org/p/kilo-ceilometerclient-library-proposals for
+# the discussion leading to this deprecation.
+#
+# We recommend checking out the python-openstacksdk project
+# (https://launchpad.net/python-openstacksdk) instead.
+#
+########################################################################
+
import inspect
import sys
@@ -34,14 +47,6 @@ class ClientException(Exception):
pass
-class MissingArgs(ClientException):
- """Supplied arguments are not sufficient for calling a function."""
- def __init__(self, missing):
- self.missing = missing
- msg = _("Missing arguments: %s") % ", ".join(missing)
- super(MissingArgs, self).__init__(msg)
-
-
class ValidationError(ClientException):
"""Error in validation on API client side."""
pass
@@ -62,11 +67,16 @@ class AuthorizationFailure(ClientException):
pass
-class ConnectionRefused(ClientException):
+class ConnectionError(ClientException):
"""Cannot connect to API service."""
pass
+class ConnectionRefused(ConnectionError):
+ """Connection refused while trying to connect to API service."""
+ pass
+
+
class AuthPluginOptionsMissing(AuthorizationFailure):
"""Auth plugin misses some options."""
def __init__(self, opt_names):
@@ -447,10 +457,13 @@ def from_response(response, method, url):
except ValueError:
pass
else:
- if isinstance(body, dict) and isinstance(body.get("error"), dict):
- error = body["error"]
- kwargs["message"] = error.get("message")
- kwargs["details"] = error.get("details")
+ if isinstance(body, dict):
+ error = body.get(list(body)[0])
+ if isinstance(error, dict):
+ kwargs["message"] = (error.get("message") or
+ error.get("faultstring"))
+ kwargs["details"] = (error.get("details") or
+ six.text_type(body))
elif content_type.startswith("text/"):
kwargs["details"] = response.text
diff --git a/ceilometerclient/openstack/common/apiclient/fake_client.py b/ceilometerclient/openstack/common/apiclient/fake_client.py
index 24807ad..289b4ba 100644
--- a/ceilometerclient/openstack/common/apiclient/fake_client.py
+++ b/ceilometerclient/openstack/common/apiclient/fake_client.py
@@ -21,6 +21,19 @@ wrong the tests might raise AssertionError. I've indicated in comments the
places where actual behavior differs from the spec.
"""
+########################################################################
+#
+# THIS MODULE IS DEPRECATED
+#
+# Please refer to
+# https://etherpad.openstack.org/p/kilo-ceilometerclient-library-proposals for
+# the discussion leading to this deprecation.
+#
+# We recommend checking out the python-openstacksdk project
+# (https://launchpad.net/python-openstacksdk) instead.
+#
+########################################################################
+
# W0102: Dangerous default value %s as argument
# pylint: disable=W0102
@@ -168,6 +181,8 @@ class FakeHTTPClient(client.HTTPClient):
else:
status, body = resp
headers = {}
+ self.last_request_id = headers.get('x-openstack-request-id',
+ 'req-test')
return TestResponse({
"status_code": status,
"text": body,
diff --git a/ceilometerclient/openstack/common/apiclient/utils.py b/ceilometerclient/openstack/common/apiclient/utils.py
new file mode 100644
index 0000000..6d94759
--- /dev/null
+++ b/ceilometerclient/openstack/common/apiclient/utils.py
@@ -0,0 +1,100 @@
+#
+# 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.
+
+########################################################################
+#
+# THIS MODULE IS DEPRECATED
+#
+# Please refer to
+# https://etherpad.openstack.org/p/kilo-ceilometerclient-library-proposals for
+# the discussion leading to this deprecation.
+#
+# We recommend checking out the python-openstacksdk project
+# (https://launchpad.net/python-openstacksdk) instead.
+#
+########################################################################
+
+from oslo.utils import encodeutils
+import six
+
+from ceilometerclient.openstack.common._i18n import _
+from ceilometerclient.openstack.common.apiclient import exceptions
+from ceilometerclient.openstack.common import uuidutils
+
+
+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 = encodeutils.safe_encode(name_or_id)
+ else:
+ tmp_id = encodeutils.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)
diff --git a/ceilometerclient/openstack/common/importutils.py b/ceilometerclient/openstack/common/importutils.py
deleted file mode 100644
index a7972e0..0000000
--- a/ceilometerclient/openstack/common/importutils.py
+++ /dev/null
@@ -1,73 +0,0 @@
-# Copyright 2011 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.
-
-"""
-Import related utilities and helper functions.
-"""
-
-import sys
-import traceback
-
-
-def import_class(import_str):
- """Returns a class from a string including module and class."""
- mod_str, _sep, class_str = import_str.rpartition('.')
- __import__(mod_str)
- try:
- return getattr(sys.modules[mod_str], class_str)
- except AttributeError:
- raise ImportError('Class %s cannot be found (%s)' %
- (class_str,
- traceback.format_exception(*sys.exc_info())))
-
-
-def import_object(import_str, *args, **kwargs):
- """Import a class and return an instance of it."""
- return import_class(import_str)(*args, **kwargs)
-
-
-def import_object_ns(name_space, import_str, *args, **kwargs):
- """Tries to import object from default namespace.
-
- Imports a class and return an instance of it, first by trying
- to find the class in a default namespace, then failing back to
- a full path if not found in the default namespace.
- """
- import_value = "%s.%s" % (name_space, import_str)
- try:
- return import_class(import_value)(*args, **kwargs)
- except ImportError:
- return import_class(import_str)(*args, **kwargs)
-
-
-def import_module(import_str):
- """Import a module."""
- __import__(import_str)
- return sys.modules[import_str]
-
-
-def import_versioned_module(version, submodule=None):
- module = 'ceilometerclient.v%s' % version
- if submodule:
- module = '.'.join((module, submodule))
- return import_module(module)
-
-
-def try_import(import_str, default=None):
- """Try to import a module and if it fails return default."""
- try:
- return import_module(import_str)
- except ImportError:
- return default