From 7a16c754fb49615b802e6b8f3d886847c168bd2a Mon Sep 17 00:00:00 2001 From: Matt Riedemann Date: Tue, 26 Jul 2016 18:27:48 -0400 Subject: [PATCH] Default image.size to 0 when extracting v1 image attributes When we snapshot a non-volume-backed instance, we create an image in nova.compute.api.API._create_image and set some values from the instance but 'size' isn't one of them. Later in the virt driver's snapshot method, at least for libvirt, it gets the snapshot image from the image API (glance) and when using glance v1 (use_glance_v1=True) the _extract_attributes method in nova.image.glance pulls the attributes out of the v1 image response to the form that nova expects. This code assumes that the 'size' attribute is set on the image, which for a snapshot image it might not be (yet anyway). This results in an AttributeError. This change defaults the size attribute value to 0 if it's not set. If it is set, but to None, we still use 0 as before. Change-Id: I14b0e44a7268231c2b19f013b563f0b8f09c2e88 Closes-Bug: #1606707 --- nova/image/glance.py | 4 +++- nova/tests/unit/image/test_glance.py | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/nova/image/glance.py b/nova/image/glance.py index 5ff403e4d99c..4f6b94d5ae85 100644 --- a/nova/image/glance.py +++ b/nova/image/glance.py @@ -965,7 +965,9 @@ def _extract_attributes(image, include_locations=False): output[attr] = getattr(image, attr, None) # NOTE(mdorman): 'size' attribute must not be 'None', so use 0 instead elif attr == 'size': - output[attr] = getattr(image, attr) or 0 + # NOTE(mriedem): A snapshot image may not have the size attribute + # set so default to 0. + output[attr] = getattr(image, attr, 0) or 0 else: # NOTE(xarses): Anything that is caught with the default value # will result in an additional lookup to glance for said attr. diff --git a/nova/tests/unit/image/test_glance.py b/nova/tests/unit/image/test_glance.py index 7406a7620bb7..d373d63a413d 100644 --- a/nova/tests/unit/image/test_glance.py +++ b/nova/tests/unit/image/test_glance.py @@ -2412,6 +2412,25 @@ class TestExtractAttributes(test.NoDBTestCase): image_v2, include_locations=False) self.assertEqual(v1_output, v2_output) + @mock.patch.object(schemas, 'Schema', side_effect=FakeSchema) + def test_extract_image_attributes_empty_images_no_size(self, + mocked_schema): + image_v1_dict = dict(image_fixtures['empty_image_v1']) + # pop the size attribute since it might not be set on a snapshot image + image_v1_dict.pop('size') + image_v2 = ImageV2(image_fixtures['empty_image_v2']) + + image_v1 = collections.namedtuple('_', image_v1_dict.keys())( + **image_v1_dict) + + self.flags(use_glance_v1=True, group='glance') + v1_output = glance._translate_from_glance( + image_v1, include_locations=False) + self.flags(use_glance_v1=False, group='glance') + v2_output = glance._translate_from_glance( + image_v2, include_locations=False) + self.assertEqual(v1_output, v2_output) + @mock.patch.object(schemas, 'Schema', side_effect=FakeSchema) def test_extract_image_attributes_active_images_custom_prop( self, mocked_schema):