Merge "Refactor HTTPClient to use two request methods"
This commit is contained in:
@@ -17,9 +17,6 @@
|
|||||||
Base utilities to build API operation managers and objects on top of.
|
Base utilities to build API operation managers and objects on top of.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from glanceclient.common import exceptions
|
|
||||||
|
|
||||||
|
|
||||||
# Python 2.4 compat
|
# Python 2.4 compat
|
||||||
try:
|
try:
|
||||||
all
|
all
|
||||||
@@ -50,11 +47,7 @@ class Manager(object):
|
|||||||
self.api = api
|
self.api = api
|
||||||
|
|
||||||
def _list(self, url, response_key, obj_class=None, body=None):
|
def _list(self, url, response_key, obj_class=None, body=None):
|
||||||
resp = None
|
resp, body = self.api.json_request('GET', url)
|
||||||
if body:
|
|
||||||
resp, body = self.api.post(url, body=body)
|
|
||||||
else:
|
|
||||||
resp, body = self.api.get(url)
|
|
||||||
|
|
||||||
if obj_class is None:
|
if obj_class is None:
|
||||||
obj_class = self.resource_class
|
obj_class = self.resource_class
|
||||||
@@ -62,29 +55,11 @@ class Manager(object):
|
|||||||
data = body[response_key]
|
data = body[response_key]
|
||||||
return [obj_class(self, res, loaded=True) for res in data if res]
|
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):
|
def _delete(self, url):
|
||||||
self.api.delete(url)
|
self.api.raw_request('DELETE', url)
|
||||||
|
|
||||||
def _update(self, url, body, response_key=None, method="PUT"):
|
def _update(self, url, body, response_key=None):
|
||||||
methods = {"PUT": self.api.put,
|
resp, body = self.api.json_request('PUT', url, body=body)
|
||||||
"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)
|
|
||||||
# PUT requests may not return a body
|
# PUT requests may not return a body
|
||||||
if body:
|
if body:
|
||||||
return self.resource_class(self, body[response_key])
|
return self.resource_class(self, body[response_key])
|
||||||
|
@@ -69,30 +69,16 @@ class HTTPClient(httplib2.Http):
|
|||||||
Wrapper around httplib2.Http.request to handle tasks such as
|
Wrapper around httplib2.Http.request to handle tasks such as
|
||||||
setting headers, JSON encoding/decoding, and error handling.
|
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
|
# Copy the kwargs so we can reuse the original in case of redirects
|
||||||
_kwargs = copy.copy(kwargs)
|
kwargs['headers'] = copy.deepcopy(kwargs.get('headers', {}))
|
||||||
_kwargs.setdefault('headers', kwargs.get('headers', {}))
|
kwargs['headers'].setdefault('User-Agent', USER_AGENT)
|
||||||
_kwargs['headers']['User-Agent'] = USER_AGENT
|
if self.auth_token:
|
||||||
if 'raw_body' in _kwargs:
|
kwargs['headers'].setdefault('X-Auth-Token', self.auth_token)
|
||||||
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'])
|
|
||||||
|
|
||||||
resp, body = super(HTTPClient, self).request(url, method, **_kwargs)
|
resp, body = super(HTTPClient, self).request(url, method, **kwargs)
|
||||||
self.http_log((url, method,), _kwargs, resp, body)
|
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
|
|
||||||
|
|
||||||
if 400 <= resp.status < 600:
|
if 400 <= resp.status < 600:
|
||||||
logger.exception("Request returned failure status.")
|
logger.exception("Request returned failure status.")
|
||||||
@@ -103,26 +89,28 @@ class HTTPClient(httplib2.Http):
|
|||||||
|
|
||||||
return resp, body
|
return resp, body
|
||||||
|
|
||||||
def request(self, url, method, **kwargs):
|
def json_request(self, method, url, **kwargs):
|
||||||
kwargs.setdefault('headers', {})
|
kwargs.setdefault('headers', {})
|
||||||
if self.auth_token:
|
kwargs['headers'].setdefault('Content-Type', 'application/json')
|
||||||
kwargs['headers']['X-Auth-Token'] = self.auth_token
|
|
||||||
|
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
|
return resp, body
|
||||||
|
|
||||||
def head(self, url, **kwargs):
|
def raw_request(self, method, url, **kwargs):
|
||||||
return self.request(url, 'HEAD', **kwargs)
|
kwargs.setdefault('headers', {})
|
||||||
|
kwargs['headers'].setdefault('Content-Type',
|
||||||
def get(self, url, **kwargs):
|
'application/octet-stream')
|
||||||
return self.request(url, 'GET', **kwargs)
|
return self._http_request(url, method, **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)
|
|
||||||
|
@@ -34,7 +34,7 @@ class ImageMemberManager(base.Manager):
|
|||||||
def get(self, image, member_id):
|
def get(self, image, member_id):
|
||||||
image_id = base.getid(image)
|
image_id = base.getid(image)
|
||||||
url = '/v1/images/%s/members/%s' % (image_id, member_id)
|
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 = body['member']
|
||||||
member['image_id'] = image_id
|
member['image_id'] = image_id
|
||||||
return ImageMember(self, member, loaded=True)
|
return ImageMember(self, member, loaded=True)
|
||||||
@@ -59,7 +59,8 @@ class ImageMemberManager(base.Manager):
|
|||||||
|
|
||||||
def _list_by_image(self, image):
|
def _list_by_image(self, image):
|
||||||
image_id = base.getid(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 = []
|
out = []
|
||||||
for member in body['members']:
|
for member in body['members']:
|
||||||
member['image_id'] = image_id
|
member['image_id'] = image_id
|
||||||
@@ -68,7 +69,8 @@ class ImageMemberManager(base.Manager):
|
|||||||
|
|
||||||
def _list_by_member(self, member):
|
def _list_by_member(self, member):
|
||||||
member_id = base.getid(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 = []
|
out = []
|
||||||
for member in body['shared_images']:
|
for member in body['shared_images']:
|
||||||
member['member_id'] = member_id
|
member['member_id'] = member_id
|
||||||
@@ -98,4 +100,4 @@ class ImageMemberManager(base.Manager):
|
|||||||
obj['can_share'] = member['can_share']
|
obj['can_share'] = member['can_share']
|
||||||
memberships.append(obj)
|
memberships.append(obj)
|
||||||
url = '/v1/images/%s/members' % base.getid(image)
|
url = '/v1/images/%s/members' % base.getid(image)
|
||||||
self.api.put(url, {}, {'memberships': memberships})
|
self.api.json_request('PUT', url, {}, {'memberships': memberships})
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
import copy
|
import copy
|
||||||
import errno
|
import errno
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import urllib
|
import urllib
|
||||||
|
|
||||||
@@ -67,7 +68,7 @@ class ImageManager(base.Manager):
|
|||||||
:param image: image object or id to look up
|
:param image: image object or id to look up
|
||||||
:rtype: :class:`Image`
|
: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)
|
meta = self._image_meta_from_headers(resp)
|
||||||
return Image(self, meta)
|
return Image(self, meta)
|
||||||
|
|
||||||
@@ -142,9 +143,9 @@ class ImageManager(base.Manager):
|
|||||||
if copy_from is not None:
|
if copy_from is not None:
|
||||||
hdrs['x-glance-api-copy-from'] = copy_from
|
hdrs['x-glance-api-copy-from'] = copy_from
|
||||||
|
|
||||||
resp, body = self.api.post('/v1/images', headers=hdrs,
|
resp, body = self.api.raw_request(
|
||||||
raw_body=image_data)
|
'POST', '/v1/images', headers=hdrs, body=image_data)
|
||||||
return Image(self, body['image'])
|
return Image(self, json.loads(body)['image'])
|
||||||
|
|
||||||
def update(self, image, **kwargs):
|
def update(self, image, **kwargs):
|
||||||
"""Update an image
|
"""Update an image
|
||||||
@@ -172,7 +173,7 @@ class ImageManager(base.Manager):
|
|||||||
if copy_from is not None:
|
if copy_from is not None:
|
||||||
hdrs['x-glance-api-copy-from'] = copy_from
|
hdrs['x-glance-api-copy-from'] = copy_from
|
||||||
|
|
||||||
image_id = base.getid(image)
|
url = '/v1/images/%s' % base.getid(image)
|
||||||
resp, body = self.api.put('/v1/images/%s' % image_id, headers=hdrs,
|
resp, body = self.api.raw_request(
|
||||||
raw_body=image_data)
|
'PUT', url, headers=hdrs, body=image_data)
|
||||||
return Image(self, body['image'])
|
return Image(self, json.loads(body)['image'])
|
||||||
|
@@ -13,12 +13,16 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
fixtures = {
|
fixtures = {
|
||||||
'/v1/images': {
|
'/v1/images': {
|
||||||
'POST': (
|
'POST': (
|
||||||
{
|
{
|
||||||
'location': '/v1/images/1',
|
'location': '/v1/images/1',
|
||||||
},
|
},
|
||||||
|
json.dumps(
|
||||||
{'image': {
|
{'image': {
|
||||||
'id': '1',
|
'id': '1',
|
||||||
'name': 'image-1',
|
'name': 'image-1',
|
||||||
@@ -29,7 +33,9 @@ fixtures = {
|
|||||||
'min_ram': '512',
|
'min_ram': '512',
|
||||||
'min_disk': '10',
|
'min_disk': '10',
|
||||||
'properties': {'a': 'b', 'c': 'd'},
|
'properties': {'a': 'b', 'c': 'd'},
|
||||||
}}),
|
}},
|
||||||
|
),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
'/v1/images/detail': {
|
'/v1/images/detail': {
|
||||||
'GET': (
|
'GET': (
|
||||||
@@ -53,6 +59,7 @@ fixtures = {
|
|||||||
None),
|
None),
|
||||||
'PUT': (
|
'PUT': (
|
||||||
{},
|
{},
|
||||||
|
json.dumps(
|
||||||
{'image': {
|
{'image': {
|
||||||
'id': '1',
|
'id': '1',
|
||||||
'name': 'image-2',
|
'name': 'image-2',
|
||||||
@@ -65,6 +72,7 @@ fixtures = {
|
|||||||
'properties': {'a': 'b', 'c': 'd'},
|
'properties': {'a': 'b', 'c': 'd'},
|
||||||
}},
|
}},
|
||||||
),
|
),
|
||||||
|
),
|
||||||
'DELETE': ({}, None),
|
'DELETE': ({}, None),
|
||||||
},
|
},
|
||||||
'/v1/images/1/members': {
|
'/v1/images/1/members': {
|
||||||
@@ -110,17 +118,8 @@ class FakeAPI(object):
|
|||||||
url = url.split('?', 1)[0]
|
url = url.split('?', 1)[0]
|
||||||
return fixtures[url][method]
|
return fixtures[url][method]
|
||||||
|
|
||||||
def get(self, url):
|
def raw_request(self, *args, **kwargs):
|
||||||
return self._request('GET', url)
|
return self._request(*args, **kwargs)
|
||||||
|
|
||||||
def head(self, url):
|
def json_request(self, *args, **kwargs):
|
||||||
return self._request('HEAD', url)
|
return self._request(*args, **kwargs)
|
||||||
|
|
||||||
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)
|
|
||||||
|
Reference in New Issue
Block a user