diff --git a/glanceclient/common/base.py b/glanceclient/common/base.py index 686ed12c..d037267b 100644 --- a/glanceclient/common/base.py +++ b/glanceclient/common/base.py @@ -17,9 +17,6 @@ Base utilities to build API operation managers and objects on top of. """ -from glanceclient.common import exceptions - - # Python 2.4 compat try: all @@ -50,11 +47,7 @@ class Manager(object): self.api = api def _list(self, url, response_key, obj_class=None, body=None): - resp = None - if body: - resp, body = self.api.post(url, body=body) - else: - resp, body = self.api.get(url) + resp, body = self.api.json_request('GET', url) if obj_class is None: obj_class = self.resource_class @@ -62,29 +55,11 @@ class Manager(object): data = body[response_key] return [obj_class(self, res, loaded=True) for res in data if res] - def _get(self, url, response_key): - resp, body = self.api.get(url) - return self.resource_class(self, body[response_key]) - - def _create(self, url, body, response_key, return_raw=False): - resp, body = self.api.post(url, body=body) - if return_raw: - return body[response_key] - return self.resource_class(self, body[response_key]) - def _delete(self, url): - self.api.delete(url) + self.api.raw_request('DELETE', url) - def _update(self, url, body, response_key=None, method="PUT"): - methods = {"PUT": self.api.put, - "POST": self.api.post} - try: - _method = methods[method] - except KeyError: - msg = "Invalid update method: %s" % method - raise exceptions.ClientException(msg) - - resp, body = _method(url, body=body) + def _update(self, url, body, response_key=None): + resp, body = self.api.json_request('PUT', url, body=body) # PUT requests may not return a body if body: return self.resource_class(self, body[response_key]) diff --git a/glanceclient/common/http.py b/glanceclient/common/http.py index 9ac51f21..fb73e134 100644 --- a/glanceclient/common/http.py +++ b/glanceclient/common/http.py @@ -69,30 +69,16 @@ class HTTPClient(httplib2.Http): Wrapper around httplib2.Http.request to handle tasks such as setting headers, JSON encoding/decoding, and error handling. """ + url = self.endpoint + url + # Copy the kwargs so we can reuse the original in case of redirects - _kwargs = copy.copy(kwargs) - _kwargs.setdefault('headers', kwargs.get('headers', {})) - _kwargs['headers']['User-Agent'] = USER_AGENT - if 'raw_body' in _kwargs: - raw_body = _kwargs.pop('raw_body') - if raw_body is not None: - _kwargs['headers']['Content-Type'] = 'application/octet-stream' - _kwargs['body'] = raw_body - elif 'body' in kwargs and kwargs['body'] is not None: - _kwargs['headers']['Content-Type'] = 'application/json' - _kwargs['body'] = json.dumps(kwargs['body']) + kwargs['headers'] = copy.deepcopy(kwargs.get('headers', {})) + kwargs['headers'].setdefault('User-Agent', USER_AGENT) + if self.auth_token: + kwargs['headers'].setdefault('X-Auth-Token', self.auth_token) - resp, body = super(HTTPClient, self).request(url, method, **_kwargs) - self.http_log((url, method,), _kwargs, resp, body) - - if body: - try: - body = json.loads(body) - except ValueError: - logger.debug("Could not decode JSON from body: %s" % body) - else: - logger.debug("No body was returned.") - body = None + resp, body = super(HTTPClient, self).request(url, method, **kwargs) + self.http_log((url, method,), kwargs, resp, body) if 400 <= resp.status < 600: logger.exception("Request returned failure status.") @@ -103,26 +89,28 @@ class HTTPClient(httplib2.Http): return resp, body - def request(self, url, method, **kwargs): + def json_request(self, method, url, **kwargs): kwargs.setdefault('headers', {}) - if self.auth_token: - kwargs['headers']['X-Auth-Token'] = self.auth_token + kwargs['headers'].setdefault('Content-Type', 'application/json') + + if 'body' in kwargs: + kwargs['body'] = json.dumps(kwargs['body']) + + resp, body = self._http_request(url, method, **kwargs) + + if body: + try: + body = json.loads(body) + except ValueError: + logger.debug("Could not decode JSON from body: %s" % body) + else: + logger.debug("No body was returned.") + body = None - req_url = self.endpoint + url - resp, body = self._http_request(req_url, method, **kwargs) return resp, body - def head(self, url, **kwargs): - return self.request(url, 'HEAD', **kwargs) - - def get(self, url, **kwargs): - return self.request(url, 'GET', **kwargs) - - def post(self, url, **kwargs): - return self.request(url, 'POST', **kwargs) - - def put(self, url, **kwargs): - return self.request(url, 'PUT', **kwargs) - - def delete(self, url, **kwargs): - return self.request(url, 'DELETE', **kwargs) + def raw_request(self, method, url, **kwargs): + kwargs.setdefault('headers', {}) + kwargs['headers'].setdefault('Content-Type', + 'application/octet-stream') + return self._http_request(url, method, **kwargs) diff --git a/glanceclient/v1/image_members.py b/glanceclient/v1/image_members.py index d561377d..a989850c 100644 --- a/glanceclient/v1/image_members.py +++ b/glanceclient/v1/image_members.py @@ -34,7 +34,7 @@ class ImageMemberManager(base.Manager): def get(self, image, member_id): image_id = base.getid(image) url = '/v1/images/%s/members/%s' % (image_id, member_id) - resp, body = self.api.get(url) + resp, body = self.api.json_request('GET', url) member = body['member'] member['image_id'] = image_id return ImageMember(self, member, loaded=True) @@ -59,7 +59,8 @@ class ImageMemberManager(base.Manager): def _list_by_image(self, image): image_id = base.getid(image) - resp, body = self.api.get('/v1/images/%s/members' % image_id) + url = '/v1/images/%s/members' % image_id + resp, body = self.api.json_request('GET', url) out = [] for member in body['members']: member['image_id'] = image_id @@ -68,7 +69,8 @@ class ImageMemberManager(base.Manager): def _list_by_member(self, member): member_id = base.getid(member) - resp, body = self.api.get('/v1/shared-images/%s' % member_id) + url = '/v1/shared-images/%s' % member_id + resp, body = self.api.json_request('GET', url) out = [] for member in body['shared_images']: member['member_id'] = member_id @@ -98,4 +100,4 @@ class ImageMemberManager(base.Manager): obj['can_share'] = member['can_share'] memberships.append(obj) url = '/v1/images/%s/members' % base.getid(image) - self.api.put(url, {}, {'memberships': memberships}) + self.api.json_request('PUT', url, {}, {'memberships': memberships}) diff --git a/glanceclient/v1/images.py b/glanceclient/v1/images.py index 2179f9d7..f9bad0c2 100644 --- a/glanceclient/v1/images.py +++ b/glanceclient/v1/images.py @@ -15,6 +15,7 @@ import copy import errno +import json import os import urllib @@ -67,7 +68,7 @@ class ImageManager(base.Manager): :param image: image object or id to look up :rtype: :class:`Image` """ - resp, body = self.api.head('/v1/images/%s' % image_id) + resp, body = self.api.raw_request('HEAD', '/v1/images/%s' % image_id) meta = self._image_meta_from_headers(resp) return Image(self, meta) @@ -142,9 +143,9 @@ class ImageManager(base.Manager): if copy_from is not None: hdrs['x-glance-api-copy-from'] = copy_from - resp, body = self.api.post('/v1/images', headers=hdrs, - raw_body=image_data) - return Image(self, body['image']) + resp, body = self.api.raw_request( + 'POST', '/v1/images', headers=hdrs, body=image_data) + return Image(self, json.loads(body)['image']) def update(self, image, **kwargs): """Update an image @@ -172,7 +173,7 @@ class ImageManager(base.Manager): if copy_from is not None: hdrs['x-glance-api-copy-from'] = copy_from - image_id = base.getid(image) - resp, body = self.api.put('/v1/images/%s' % image_id, headers=hdrs, - raw_body=image_data) - return Image(self, body['image']) + url = '/v1/images/%s' % base.getid(image) + resp, body = self.api.raw_request( + 'PUT', url, headers=hdrs, body=image_data) + return Image(self, json.loads(body)['image']) diff --git a/tests/v1/utils.py b/tests/v1/utils.py index 4a3bb41e..c38519b4 100644 --- a/tests/v1/utils.py +++ b/tests/v1/utils.py @@ -13,23 +13,29 @@ # License for the specific language governing permissions and limitations # under the License. +import json + + fixtures = { '/v1/images': { 'POST': ( { 'location': '/v1/images/1', }, - {'image': { - 'id': '1', - 'name': 'image-1', - 'container_format': 'ovf', - 'disk_format': 'vhd', - 'owner': 'asdf', - 'size': '1024', - 'min_ram': '512', - 'min_disk': '10', - 'properties': {'a': 'b', 'c': 'd'}, - }}), + json.dumps( + {'image': { + 'id': '1', + 'name': 'image-1', + 'container_format': 'ovf', + 'disk_format': 'vhd', + 'owner': 'asdf', + 'size': '1024', + 'min_ram': '512', + 'min_disk': '10', + 'properties': {'a': 'b', 'c': 'd'}, + }}, + ), + ), }, '/v1/images/detail': { 'GET': ( @@ -53,17 +59,19 @@ fixtures = { None), 'PUT': ( {}, - {'image': { - 'id': '1', - 'name': 'image-2', - 'container_format': 'ovf', - 'disk_format': 'vhd', - 'owner': 'asdf', - 'size': '1024', - 'min_ram': '512', - 'min_disk': '10', - 'properties': {'a': 'b', 'c': 'd'}, - }}, + json.dumps( + {'image': { + 'id': '1', + 'name': 'image-2', + 'container_format': 'ovf', + 'disk_format': 'vhd', + 'owner': 'asdf', + 'size': '1024', + 'min_ram': '512', + 'min_disk': '10', + 'properties': {'a': 'b', 'c': 'd'}, + }}, + ), ), 'DELETE': ({}, None), }, @@ -110,17 +118,8 @@ class FakeAPI(object): url = url.split('?', 1)[0] return fixtures[url][method] - def get(self, url): - return self._request('GET', url) + def raw_request(self, *args, **kwargs): + return self._request(*args, **kwargs) - def head(self, url): - return self._request('HEAD', url) - - def post(self, url, headers=None, body=None, raw_body=None): - return self._request('POST', url, headers, body or raw_body) - - def put(self, url, headers=None, body=None, raw_body=None): - return self._request('PUT', url, headers, body or raw_body) - - def delete(self, url): - return self._request('DELETE', url) + def json_request(self, *args, **kwargs): + return self._request(*args, **kwargs)