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:
Matt Riedemann
2014-08-01 08:09:07 -07:00
parent 3619c1914e
commit ed2aa220aa
2 changed files with 27 additions and 14 deletions

View File

@@ -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.

View File

@@ -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'])