Only get image location attributes if including locations
Commit 155eeabbfa added 'direct_url' and
'locations' to the list of attributes to get from an image which makes a
call back to glance if the attributes aren't on the image, and can
result in a 404 if they aren't available, which would be in the glance
v1 API case.
This change simply passes the new include_locations parameter down to
_extract_attributes so we can do the proper filtering.
Change-Id: I903fa5c781fed52183b340dc3d9bc4b6598b21ce
Partial-Bug: #1351333
This commit is contained in:
@@ -307,16 +307,14 @@ class GlanceImageService(object):
|
|||||||
if not _is_image_available(context, image):
|
if not _is_image_available(context, image):
|
||||||
raise exception.ImageNotFound(image_id=image_id)
|
raise exception.ImageNotFound(image_id=image_id)
|
||||||
|
|
||||||
image = _translate_from_glance(image)
|
image = _translate_from_glance(image,
|
||||||
|
include_locations=include_locations)
|
||||||
if include_locations:
|
if include_locations:
|
||||||
locations = image.get('locations', None) or []
|
locations = image.get('locations', None) or []
|
||||||
du = image.get('direct_url', None)
|
du = image.get('direct_url', None)
|
||||||
if du:
|
if du:
|
||||||
locations.append({'url': du, 'metadata': {}})
|
locations.append({'url': du, 'metadata': {}})
|
||||||
image['locations'] = locations
|
image['locations'] = locations
|
||||||
else:
|
|
||||||
image.pop('locations', None)
|
|
||||||
image.pop('direct_url', None)
|
|
||||||
|
|
||||||
return image
|
return image
|
||||||
|
|
||||||
@@ -482,8 +480,9 @@ def _translate_to_glance(image_meta):
|
|||||||
return image_meta
|
return image_meta
|
||||||
|
|
||||||
|
|
||||||
def _translate_from_glance(image):
|
def _translate_from_glance(image, include_locations=False):
|
||||||
image_meta = _extract_attributes(image)
|
image_meta = _extract_attributes(image,
|
||||||
|
include_locations=include_locations)
|
||||||
image_meta = _convert_timestamps_to_datetimes(image_meta)
|
image_meta = _convert_timestamps_to_datetimes(image_meta)
|
||||||
image_meta = _convert_from_string(image_meta)
|
image_meta = _convert_from_string(image_meta)
|
||||||
return image_meta
|
return image_meta
|
||||||
@@ -532,7 +531,7 @@ def _convert_to_string(metadata):
|
|||||||
return _convert(_json_dumps, metadata)
|
return _convert(_json_dumps, metadata)
|
||||||
|
|
||||||
|
|
||||||
def _extract_attributes(image):
|
def _extract_attributes(image, include_locations=False):
|
||||||
# NOTE(hdd): If a key is not found, base.Resource.__getattr__() may perform
|
# NOTE(hdd): If a key is not found, base.Resource.__getattr__() may perform
|
||||||
# a get(), resulting in a useless request back to glance. This list is
|
# a get(), resulting in a useless request back to glance. This list is
|
||||||
# therefore sorted, with dependent attributes as the end
|
# therefore sorted, with dependent attributes as the end
|
||||||
@@ -547,6 +546,7 @@ def _extract_attributes(image):
|
|||||||
|
|
||||||
queued = getattr(image, 'status') == 'queued'
|
queued = getattr(image, 'status') == 'queued'
|
||||||
queued_exclude_attrs = ['disk_format', 'container_format']
|
queued_exclude_attrs = ['disk_format', 'container_format']
|
||||||
|
include_locations_attrs = ['direct_url', 'locations']
|
||||||
output = {}
|
output = {}
|
||||||
|
|
||||||
for attr in IMAGE_ATTRIBUTES:
|
for attr in IMAGE_ATTRIBUTES:
|
||||||
@@ -560,6 +560,10 @@ def _extract_attributes(image):
|
|||||||
# NOTE(liusheng): queued image may not have these attributes and 'name'
|
# NOTE(liusheng): queued image may not have these attributes and 'name'
|
||||||
elif queued and attr in queued_exclude_attrs:
|
elif queued and attr in queued_exclude_attrs:
|
||||||
output[attr] = getattr(image, attr, None)
|
output[attr] = getattr(image, attr, None)
|
||||||
|
# NOTE(mriedem): Only get location attrs if including locations.
|
||||||
|
elif attr in include_locations_attrs:
|
||||||
|
if include_locations:
|
||||||
|
output[attr] = getattr(image, attr, None)
|
||||||
else:
|
else:
|
||||||
# NOTE(xarses): Anything that is caught with the default value
|
# NOTE(xarses): Anything that is caught with the default value
|
||||||
# will result in a additional lookup to glance for said attr.
|
# will result in a additional lookup to glance for said attr.
|
||||||
|
|||||||
@@ -454,7 +454,7 @@ class TestGlanceImageService(test.NoDBTestCase):
|
|||||||
self.assertEqual(same_id, image_id)
|
self.assertEqual(same_id, image_id)
|
||||||
self.assertEqual(service._client.host, 'something-less-likely')
|
self.assertEqual(service._client.host, 'something-less-likely')
|
||||||
|
|
||||||
def test_extracting_missing_attributes(self):
|
def _test_extracting_missing_attributes(self, include_locations):
|
||||||
"""Verify behavior from glance objects that are missing attributes
|
"""Verify behavior from glance objects that are missing attributes
|
||||||
|
|
||||||
This fakes the image class and is missing attribute as the client can
|
This fakes the image class and is missing attribute as the client can
|
||||||
@@ -475,7 +475,8 @@ class TestGlanceImageService(test.NoDBTestCase):
|
|||||||
'updated_at': self.NOW_DATETIME,
|
'updated_at': self.NOW_DATETIME,
|
||||||
}
|
}
|
||||||
image = MyFakeGlanceImage(metadata)
|
image = MyFakeGlanceImage(metadata)
|
||||||
observed = glance._extract_attributes(image)
|
observed = glance._extract_attributes(
|
||||||
|
image, include_locations=include_locations)
|
||||||
expected = {
|
expected = {
|
||||||
'id': 1,
|
'id': 1,
|
||||||
'name': None,
|
'name': None,
|
||||||
@@ -492,12 +493,19 @@ class TestGlanceImageService(test.NoDBTestCase):
|
|||||||
'deleted': None,
|
'deleted': None,
|
||||||
'status': None,
|
'status': None,
|
||||||
'properties': {},
|
'properties': {},
|
||||||
'owner': None,
|
'owner': None
|
||||||
'locations': None,
|
|
||||||
'direct_url': None
|
|
||||||
}
|
}
|
||||||
|
if include_locations:
|
||||||
|
expected['locations'] = None
|
||||||
|
expected['direct_url'] = None
|
||||||
self.assertEqual(expected, observed)
|
self.assertEqual(expected, observed)
|
||||||
|
|
||||||
|
def test_extracting_missing_attributes_include_locations(self):
|
||||||
|
self._test_extracting_missing_attributes(include_locations=True)
|
||||||
|
|
||||||
|
def test_extracting_missing_attributes_exclude_locations(self):
|
||||||
|
self._test_extracting_missing_attributes(include_locations=False)
|
||||||
|
|
||||||
|
|
||||||
def _create_failing_glance_client(info):
|
def _create_failing_glance_client(info):
|
||||||
class MyGlanceStubClient(glance_stubs.StubGlanceClient):
|
class MyGlanceStubClient(glance_stubs.StubGlanceClient):
|
||||||
@@ -652,7 +660,7 @@ class TestShow(test.NoDBTestCase):
|
|||||||
client.call.assert_called_once_with(ctx, 1, 'get',
|
client.call.assert_called_once_with(ctx, 1, 'get',
|
||||||
mock.sentinel.image_id)
|
mock.sentinel.image_id)
|
||||||
is_avail_mock.assert_called_once_with(ctx, {})
|
is_avail_mock.assert_called_once_with(ctx, {})
|
||||||
trans_from_mock.assert_called_once_with({})
|
trans_from_mock.assert_called_once_with({}, include_locations=False)
|
||||||
self.assertIn('mock', info)
|
self.assertIn('mock', info)
|
||||||
self.assertEqual(mock.sentinel.trans_from, info['mock'])
|
self.assertEqual(mock.sentinel.trans_from, info['mock'])
|
||||||
|
|
||||||
@@ -743,7 +751,8 @@ class TestShow(test.NoDBTestCase):
|
|||||||
|
|
||||||
client.call.assert_called_once_with(ctx, 2, 'get', image_id)
|
client.call.assert_called_once_with(ctx, 2, 'get', image_id)
|
||||||
avail_mock.assert_called_once_with(ctx, mock.sentinel.image)
|
avail_mock.assert_called_once_with(ctx, mock.sentinel.image)
|
||||||
trans_from_mock.assert_called_once_with(mock.sentinel.image)
|
trans_from_mock.assert_called_once_with(mock.sentinel.image,
|
||||||
|
include_locations=True)
|
||||||
self.assertIn('locations', info)
|
self.assertIn('locations', info)
|
||||||
self.assertEqual(locations, info['locations'])
|
self.assertEqual(locations, info['locations'])
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user