diff options
Diffstat (limited to 'swift/common/direct_client.py')
-rw-r--r-- | swift/common/direct_client.py | 195 |
1 files changed, 115 insertions, 80 deletions
diff --git a/swift/common/direct_client.py b/swift/common/direct_client.py index b86ee4c2d..6a6efdea5 100644 --- a/swift/common/direct_client.py +++ b/swift/common/direct_client.py @@ -39,6 +39,19 @@ except ImportError: import json +class DirectClientException(ClientException): + + def __init__(self, stype, method, node, part, path, resp): + full_path = quote('/%s/%s%s' % (node['device'], part, path)) + msg = '%s server %s:%s direct %s %r gave status %s' % ( + stype, node['ip'], node['port'], method, full_path, resp.status) + headers = HeaderKeyDict(resp.getheaders()) + super(DirectClientException, self).__init__( + msg, http_host=node['ip'], http_port=node['port'], + http_device=node['device'], http_status=resp.status, + http_reason=resp.reason, http_headers=headers) + + def _get_direct_account_container(path, stype, node, part, account, marker=None, limit=None, prefix=None, delimiter=None, conn_timeout=5, @@ -65,17 +78,10 @@ def _get_direct_account_container(path, stype, node, part, resp = conn.getresponse() if not is_success(resp.status): resp.read() - raise ClientException( - '%s server %s:%s direct GET %s gave stats %s' % - (stype, node['ip'], node['port'], - repr('/%s/%s%s' % (node['device'], part, path)), - resp.status), - http_host=node['ip'], http_port=node['port'], - http_device=node['device'], http_status=resp.status, - http_reason=resp.reason) - resp_headers = {} + raise DirectClientException(stype, 'GET', node, part, path, resp) + resp_headers = HeaderKeyDict() for header, value in resp.getheaders(): - resp_headers[header.lower()] = value + resp_headers[header] = value if resp.status == HTTP_NO_CONTENT: resp.read() return resp_headers, [] @@ -106,7 +112,7 @@ def direct_get_account(node, part, account, marker=None, limit=None, :param conn_timeout: timeout in seconds for establishing the connection :param response_timeout: timeout in seconds for getting the response :returns: a tuple of (response headers, a list of containers) The response - headers will be a dict and all header names will be lowercase. + headers will HeaderKeyDict. """ path = '/' + account return _get_direct_account_container(path, "Account", node, part, @@ -117,6 +123,24 @@ def direct_get_account(node, part, account, marker=None, limit=None, response_timeout=15) +def direct_delete_account(node, part, account, conn_timeout=5, + response_timeout=15, headers=None): + if headers is None: + headers = {} + + path = '/%s' % account + with Timeout(conn_timeout): + conn = http_connect(node['ip'], node['port'], node['device'], part, + 'DELETE', path, + headers=gen_headers(headers, True)) + with Timeout(response_timeout): + resp = conn.getresponse() + resp.read() + if not is_success(resp.status): + raise DirectClientException('Account', 'DELETE', + node, part, path, resp) + + def direct_head_container(node, part, account, container, conn_timeout=5, response_timeout=15): """ @@ -128,8 +152,7 @@ def direct_head_container(node, part, account, container, conn_timeout=5, :param container: container name :param conn_timeout: timeout in seconds for establishing the connection :param response_timeout: timeout in seconds for getting the response - :returns: a dict containing the response's headers (all header names will - be lowercase) + :returns: a dict containing the response's headers in a HeaderKeyDict """ path = '/%s/%s' % (account, container) with Timeout(conn_timeout): @@ -139,17 +162,11 @@ def direct_head_container(node, part, account, container, conn_timeout=5, resp = conn.getresponse() resp.read() if not is_success(resp.status): - raise ClientException( - 'Container server %s:%s direct HEAD %s gave status %s' % - (node['ip'], node['port'], - repr('/%s/%s%s' % (node['device'], part, path)), - resp.status), - http_host=node['ip'], http_port=node['port'], - http_device=node['device'], http_status=resp.status, - http_reason=resp.reason) - resp_headers = {} + raise DirectClientException('Container', 'HEAD', + node, part, path, resp) + resp_headers = HeaderKeyDict() for header, value in resp.getheaders(): - resp_headers[header.lower()] = value + resp_headers[header] = value return resp_headers @@ -170,7 +187,7 @@ def direct_get_container(node, part, account, container, marker=None, :param conn_timeout: timeout in seconds for establishing the connection :param response_timeout: timeout in seconds for getting the response :returns: a tuple of (response headers, a list of objects) The response - headers will be a dict and all header names will be lowercase. + headers will be a HeaderKeyDict. """ path = '/%s/%s' % (account, container) return _get_direct_account_container(path, "Container", node, @@ -195,17 +212,56 @@ def direct_delete_container(node, part, account, container, conn_timeout=5, resp = conn.getresponse() resp.read() if not is_success(resp.status): - raise ClientException( - 'Container server %s:%s direct DELETE %s gave status %s' % - (node['ip'], node['port'], - repr('/%s/%s%s' % (node['device'], part, path)), resp.status), - http_host=node['ip'], http_port=node['port'], - http_device=node['device'], http_status=resp.status, - http_reason=resp.reason) + raise DirectClientException('Container', 'DELETE', + node, part, path, resp) + + +def direct_put_container_object(node, part, account, container, obj, + conn_timeout=5, response_timeout=15, + headers=None): + if headers is None: + headers = {} + + have_x_timestamp = 'x-timestamp' in (k.lower() for k in headers) + + path = '/%s/%s/%s' % (account, container, obj) + with Timeout(conn_timeout): + conn = http_connect(node['ip'], node['port'], node['device'], part, + 'PUT', path, + headers=gen_headers(headers, + add_ts=(not have_x_timestamp))) + with Timeout(response_timeout): + resp = conn.getresponse() + resp.read() + if not is_success(resp.status): + raise DirectClientException('Container', 'PUT', + node, part, path, resp) + + +def direct_delete_container_object(node, part, account, container, obj, + conn_timeout=5, response_timeout=15, + headers=None): + if headers is None: + headers = {} + + headers = gen_headers(headers, add_ts='x-timestamp' not in ( + k.lower() for k in headers)) + + path = '/%s/%s/%s' % (account, container, obj) + with Timeout(conn_timeout): + conn = http_connect(node['ip'], node['port'], node['device'], part, + 'DELETE', path, headers=headers) + + with Timeout(response_timeout): + resp = conn.getresponse() + resp.read() + if not is_success(resp.status): + raise DirectClientException('Container', 'DELETE', + node, part, path, resp) def direct_head_object(node, part, account, container, obj, conn_timeout=5, - response_timeout=15): + response_timeout=15, headers=None): """ Request object information directly from the object server. @@ -216,28 +272,27 @@ def direct_head_object(node, part, account, container, obj, conn_timeout=5, :param obj: object name :param conn_timeout: timeout in seconds for establishing the connection :param response_timeout: timeout in seconds for getting the response - :returns: a dict containing the response's headers (all header names will - be lowercase) + :param headers: dict to be passed into HTTPConnection headers + :returns: a dict containing the response's headers in a HeaderKeyDict """ + if headers is None: + headers = {} + + headers = gen_headers(headers) + path = '/%s/%s/%s' % (account, container, obj) with Timeout(conn_timeout): conn = http_connect(node['ip'], node['port'], node['device'], part, - 'HEAD', path, headers=gen_headers()) + 'HEAD', path, headers=headers) with Timeout(response_timeout): resp = conn.getresponse() resp.read() if not is_success(resp.status): - raise ClientException( - 'Object server %s:%s direct HEAD %s gave status %s' % - (node['ip'], node['port'], - repr('/%s/%s%s' % (node['device'], part, path)), - resp.status), - http_host=node['ip'], http_port=node['port'], - http_device=node['device'], http_status=resp.status, - http_reason=resp.reason) - resp_headers = {} + raise DirectClientException('Object', 'HEAD', + node, part, path, resp) + resp_headers = HeaderKeyDict() for header, value in resp.getheaders(): - resp_headers[header.lower()] = value + resp_headers[header] = value return resp_headers @@ -256,7 +311,7 @@ def direct_get_object(node, part, account, container, obj, conn_timeout=5, :param resp_chunk_size: if defined, chunk size of data to read. :param headers: dict to be passed into HTTPConnection 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. + headers will be a HeaderKeyDict. """ if headers is None: headers = {} @@ -269,13 +324,8 @@ def direct_get_object(node, part, account, container, obj, conn_timeout=5, resp = conn.getresponse() if not is_success(resp.status): resp.read() - raise ClientException( - 'Object server %s:%s direct GET %s gave status %s' % - (node['ip'], node['port'], - repr('/%s/%s%s' % (node['device'], part, path)), resp.status), - http_host=node['ip'], http_port=node['port'], - http_device=node['device'], http_status=resp.status, - http_reason=resp.reason) + raise DirectClientException('Object', 'GET', + node, part, path, resp) if resp_chunk_size: def _object_body(): @@ -286,9 +336,9 @@ def direct_get_object(node, part, account, container, obj, conn_timeout=5, object_body = _object_body() else: object_body = resp.read() - resp_headers = {} + resp_headers = HeaderKeyDict() for header, value in resp.getheaders(): - resp_headers[header.lower()] = value + resp_headers[header] = value return resp_headers, object_body @@ -368,14 +418,8 @@ def direct_put_object(node, part, account, container, name, contents, resp = conn.getresponse() resp.read() if not is_success(resp.status): - raise ClientException( - 'Object server %s:%s direct PUT %s gave status %s' % - (node['ip'], node['port'], - repr('/%s/%s%s' % (node['device'], part, path)), - resp.status), - http_host=node['ip'], http_port=node['port'], - http_device=node['device'], http_status=resp.status, - http_reason=resp.reason) + raise DirectClientException('Object', 'PUT', + node, part, path, resp) return resp.getheader('etag').strip('"') @@ -402,14 +446,8 @@ def direct_post_object(node, part, account, container, name, headers, resp = conn.getresponse() resp.read() if not is_success(resp.status): - raise ClientException( - 'Object server %s:%s direct POST %s gave status %s' % - (node['ip'], node['port'], - repr('/%s/%s%s' % (node['device'], part, path)), - resp.status), - http_host=node['ip'], http_port=node['port'], - http_device=node['device'], http_status=resp.status, - http_reason=resp.reason) + raise DirectClientException('Object', 'POST', + node, part, path, resp) def direct_delete_object(node, part, account, container, obj, @@ -429,22 +467,19 @@ def direct_delete_object(node, part, account, container, obj, if headers is None: headers = {} + headers = gen_headers(headers, add_ts='x-timestamp' not in ( + k.lower() for k in headers)) + path = '/%s/%s/%s' % (account, container, obj) with Timeout(conn_timeout): conn = http_connect(node['ip'], node['port'], node['device'], part, - 'DELETE', path, headers=gen_headers(headers, True)) + 'DELETE', path, headers=headers) with Timeout(response_timeout): resp = conn.getresponse() resp.read() if not is_success(resp.status): - raise ClientException( - 'Object server %s:%s direct DELETE %s gave status %s' % - (node['ip'], node['port'], - repr('/%s/%s%s' % (node['device'], part, path)), - resp.status), - http_host=node['ip'], http_port=node['port'], - http_device=node['device'], http_status=resp.status, - http_reason=resp.reason) + raise DirectClientException('Object', 'DELETE', + node, part, path, resp) def retry(func, *args, **kwargs): |