From ea109b5f24dca93fd6f660bc436a685d6101bcea Mon Sep 17 00:00:00 2001 From: Jon Bernard Date: Tue, 7 Apr 2015 13:57:36 -0400 Subject: [PATCH] Include boot properties from glance v2 images In order for users to take advantage of COW volumes created from a glance image, Cinder must be configured to use Glance API version 2 (default is 1). In version 2, the required boot metadata (kernel_id and ramdisk_id) are no long stored in the 'properties' dict, but as standalone fields in the GET response from glance. The existing cinder parser for the glance request is not aware of this and the volume created form a v2 image will lack this required metadata. This was causing the recent Ceph CI gate failures for test_volume_boot_pattern. Change-Id: I688898b3841691369d73887f7eabdceb05155db1 Closes-Bug: #1439371 --- cinder/image/glance.py | 11 ++++++ cinder/tests/image/test_glance.py | 57 +++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/cinder/image/glance.py b/cinder/image/glance.py index 5b9c85ed1..9bef05bf7 100644 --- a/cinder/image/glance.py +++ b/cinder/image/glance.py @@ -449,6 +449,17 @@ def _extract_attributes(image): output['properties'] = getattr(image, 'properties', {}) + # NOTE(jbernard): Update image properties for API version 2. For UEC + # images stored in glance, the necessary boot information is stored in the + # properties dict in version 1 so there is nothing more to do. However, in + # version 2 these are standalone fields in the GET response. This bit of + # code moves them back into the properties dict as the caller expects, thus + # producing a volume with correct metadata for booting. + for attr in ('kernel_id', 'ramdisk_id'): + value = getattr(image, attr, None) + if value: + output['properties'][attr] = value + return output diff --git a/cinder/tests/image/test_glance.py b/cinder/tests/image/test_glance.py index f4f9ee150..1fa518ff9 100644 --- a/cinder/tests/image/test_glance.py +++ b/cinder/tests/image/test_glance.py @@ -584,6 +584,63 @@ class TestGlanceImageService(test.TestCase): } self.assertEqual(actual, expected) + @mock.patch('cinder.image.glance.CONF') + def test_extracting_v2_boot_properties(self, config): + + config.glance_api_version = 2 + + attributes = ['size', 'disk_format', 'owner', 'container_format', + 'checksum', 'id', 'name', 'created_at', 'updated_at', + 'deleted', 'status', 'min_disk', 'min_ram', 'is_public'] + + metadata = { + 'id': 1, + 'size': 2, + 'min_disk': 2, + 'min_ram': 2, + 'kernel_id': 'foo', + 'ramdisk_id': 'bar', + } + + class FakeSchema(object): + + def __init__(self, base): + self.base = base + + def is_base_property(self, key): + if key in self.base: + return True + else: + return False + + image = glance_stubs.FakeImage(metadata) + client = glance_stubs.StubGlanceClient() + + service = self._create_image_service(client) + service._image_schema = FakeSchema(attributes) + actual = service._translate_from_glance(image) + expected = { + 'id': 1, + 'name': None, + 'is_public': None, + 'size': 2, + 'min_disk': 2, + 'min_ram': 2, + 'disk_format': None, + 'container_format': None, + 'checksum': None, + 'deleted': None, + 'deleted_at': None, + 'status': None, + 'properties': {'kernel_id': 'foo', + 'ramdisk_id': 'bar'}, + 'owner': None, + 'created_at': None, + 'updated_at': None + } + + self.assertEqual(expected, actual) + class TestGlanceClientVersion(test.TestCase): """Tests the version of the glance client generated.""" -- 2.45.2