Merge "Return request ID to callers"
This commit is contained in:
commit
e9e933145e
|
@ -57,10 +57,12 @@ class Manager(object):
|
|||
obj_class = self.resource_class
|
||||
|
||||
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],
|
||||
resp)
|
||||
|
||||
def _delete(self, url):
|
||||
self.api.raw_request('DELETE', url)
|
||||
resp = self.api.raw_request('DELETE', url)
|
||||
return resp[0]
|
||||
|
||||
def _update(self, url, body, response_key=None):
|
||||
resp, body = self.api.json_request('PUT', url, body=body)
|
||||
|
|
|
@ -39,6 +39,8 @@ SORT_DIR_VALUES = ('asc', 'desc')
|
|||
SORT_KEY_VALUES = ('name', 'status', 'container_format', 'disk_format',
|
||||
'size', 'id', 'created_at', 'updated_at')
|
||||
|
||||
OS_REQ_ID_HDR = 'x-openstack-request-id'
|
||||
|
||||
|
||||
class Image(base.Resource):
|
||||
def __repr__(self):
|
||||
|
@ -47,7 +49,7 @@ class Image(base.Resource):
|
|||
def update(self, **fields):
|
||||
self.manager.update(self, **fields)
|
||||
|
||||
def delete(self):
|
||||
def delete(self, **kwargs):
|
||||
return self.manager.delete(self)
|
||||
|
||||
def data(self, **kwargs):
|
||||
|
@ -104,7 +106,7 @@ class ImageManager(base.Manager):
|
|||
pass
|
||||
return meta
|
||||
|
||||
def get(self, image):
|
||||
def get(self, image, **kwargs):
|
||||
"""Get the metadata for a specific image.
|
||||
|
||||
:param image: image object or id to look up
|
||||
|
@ -115,9 +117,13 @@ class ImageManager(base.Manager):
|
|||
resp, body = self.api.raw_request('HEAD', '/v1/images/%s'
|
||||
% parse.quote(str(image_id)))
|
||||
meta = self._image_meta_from_headers(dict(resp.getheaders()))
|
||||
return_request_id = kwargs.get('return_req_id', None)
|
||||
if return_request_id is not None:
|
||||
return_request_id.append(resp.getheader(OS_REQ_ID_HDR, None))
|
||||
|
||||
return Image(self, meta)
|
||||
|
||||
def data(self, image, do_checksum=True):
|
||||
def data(self, image, do_checksum=True, **kwargs):
|
||||
"""Get the raw data for a specific image.
|
||||
|
||||
:param image: image object or id to look up
|
||||
|
@ -130,6 +136,10 @@ class ImageManager(base.Manager):
|
|||
checksum = resp.getheader('x-image-meta-checksum', None)
|
||||
if do_checksum and checksum is not None:
|
||||
body.set_checksum(checksum)
|
||||
return_request_id = kwargs.get('return_req_id', None)
|
||||
if return_request_id is not None:
|
||||
return_request_id.append(resp.getheader(OS_REQ_ID_HDR, None))
|
||||
|
||||
return body
|
||||
|
||||
def list(self, **kwargs):
|
||||
|
@ -144,11 +154,14 @@ class ImageManager(base.Manager):
|
|||
:param owner: If provided, only images with this owner (tenant id)
|
||||
will be listed. An empty string ('') matches ownerless
|
||||
images.
|
||||
:param return_request_id: If an empty list is provided, populate this
|
||||
list with the request ID value from the header
|
||||
x-openstack-request-id
|
||||
:rtype: list of :class:`Image`
|
||||
"""
|
||||
absolute_limit = kwargs.get('limit')
|
||||
|
||||
def paginate(qp, seen=0):
|
||||
def paginate(qp, seen=0, return_request_id=None):
|
||||
def filter_owner(owner, image):
|
||||
# If client side owner 'filter' is specified
|
||||
# only return images that match 'owner'.
|
||||
|
@ -173,7 +186,11 @@ class ImageManager(base.Manager):
|
|||
qp[param] = strutils.safe_encode(value)
|
||||
|
||||
url = '/v1/images/detail?%s' % parse.urlencode(qp)
|
||||
images = self._list(url, "images")
|
||||
images, resp = self._list(url, "images")
|
||||
|
||||
if return_request_id is not None:
|
||||
return_request_id.append(resp.getheader(OS_REQ_ID_HDR, None))
|
||||
|
||||
for image in images:
|
||||
if filter_owner(owner, image):
|
||||
continue
|
||||
|
@ -186,7 +203,7 @@ class ImageManager(base.Manager):
|
|||
if (page_size and len(images) == page_size and
|
||||
(absolute_limit is None or 0 < seen < absolute_limit)):
|
||||
qp['marker'] = image.id
|
||||
for image in paginate(qp, seen):
|
||||
for image in paginate(qp, seen, return_request_id):
|
||||
yield image
|
||||
|
||||
params = {'limit': kwargs.get('page_size', DEFAULT_PAGE_SIZE)}
|
||||
|
@ -221,11 +238,16 @@ class ImageManager(base.Manager):
|
|||
if 'is_public' in kwargs:
|
||||
params['is_public'] = kwargs['is_public']
|
||||
|
||||
return paginate(params)
|
||||
return_request_id = kwargs.get('return_req_id', None)
|
||||
|
||||
def delete(self, image):
|
||||
return paginate(params, 0, return_request_id)
|
||||
|
||||
def delete(self, image, **kwargs):
|
||||
"""Delete an image."""
|
||||
self._delete("/v1/images/%s" % base.getid(image))
|
||||
resp = self._delete("/v1/images/%s" % base.getid(image))
|
||||
return_request_id = kwargs.get('return_req_id', None)
|
||||
if return_request_id is not None:
|
||||
return_request_id.append(resp.getheader(OS_REQ_ID_HDR, None))
|
||||
|
||||
def create(self, **kwargs):
|
||||
"""Create an image
|
||||
|
@ -242,6 +264,8 @@ class ImageManager(base.Manager):
|
|||
for field in kwargs:
|
||||
if field in CREATE_PARAMS:
|
||||
fields[field] = kwargs[field]
|
||||
elif field == 'return_req_id':
|
||||
continue
|
||||
else:
|
||||
msg = 'create() got an unexpected keyword argument \'%s\''
|
||||
raise TypeError(msg % field)
|
||||
|
@ -254,6 +278,10 @@ class ImageManager(base.Manager):
|
|||
resp, body_iter = self.api.raw_request(
|
||||
'POST', '/v1/images', headers=hdrs, body=image_data)
|
||||
body = json.loads(''.join([c for c in body_iter]))
|
||||
return_request_id = kwargs.get('return_req_id', None)
|
||||
if return_request_id is not None:
|
||||
return_request_id.append(resp.getheader(OS_REQ_ID_HDR, None))
|
||||
|
||||
return Image(self, self._format_image_meta_for_user(body['image']))
|
||||
|
||||
def update(self, image, **kwargs):
|
||||
|
@ -279,6 +307,8 @@ class ImageManager(base.Manager):
|
|||
for field in kwargs:
|
||||
if field in UPDATE_PARAMS:
|
||||
fields[field] = kwargs[field]
|
||||
elif field == 'return_req_id':
|
||||
continue
|
||||
else:
|
||||
msg = 'update() got an unexpected keyword argument \'%s\''
|
||||
raise TypeError(msg % field)
|
||||
|
@ -292,4 +322,8 @@ class ImageManager(base.Manager):
|
|||
resp, body_iter = self.api.raw_request(
|
||||
'PUT', url, headers=hdrs, body=image_data)
|
||||
body = json.loads(''.join([c for c in body_iter]))
|
||||
return_request_id = kwargs.get('return_req_id', None)
|
||||
if return_request_id is not None:
|
||||
return_request_id.append(resp.getheader(OS_REQ_ID_HDR, None))
|
||||
|
||||
return Image(self, self._format_image_meta_for_user(body['image']))
|
||||
|
|
|
@ -33,6 +33,7 @@ fixtures = {
|
|||
'POST': (
|
||||
{
|
||||
'location': '/v1/images/1',
|
||||
'x-openstack-request-id': 'req-1234',
|
||||
},
|
||||
json.dumps(
|
||||
{'image': {
|
||||
|
@ -71,7 +72,7 @@ fixtures = {
|
|||
},
|
||||
'/v1/images/detail?is_public=None&limit=20': {
|
||||
'GET': (
|
||||
{},
|
||||
{'x-openstack-request-id': 'req-1234'},
|
||||
{'images': [
|
||||
{
|
||||
'id': 'a',
|
||||
|
@ -358,6 +359,50 @@ fixtures = {
|
|||
'ZZZ',
|
||||
),
|
||||
},
|
||||
'/v1/images/4': {
|
||||
'HEAD': (
|
||||
{
|
||||
'x-image-meta-id': '4',
|
||||
'x-image-meta-name': 'image-4',
|
||||
'x-image-meta-property-arch': 'x86_64',
|
||||
'x-image-meta-is_public': 'false',
|
||||
'x-image-meta-protected': 'false',
|
||||
'x-image-meta-deleted': 'false',
|
||||
'x-openstack-request-id': 'req-1234',
|
||||
},
|
||||
None),
|
||||
'GET': (
|
||||
{
|
||||
'x-openstack-request-id': 'req-1234',
|
||||
},
|
||||
'XXX',
|
||||
),
|
||||
'PUT': (
|
||||
{
|
||||
'x-openstack-request-id': 'req-1234',
|
||||
},
|
||||
json.dumps(
|
||||
{'image': {
|
||||
'id': '4',
|
||||
'name': 'image-4',
|
||||
'container_format': 'ovf',
|
||||
'disk_format': 'vhd',
|
||||
'owner': 'asdf',
|
||||
'size': '1024',
|
||||
'min_ram': '512',
|
||||
'min_disk': '10',
|
||||
'properties': {'a': 'b', 'c': 'd'},
|
||||
'is_public': False,
|
||||
'protected': False,
|
||||
}},
|
||||
),
|
||||
),
|
||||
'DELETE': (
|
||||
{
|
||||
'x-openstack-request-id': 'req-1234',
|
||||
},
|
||||
None),
|
||||
},
|
||||
'/v1/images/v2_created_img': {
|
||||
'PUT': (
|
||||
{},
|
||||
|
@ -480,6 +525,12 @@ class ImageManagerTest(testtools.TestCase):
|
|||
expect = [('HEAD', '/v1/images/3', {}, None)]
|
||||
self.assertEqual(u"ni\xf1o", image.name)
|
||||
|
||||
def test_get_req_id(self):
|
||||
params = {'return_req_id': []}
|
||||
image = self.mgr.get('4', **params)
|
||||
expect_req_id = ['req-1234']
|
||||
self.assertEqual(expect_req_id, params['return_req_id'])
|
||||
|
||||
def test_data(self):
|
||||
data = ''.join([b for b in self.mgr.data('1', do_checksum=False)])
|
||||
expect = [('GET', '/v1/images/1', {}, None)]
|
||||
|
@ -508,6 +559,15 @@ class ImageManagerTest(testtools.TestCase):
|
|||
msg = 'was fd7c5c4fdaa97163ee4ba8842baa537a expected wrong'
|
||||
self.assertTrue(msg in str(e))
|
||||
|
||||
def test_data_req_id(self):
|
||||
params = {
|
||||
'do_checksum': False,
|
||||
'return_req_id': [],
|
||||
}
|
||||
data = ''.join([b for b in self.mgr.data('4', **params)])
|
||||
expect_req_id = ['req-1234']
|
||||
self.assertEqual(expect_req_id, params['return_req_id'])
|
||||
|
||||
def test_data_with_checksum(self):
|
||||
data = ''.join([b for b in self.mgr.data('3', do_checksum=False)])
|
||||
expect = [('GET', '/v1/images/3', {}, None)]
|
||||
|
@ -524,6 +584,16 @@ class ImageManagerTest(testtools.TestCase):
|
|||
expect = [('DELETE', '/v1/images/1', {}, None)]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
|
||||
def test_delete_req_id(self):
|
||||
params = {
|
||||
'return_req_id': []
|
||||
}
|
||||
self.mgr.delete('4', **params)
|
||||
expect = [('DELETE', '/v1/images/4', {}, None)]
|
||||
self.assertEqual(self.api.calls, expect)
|
||||
expect_req_id = ['req-1234']
|
||||
self.assertEqual(expect_req_id, params['return_req_id'])
|
||||
|
||||
def test_create_without_data(self):
|
||||
params = {
|
||||
'id': '1',
|
||||
|
@ -573,6 +643,40 @@ class ImageManagerTest(testtools.TestCase):
|
|||
expect = [('POST', '/v1/images', expect_headers, image_data)]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
|
||||
def test_create_req_id(self):
|
||||
params = {
|
||||
'id': '4',
|
||||
'name': 'image-4',
|
||||
'container_format': 'ovf',
|
||||
'disk_format': 'vhd',
|
||||
'owner': 'asdf',
|
||||
'size': 1024,
|
||||
'min_ram': 512,
|
||||
'min_disk': 10,
|
||||
'copy_from': 'http://example.com',
|
||||
'properties': {'a': 'b', 'c': 'd'},
|
||||
'return_req_id': [],
|
||||
}
|
||||
image = self.mgr.create(**params)
|
||||
expect_headers = {
|
||||
'x-image-meta-id': '4',
|
||||
'x-image-meta-name': 'image-4',
|
||||
'x-image-meta-container_format': 'ovf',
|
||||
'x-image-meta-disk_format': 'vhd',
|
||||
'x-image-meta-owner': 'asdf',
|
||||
'x-image-meta-size': '1024',
|
||||
'x-image-meta-min_ram': '512',
|
||||
'x-image-meta-min_disk': '10',
|
||||
'x-glance-api-copy-from': 'http://example.com',
|
||||
'x-image-meta-property-a': 'b',
|
||||
'x-image-meta-property-c': 'd',
|
||||
}
|
||||
expect = [('POST', '/v1/images', expect_headers, None)]
|
||||
self.assertEqual(self.api.calls, expect)
|
||||
self.assertEqual(image.id, '1')
|
||||
expect_req_id = ['req-1234']
|
||||
self.assertEqual(expect_req_id, params['return_req_id'])
|
||||
|
||||
def test_update(self):
|
||||
fields = {
|
||||
'name': 'image-2',
|
||||
|
@ -621,6 +725,18 @@ class ImageManagerTest(testtools.TestCase):
|
|||
expect = [('PUT', '/v1/images/1', expect_headers, None)]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
|
||||
def test_update_req_id(self):
|
||||
fields = {
|
||||
'purge_props': True,
|
||||
'return_req_id': [],
|
||||
}
|
||||
self.mgr.update('4', **fields)
|
||||
expect_headers = {'x-glance-registry-purge-props': 'true'}
|
||||
expect = [('PUT', '/v1/images/4', expect_headers, None)]
|
||||
self.assertEqual(self.api.calls, expect)
|
||||
expect_req_id = ['req-1234']
|
||||
self.assertEqual(expect_req_id, fields['return_req_id'])
|
||||
|
||||
def test_image_meta_from_headers_encoding(self):
|
||||
fields = {"x-image-meta-name": "ni\xc3\xb1o"}
|
||||
headers = self.mgr._image_meta_from_headers(fields)
|
||||
|
@ -633,6 +749,15 @@ class ImageManagerTest(testtools.TestCase):
|
|||
self.assertEqual('a', image_list[0].id)
|
||||
self.assertEqual(1, len(image_list))
|
||||
|
||||
def test_image_list_with_owner_req_id(self):
|
||||
fields = {
|
||||
'owner': 'A',
|
||||
'return_req_id': [],
|
||||
}
|
||||
images = self.mgr.list(**fields)
|
||||
images.next()
|
||||
self.assertEqual(fields['return_req_id'], ['req-1234'])
|
||||
|
||||
def test_image_list_with_notfound_owner(self):
|
||||
images = self.mgr.list(owner='X', page_size=20)
|
||||
self.assertEqual(0, len(list(images)))
|
||||
|
|
Loading…
Reference in New Issue