6
from glance.common import exception
9
class ImageBodyIterator(object):
12
A class that acts as an iterator over an image file's
13
chunks of data. This is returned as part of the result
14
tuple from `glance.client.Client.get_image`
19
def __init__(self, response):
21
Constructs the object from an HTTPResponse object
23
self.response = response
27
Exposes an iterator over the chunks of data in the
31
chunk = self.response.read(ImageBodyIterator.CHUNKSIZE)
38
class BaseClient(object):
40
"""A base client class"""
44
def __init__(self, host, port, use_ssl):
46
Creates a new client to some service.
48
:param host: The host where service resides
49
:param port: The port where service resides
50
:param use_ssl: Should we use HTTPS?
54
self.use_ssl = use_ssl
55
self.connection = None
57
def get_connection_type(self):
59
Returns the proper connection type
62
return httplib.HTTPSConnection
64
return httplib.HTTPConnection
66
def do_request(self, method, action, body=None, headers=None,
69
Connects to the server and issues a request. Handles converting
70
any returned HTTP error status codes to OpenStack/Glance exceptions
71
and closing the server connection. Returns the result data, or
72
raises an appropriate exception.
74
:param method: HTTP method ("GET", "POST", "PUT", etc...)
75
:param action: part of URL after root netloc
76
:param body: string of data to send, or None (default)
77
:param headers: mapping of key/value pairs to add as headers
78
:param params: dictionary of key/value pairs to add to append
83
If the body param has a read attribute, and method is either
84
POST or PUT, this method will automatically conduct a chunked-transfer
85
encoding and use the body as a file object, transferring chunks
86
of data using the connection's send() method. This allows large
87
objects to be transferred efficiently without buffering the entire
90
if type(params) is dict:
91
action += '?' + urllib.urlencode(params)
94
connection_type = self.get_connection_type()
95
headers = headers or {}
96
c = connection_type(self.host, self.port)
98
# Do a simple request or a chunked request, depending
99
# on whether the body param is a file-like object and
100
# the method is PUT or POST
101
if hasattr(body, 'read') and method.lower() in ('post', 'put'):
103
c.putrequest(method, action)
105
for header, value in headers.items():
106
c.putheader(header, value)
107
c.putheader('Transfer-Encoding', 'chunked')
110
chunk = body.read(self.CHUNKSIZE)
112
c.send('%x\r\n%s\r\n' % (len(chunk), chunk))
113
chunk = body.read(self.CHUNKSIZE)
117
c.request(method, action, body, headers)
118
res = c.getresponse()
119
status_code = self.get_status_code(res)
120
if status_code in (httplib.OK,
125
elif status_code == httplib.UNAUTHORIZED:
126
raise exception.NotAuthorized
127
elif status_code == httplib.FORBIDDEN:
128
raise exception.NotAuthorized
129
elif status_code == httplib.NOT_FOUND:
130
raise exception.NotFound
131
elif status_code == httplib.CONFLICT:
132
raise exception.Duplicate(res.read())
133
elif status_code == httplib.BAD_REQUEST:
134
raise exception.Invalid(res.read())
135
elif status_code == httplib.INTERNAL_SERVER_ERROR:
136
raise Exception("Internal Server error: %s" % res.read())
138
raise Exception("Unknown error occurred! %s" % res.read())
140
except (socket.error, IOError), e:
141
raise exception.ClientConnectionError("Unable to connect to "
142
"server. Got error: %s" % e)
144
def get_status_code(self, response):
146
Returns the integer status code from the response, which
147
can be either a Webob.Response (used in testing) or httplib.Response
149
if hasattr(response, 'status_int'):
150
return response.status_int
152
return response.status
154
def _extract_params(self, actual_params, allowed_params):
156
Extract a subset of keys from a dictionary. The filters key
157
will also be extracted, and each of its values will be returned
158
as an individual param.
160
:param actual_params: dict of keys to filter
161
:param allowed_params: list of keys that 'actual_params' will be
163
:retval subset of 'params' dict
165
result = actual_params.get('filters', {})
166
for allowed_param in allowed_params:
167
if allowed_param in actual_params:
168
result[allowed_param] = actual_params[allowed_param]