summaryrefslogtreecommitdiff
path: root/keystoneclient/base.py
diff options
context:
space:
mode:
authorDavid Stanek <dstanek@dstanek.com>2016-06-15 12:51:04 +0000
committerdineshbhor <dinesh.bhor@nttdata.com>2018-03-26 01:51:30 -0700
commitb2e9caee38ca66147552a8f677468becf812e16e (patch)
treeee6d38ec886efb8da04664ab822d501cf57ff559 /keystoneclient/base.py
parent70f33b5e226e9b945cea66bfa774934537f04841 (diff)
downloadpython-keystoneclient-b2e9caee38ca66147552a8f677468becf812e16e.tar.gz
Add Response class to return request-id to caller
This change is required to return 'request_id' from client to log request_id mappings of cross-project requests. Instantiating class 'keystoneclient.v3.client.Client' using 'include_metadata=True' will cause manager response to return a new 'Response' class instead of just the data. This 'Response' class is going to have additional metadata properties available like 'request_ids' and the original data will be available as property 'data' to it. This change is backward compatible since user has to set a new parameter 'include_metadata=True' to client in order to get the request_id returned. Co-author: Dinesh Bhor <dinesh.bhor@nttdata.com> Partially Implements: blueprint return-request-id-to-caller Change-Id: Ibefaa484158ff08bfcacc1e2802d87fc26fd76a5
Diffstat (limited to 'keystoneclient/base.py')
-rw-r--r--keystoneclient/base.py122
1 files changed, 92 insertions, 30 deletions
diff --git a/keystoneclient/base.py b/keystoneclient/base.py
index c466b1b..5824e6d 100644
--- a/keystoneclient/base.py
+++ b/keystoneclient/base.py
@@ -32,6 +32,23 @@ from keystoneclient import exceptions as ksc_exceptions
from keystoneclient.i18n import _
+class Response(object):
+
+ def __init__(self, http_response, data):
+ self.request_ids = []
+ if isinstance(http_response, list):
+ # http_response is a list of <requests.Response> in case
+ # of pagination
+ for resp_obj in http_response:
+ # Extract 'x-openstack-request-id' from headers
+ self.request_ids.append(resp_obj.headers.get(
+ 'x-openstack-request-id'))
+ else:
+ self.request_ids.append(http_response.headers.get(
+ 'x-openstack-request-id'))
+ self.data = data
+
+
def getid(obj):
"""Return id if argument is a Resource.
@@ -107,6 +124,11 @@ class Manager(object):
'may be removed in the 2.0.0 release', DeprecationWarning)
return self.client
+ def _prepare_return_value(self, http_response, data):
+ if self.client.include_metadata:
+ return Response(http_response, data)
+ return data
+
def _list(self, url, response_key, obj_class=None, body=None, **kwargs):
"""List the collection.
@@ -137,7 +159,8 @@ class Manager(object):
# are already returned in a list (so simply utilize that list)
pass
- return [obj_class(self, res, loaded=True) for res in data if res]
+ return self._prepare_return_value(
+ resp, [obj_class(self, res, loaded=True) for res in data if res])
def _get(self, url, response_key, **kwargs):
"""Get an object from collection.
@@ -148,7 +171,8 @@ class Manager(object):
:param kwargs: Additional arguments will be passed to the request.
"""
resp, body = self.client.get(url, **kwargs)
- return self.resource_class(self, body[response_key], loaded=True)
+ return self._prepare_return_value(
+ resp, self.resource_class(self, body[response_key], loaded=True))
def _head(self, url, **kwargs):
"""Retrieve request headers for an object.
@@ -157,7 +181,7 @@ class Manager(object):
:param kwargs: Additional arguments will be passed to the request.
"""
resp, body = self.client.head(url, **kwargs)
- return resp.status_code == 204
+ return self._prepare_return_value(resp, resp.status_code == 204)
def _post(self, url, body, response_key, return_raw=False, **kwargs):
"""Create an object.
@@ -174,7 +198,8 @@ class Manager(object):
resp, body = self.client.post(url, body=body, **kwargs)
if return_raw:
return body[response_key]
- return self.resource_class(self, body[response_key])
+ return self._prepare_return_value(
+ resp, self.resource_class(self, body[response_key]))
def _put(self, url, body=None, response_key=None, **kwargs):
"""Update an object with PUT method.
@@ -190,9 +215,11 @@ class Manager(object):
# PUT requests may not return a body
if body is not None:
if response_key is not None:
- return self.resource_class(self, body[response_key])
+ return self._prepare_return_value(
+ resp, self.resource_class(self, body[response_key]))
else:
- return self.resource_class(self, body)
+ return self._prepare_return_value(
+ resp, self.resource_class(self, body))
def _patch(self, url, body=None, response_key=None, **kwargs):
"""Update an object with PATCH method.
@@ -206,9 +233,11 @@ class Manager(object):
"""
resp, body = self.client.patch(url, body=body, **kwargs)
if response_key is not None:
- return self.resource_class(self, body[response_key])
+ return self._prepare_return_value(
+ resp, self.resource_class(self, body[response_key]))
else:
- return self.resource_class(self, body)
+ return self._prepare_return_value(
+ resp, self.resource_class(self, body))
def _delete(self, url, **kwargs):
"""Delete an object.
@@ -216,7 +245,8 @@ class Manager(object):
:param url: a partial URL, e.g., '/servers/my-server'
:param kwargs: Additional arguments will be passed to the request.
"""
- return self.client.delete(url, **kwargs)
+ resp, body = self.client.delete(url, **kwargs)
+ return resp, self._prepare_return_value(resp, body)
def _update(self, url, body=None, response_key=None, method="PUT",
**kwargs):
@@ -231,7 +261,10 @@ class Manager(object):
% method)
# PUT requests may not return a body
if body:
- return self.resource_class(self, body[response_key])
+ return self._prepare_return_value(
+ resp, self.resource_class(self, body[response_key]))
+ else:
+ return self._prepare_return_value(resp, body)
@six.add_metaclass(abc.ABCMeta)
@@ -249,16 +282,20 @@ class ManagerWithFind(Manager):
the Python side.
"""
rl = self.findall(**kwargs)
- num = len(rl)
- if num == 0:
+ if self.client.include_metadata:
+ base_response = rl
+ rl = rl.data
+ base_response.data = rl[0]
+
+ if len(rl) == 0:
msg = _("No %(name)s matching %(kwargs)s.") % {
'name': self.resource_class.__name__, 'kwargs': kwargs}
raise ksa_exceptions.NotFound(404, msg)
- elif num > 1:
+ elif len(rl) > 1:
raise ksc_exceptions.NoUniqueMatch
else:
- return rl[0]
+ return base_response if self.client.include_metadata else rl[0]
def findall(self, **kwargs):
"""Find all items with attributes matching ``**kwargs``.
@@ -269,15 +306,23 @@ class ManagerWithFind(Manager):
found = []
searches = kwargs.items()
- for obj in self.list():
- try:
- if all(getattr(obj, attr) == value
- for (attr, value) in searches):
- found.append(obj)
- except AttributeError:
- continue
+ def _extract_data(objs, response_data):
+ for obj in objs:
+ try:
+ if all(getattr(obj, attr) == value
+ for (attr, value) in searches):
+ response_data.append(obj)
+ except AttributeError:
+ continue
+ return response_data
+
+ objs = self.list()
+ if self.client.include_metadata:
+ # 'objs' is the object of 'Response' class.
+ objs.data = _extract_data(objs.data, found)
+ return objs
- return found
+ return _extract_data(objs, found)
class CrudManager(Manager):
@@ -376,6 +421,16 @@ class CrudManager(Manager):
@filter_kwargs
def list(self, fallback_to_auth=False, **kwargs):
+
+ def return_resp(resp, include_metadata=False):
+ base_response = None
+ list_data = resp
+ if include_metadata:
+ base_response = resp
+ list_data = resp.data
+ base_response.data = list_data
+ return base_response if include_metadata else list_data
+
if 'id' in kwargs.keys():
# Ensure that users are not trying to call things like
# ``domains.list(id='default')`` when they should have used
@@ -392,15 +447,16 @@ class CrudManager(Manager):
try:
query = self._build_query(kwargs)
url_query = '%(url)s%(query)s' % {'url': url, 'query': query}
- return self._list(
- url_query,
- self.collection_key)
+ list_resp = self._list(url_query, self.collection_key)
+ return return_resp(list_resp,
+ include_metadata=self.client.include_metadata)
except ksa_exceptions.EmptyCatalog:
if fallback_to_auth:
- return self._list(
- url_query,
- self.collection_key,
- endpoint_filter={'interface': plugin.AUTH_INTERFACE})
+ list_resp = self._list(url_query, self.collection_key,
+ endpoint_filter={
+ 'interface': plugin.AUTH_INTERFACE})
+ return return_resp(
+ list_resp, include_metadata=self.client.include_metadata)
else:
raise
@@ -439,6 +495,11 @@ class CrudManager(Manager):
url_query,
self.collection_key)
+ if self.client.include_metadata:
+ base_response = elements
+ elements = elements.data
+ base_response.data = elements[0]
+
if not elements:
msg = _("No %(name)s matching %(kwargs)s.") % {
'name': self.resource_class.__name__, 'kwargs': kwargs}
@@ -446,7 +507,8 @@ class CrudManager(Manager):
elif len(elements) > 1:
raise ksc_exceptions.NoUniqueMatch
else:
- return elements[0]
+ return (base_response if self.client.include_metadata
+ else elements[0])
class Resource(object):