add optional 'response_dict' parameters to many calls into which they'll
return a dictionary of the response status, reason and headers Change-Id: I35f8824537f0484362dd6646c91789fac02fa075
This commit is contained in:
parent
5d84ff8d9b
commit
3f66a8ae6b
@ -332,6 +332,25 @@ def get_auth(auth_url, user, key, **kwargs):
|
||||
% auth_version)
|
||||
|
||||
|
||||
def store_response(resp, response_dict):
|
||||
"""
|
||||
store information about an operation into a dict
|
||||
|
||||
:param resp: an http response object containing the response
|
||||
headers
|
||||
:param response_dict: a dict into which are placed the
|
||||
status, reason and a dict of lower-cased headers
|
||||
"""
|
||||
if response_dict is not None:
|
||||
resp_headers = {}
|
||||
for header, value in resp.getheaders():
|
||||
resp_headers[header.lower()] = value
|
||||
|
||||
response_dict['status'] = resp.status
|
||||
response_dict['reason'] = resp.reason
|
||||
response_dict['headers'] = resp_headers
|
||||
|
||||
|
||||
def get_account(url, token, marker=None, limit=None, prefix=None,
|
||||
end_marker=None, http_conn=None, full_listing=False):
|
||||
"""
|
||||
@ -432,7 +451,7 @@ def head_account(url, token, http_conn=None):
|
||||
return resp_headers
|
||||
|
||||
|
||||
def post_account(url, token, headers, http_conn=None):
|
||||
def post_account(url, token, headers, http_conn=None, response_dict=None):
|
||||
"""
|
||||
Update an account's metadata.
|
||||
|
||||
@ -441,6 +460,8 @@ def post_account(url, token, headers, http_conn=None):
|
||||
:param headers: additional headers to include in the request
|
||||
:param http_conn: HTTP connection object (If None, it will create the
|
||||
conn object)
|
||||
:param response_dict: an optional dictionary into which to place
|
||||
the response - status, reason and headers
|
||||
:raises ClientException: HTTP POST request failed
|
||||
"""
|
||||
if http_conn:
|
||||
@ -453,6 +474,9 @@ def post_account(url, token, headers, http_conn=None):
|
||||
resp = conn.getresponse()
|
||||
body = resp.read()
|
||||
http_log((url, method,), {'headers': headers}, resp, body)
|
||||
|
||||
store_response(resp, response_dict)
|
||||
|
||||
if resp.status < 200 or resp.status >= 300:
|
||||
raise ClientException('Account POST failed',
|
||||
http_scheme=parsed.scheme,
|
||||
@ -582,7 +606,8 @@ def head_container(url, token, container, http_conn=None, headers=None):
|
||||
return resp_headers
|
||||
|
||||
|
||||
def put_container(url, token, container, headers=None, http_conn=None):
|
||||
def put_container(url, token, container, headers=None, http_conn=None,
|
||||
response_dict=None):
|
||||
"""
|
||||
Create a container
|
||||
|
||||
@ -592,6 +617,8 @@ def put_container(url, token, container, headers=None, http_conn=None):
|
||||
:param headers: additional headers to include in the request
|
||||
:param http_conn: HTTP connection object (If None, it will create the
|
||||
conn object)
|
||||
:param response_dict: an optional dictionary into which to place
|
||||
the response - status, reason and headers
|
||||
:raises ClientException: HTTP PUT request failed
|
||||
"""
|
||||
if http_conn:
|
||||
@ -608,6 +635,9 @@ def put_container(url, token, container, headers=None, http_conn=None):
|
||||
conn.request(method, path, '', headers)
|
||||
resp = conn.getresponse()
|
||||
body = resp.read()
|
||||
|
||||
store_response(resp, response_dict)
|
||||
|
||||
http_log(('%s%s' % (url.replace(parsed.path, ''), path), method,),
|
||||
{'headers': headers}, resp, body)
|
||||
if resp.status < 200 or resp.status >= 300:
|
||||
@ -618,7 +648,8 @@ def put_container(url, token, container, headers=None, http_conn=None):
|
||||
http_response_content=body)
|
||||
|
||||
|
||||
def post_container(url, token, container, headers, http_conn=None):
|
||||
def post_container(url, token, container, headers, http_conn=None,
|
||||
response_dict=None):
|
||||
"""
|
||||
Update a container's metadata.
|
||||
|
||||
@ -628,6 +659,8 @@ def post_container(url, token, container, headers, http_conn=None):
|
||||
:param headers: additional headers to include in the request
|
||||
:param http_conn: HTTP connection object (If None, it will create the
|
||||
conn object)
|
||||
:param response_dict: an optional dictionary into which to place
|
||||
the response - status, reason and headers
|
||||
:raises ClientException: HTTP POST request failed
|
||||
"""
|
||||
if http_conn:
|
||||
@ -644,6 +677,9 @@ def post_container(url, token, container, headers, http_conn=None):
|
||||
body = resp.read()
|
||||
http_log(('%s%s' % (url.replace(parsed.path, ''), path), method,),
|
||||
{'headers': headers}, resp, body)
|
||||
|
||||
store_response(resp, response_dict)
|
||||
|
||||
if resp.status < 200 or resp.status >= 300:
|
||||
raise ClientException('Container POST failed',
|
||||
http_scheme=parsed.scheme, http_host=conn.host,
|
||||
@ -652,7 +688,8 @@ def post_container(url, token, container, headers, http_conn=None):
|
||||
http_response_content=body)
|
||||
|
||||
|
||||
def delete_container(url, token, container, http_conn=None):
|
||||
def delete_container(url, token, container, http_conn=None,
|
||||
response_dict=None):
|
||||
"""
|
||||
Delete a container
|
||||
|
||||
@ -661,6 +698,8 @@ def delete_container(url, token, container, http_conn=None):
|
||||
:param container: container name to delete
|
||||
:param http_conn: HTTP connection object (If None, it will create the
|
||||
conn object)
|
||||
:param response_dict: an optional dictionary into which to place
|
||||
the response - status, reason and headers
|
||||
:raises ClientException: HTTP DELETE request failed
|
||||
"""
|
||||
if http_conn:
|
||||
@ -675,6 +714,9 @@ def delete_container(url, token, container, http_conn=None):
|
||||
body = resp.read()
|
||||
http_log(('%s%s' % (url.replace(parsed.path, ''), path), method,),
|
||||
{'headers': headers}, resp, body)
|
||||
|
||||
store_response(resp, response_dict)
|
||||
|
||||
if resp.status < 200 or resp.status >= 300:
|
||||
raise ClientException('Container DELETE failed',
|
||||
http_scheme=parsed.scheme, http_host=conn.host,
|
||||
@ -684,7 +726,8 @@ def delete_container(url, token, container, http_conn=None):
|
||||
|
||||
|
||||
def get_object(url, token, container, name, http_conn=None,
|
||||
resp_chunk_size=None, query_string=None):
|
||||
resp_chunk_size=None, query_string=None,
|
||||
response_dict=None):
|
||||
"""
|
||||
Get an object
|
||||
|
||||
@ -699,6 +742,8 @@ def get_object(url, token, container, name, http_conn=None,
|
||||
the object's contents before making another
|
||||
request.
|
||||
:param query_string: if set will be appended with '?' to generated path
|
||||
:param response_dict: an optional dictionary into which to place
|
||||
the response - status, reason and headers
|
||||
:returns: a tuple of (response headers, the object's contents) The response
|
||||
headers will be a dict and all header names will be lowercase.
|
||||
:raises ClientException: HTTP GET request failed
|
||||
@ -714,6 +759,12 @@ def get_object(url, token, container, name, http_conn=None,
|
||||
headers = {'X-Auth-Token': token}
|
||||
conn.request(method, path, '', headers)
|
||||
resp = conn.getresponse()
|
||||
|
||||
parsed_response = {}
|
||||
store_response(resp, parsed_response)
|
||||
if response_dict is not None:
|
||||
response_dict.update(parsed_response)
|
||||
|
||||
if resp.status < 200 or resp.status >= 300:
|
||||
body = resp.read()
|
||||
http_log(('%s%s' % (url.replace(parsed.path, ''), path), method,),
|
||||
@ -733,12 +784,10 @@ def get_object(url, token, container, name, http_conn=None,
|
||||
object_body = _object_body()
|
||||
else:
|
||||
object_body = resp.read()
|
||||
resp_headers = {}
|
||||
for header, value in resp.getheaders():
|
||||
resp_headers[header.lower()] = value
|
||||
http_log(('%s%s' % (url.replace(parsed.path, ''), path), method,),
|
||||
{'headers': headers}, resp, None)
|
||||
return resp_headers, object_body
|
||||
|
||||
return parsed_response['headers'], object_body
|
||||
|
||||
|
||||
def head_object(url, token, container, name, http_conn=None):
|
||||
@ -782,7 +831,7 @@ def head_object(url, token, container, name, http_conn=None):
|
||||
def put_object(url, token=None, container=None, name=None, contents=None,
|
||||
content_length=None, etag=None, chunk_size=None,
|
||||
content_type=None, headers=None, http_conn=None, proxy=None,
|
||||
query_string=None):
|
||||
query_string=None, response_dict=None):
|
||||
"""
|
||||
Put an object
|
||||
|
||||
@ -811,7 +860,9 @@ def put_object(url, token=None, container=None, name=None, contents=None,
|
||||
:param proxy: proxy to connect through, if any; None by default; str of the
|
||||
format 'http://127.0.0.1:8888' to set one
|
||||
:param query_string: if set will be appended with '?' to generated path
|
||||
:returns: etag from server response
|
||||
:param response_dict: an optional dictionary into which to place
|
||||
the response - status, reason and headers
|
||||
:returns: etag
|
||||
:raises ClientException: HTTP PUT request failed
|
||||
"""
|
||||
if http_conn:
|
||||
@ -878,16 +929,21 @@ def put_object(url, token=None, container=None, name=None, contents=None,
|
||||
headers = {'X-Auth-Token': token}
|
||||
http_log(('%s%s' % (url.replace(parsed.path, ''), path), 'PUT',),
|
||||
{'headers': headers}, resp, body)
|
||||
|
||||
store_response(resp, response_dict)
|
||||
|
||||
if resp.status < 200 or resp.status >= 300:
|
||||
raise ClientException('Object PUT failed', http_scheme=parsed.scheme,
|
||||
http_host=conn.host, http_port=conn.port,
|
||||
http_path=path, http_status=resp.status,
|
||||
http_reason=resp.reason,
|
||||
http_response_content=body)
|
||||
|
||||
return resp.getheader('etag', '').strip('"')
|
||||
|
||||
|
||||
def post_object(url, token, container, name, headers, http_conn=None):
|
||||
def post_object(url, token, container, name, headers, http_conn=None,
|
||||
response_dict=None):
|
||||
"""
|
||||
Update object metadata
|
||||
|
||||
@ -898,6 +954,8 @@ def post_object(url, token, container, name, headers, http_conn=None):
|
||||
:param headers: additional headers to include in the request
|
||||
:param http_conn: HTTP connection object (If None, it will create the
|
||||
conn object)
|
||||
:param response_dict: an optional dictionary into which to place
|
||||
the response - status, reason and headers
|
||||
:raises ClientException: HTTP POST request failed
|
||||
"""
|
||||
if http_conn:
|
||||
@ -911,6 +969,9 @@ def post_object(url, token, container, name, headers, http_conn=None):
|
||||
body = resp.read()
|
||||
http_log(('%s%s' % (url.replace(parsed.path, ''), path), 'POST',),
|
||||
{'headers': headers}, resp, body)
|
||||
|
||||
store_response(resp, response_dict)
|
||||
|
||||
if resp.status < 200 or resp.status >= 300:
|
||||
raise ClientException('Object POST failed', http_scheme=parsed.scheme,
|
||||
http_host=conn.host, http_port=conn.port,
|
||||
@ -920,7 +981,8 @@ def post_object(url, token, container, name, headers, http_conn=None):
|
||||
|
||||
|
||||
def delete_object(url, token=None, container=None, name=None, http_conn=None,
|
||||
headers=None, proxy=None, query_string=None):
|
||||
headers=None, proxy=None, query_string=None,
|
||||
response_dict=None):
|
||||
"""
|
||||
Delete object
|
||||
|
||||
@ -936,6 +998,8 @@ def delete_object(url, token=None, container=None, name=None, http_conn=None,
|
||||
:param proxy: proxy to connect through, if any; None by default; str of the
|
||||
format 'http://127.0.0.1:8888' to set one
|
||||
:param query_string: if set will be appended with '?' to generated path
|
||||
:param response_dict: an optional dictionary into which to place
|
||||
the response - status, reason and headers
|
||||
:raises ClientException: HTTP DELETE request failed
|
||||
"""
|
||||
if http_conn:
|
||||
@ -960,6 +1024,9 @@ def delete_object(url, token=None, container=None, name=None, http_conn=None,
|
||||
body = resp.read()
|
||||
http_log(('%s%s' % (url.replace(parsed.path, ''), path), 'DELETE',),
|
||||
{'headers': headers}, resp, body)
|
||||
|
||||
store_response(resp, response_dict)
|
||||
|
||||
if resp.status < 200 or resp.status >= 300:
|
||||
raise ClientException('Object DELETE failed',
|
||||
http_scheme=parsed.scheme, http_host=conn.host,
|
||||
@ -1032,10 +1099,20 @@ class Connection(object):
|
||||
return http_connection(self.url,
|
||||
ssl_compression=self.ssl_compression)
|
||||
|
||||
def _add_response_dict(self, target_dict, kwargs):
|
||||
if target_dict is not None:
|
||||
response_dict = kwargs['response_dict']
|
||||
if 'response_dicts' in target_dict:
|
||||
target_dict['response_dicts'].append(response_dict)
|
||||
else:
|
||||
target_dict['response_dicts'] = [response_dict]
|
||||
target_dict.update(response_dict)
|
||||
|
||||
def _retry(self, reset_func, func, *args, **kwargs):
|
||||
self.attempts = 0
|
||||
retried_auth = False
|
||||
backoff = self.starting_backoff
|
||||
caller_response_dict = kwargs.pop('response_dict', None)
|
||||
while self.attempts <= self.retries:
|
||||
self.attempts += 1
|
||||
try:
|
||||
@ -1045,13 +1122,18 @@ class Connection(object):
|
||||
if not self.http_conn:
|
||||
self.http_conn = self.http_connection()
|
||||
kwargs['http_conn'] = self.http_conn
|
||||
if caller_response_dict is not None:
|
||||
kwargs['response_dict'] = {}
|
||||
rv = func(self.url, self.token, *args, **kwargs)
|
||||
self._add_response_dict(caller_response_dict, kwargs)
|
||||
return rv
|
||||
except (socket.error, HTTPException):
|
||||
self._add_response_dict(caller_response_dict, kwargs)
|
||||
if self.attempts > self.retries:
|
||||
raise
|
||||
self.http_conn = None
|
||||
except ClientException as err:
|
||||
self._add_response_dict(caller_response_dict, kwargs)
|
||||
if self.attempts > self.retries:
|
||||
raise
|
||||
if err.http_status == 401:
|
||||
@ -1086,9 +1168,10 @@ class Connection(object):
|
||||
prefix=prefix, end_marker=end_marker,
|
||||
full_listing=full_listing)
|
||||
|
||||
def post_account(self, headers):
|
||||
def post_account(self, headers, response_dict=None):
|
||||
"""Wrapper for :func:`post_account`"""
|
||||
return self._retry(None, post_account, headers)
|
||||
return self._retry(None, post_account, headers,
|
||||
response_dict=response_dict)
|
||||
|
||||
def head_container(self, container):
|
||||
"""Wrapper for :func:`head_container`"""
|
||||
@ -1106,32 +1189,36 @@ class Connection(object):
|
||||
end_marker=end_marker, path=path,
|
||||
full_listing=full_listing)
|
||||
|
||||
def put_container(self, container, headers=None):
|
||||
def put_container(self, container, headers=None, response_dict=None):
|
||||
"""Wrapper for :func:`put_container`"""
|
||||
return self._retry(None, put_container, container, headers=headers)
|
||||
return self._retry(None, put_container, container, headers=headers,
|
||||
response_dict=response_dict)
|
||||
|
||||
def post_container(self, container, headers):
|
||||
def post_container(self, container, headers, response_dict=None):
|
||||
"""Wrapper for :func:`post_container`"""
|
||||
return self._retry(None, post_container, container, headers)
|
||||
return self._retry(None, post_container, container, headers,
|
||||
response_dict=response_dict)
|
||||
|
||||
def delete_container(self, container):
|
||||
def delete_container(self, container, response_dict=None):
|
||||
"""Wrapper for :func:`delete_container`"""
|
||||
return self._retry(None, delete_container, container)
|
||||
return self._retry(None, delete_container, container,
|
||||
response_dict=response_dict)
|
||||
|
||||
def head_object(self, container, obj):
|
||||
"""Wrapper for :func:`head_object`"""
|
||||
return self._retry(None, head_object, container, obj)
|
||||
|
||||
def get_object(self, container, obj, resp_chunk_size=None,
|
||||
query_string=None):
|
||||
query_string=None, response_dict=None):
|
||||
"""Wrapper for :func:`get_object`"""
|
||||
return self._retry(None, get_object, container, obj,
|
||||
resp_chunk_size=resp_chunk_size,
|
||||
query_string=query_string)
|
||||
query_string=query_string,
|
||||
response_dict=response_dict)
|
||||
|
||||
def put_object(self, container, obj, contents, content_length=None,
|
||||
etag=None, chunk_size=None, content_type=None,
|
||||
headers=None, query_string=None):
|
||||
headers=None, query_string=None, response_dict=None):
|
||||
"""Wrapper for :func:`put_object`"""
|
||||
|
||||
def _default_reset(*args, **kwargs):
|
||||
@ -1155,13 +1242,17 @@ class Connection(object):
|
||||
return self._retry(reset_func, put_object, container, obj, contents,
|
||||
content_length=content_length, etag=etag,
|
||||
chunk_size=chunk_size, content_type=content_type,
|
||||
headers=headers, query_string=query_string)
|
||||
headers=headers, query_string=query_string,
|
||||
response_dict=response_dict)
|
||||
|
||||
def post_object(self, container, obj, headers):
|
||||
def post_object(self, container, obj, headers, response_dict=None):
|
||||
"""Wrapper for :func:`post_object`"""
|
||||
return self._retry(None, post_object, container, obj, headers)
|
||||
return self._retry(None, post_object, container, obj, headers,
|
||||
response_dict=response_dict)
|
||||
|
||||
def delete_object(self, container, obj, query_string=None):
|
||||
def delete_object(self, container, obj, query_string=None,
|
||||
response_dict=None):
|
||||
"""Wrapper for :func:`delete_object`"""
|
||||
return self._retry(None, delete_object, container, obj,
|
||||
query_string=query_string)
|
||||
query_string=query_string,
|
||||
response_dict=response_dict)
|
||||
|
Loading…
x
Reference in New Issue
Block a user