diff -Nru cinder-2015.1.4/debian/changelog cinder-2015.1.4/debian/changelog --- cinder-2015.1.4/debian/changelog 2016-05-11 23:49:42.000000000 +0900 +++ cinder-2015.1.4/debian/changelog 2016-12-03 02:07:55.000000000 +0900 @@ -1,3 +1,10 @@ +cinder (1:2015.1.4-0ubuntu1~cloud0) trusty-kilo; urgency=medium + + * Fix extract properties from image with glance api v2 (LP: #1323660): + - d/p/0001-Fix-properties-extracting-from-image-with-glance-api.patch + + -- Seyeong Kim Sat, 03 Dec 2016 02:07:55 +0900 + cinder (1:2015.1.4-0ubuntu1) trusty-kilo; urgency=medium * New upstream stable release (LP: #1580334). diff -Nru cinder-2015.1.4/debian/patches/0001-Fix-properties-extracting-from-image-with-glance-api.patch cinder-2015.1.4/debian/patches/0001-Fix-properties-extracting-from-image-with-glance-api.patch --- cinder-2015.1.4/debian/patches/0001-Fix-properties-extracting-from-image-with-glance-api.patch 1970-01-01 09:00:00.000000000 +0900 +++ cinder-2015.1.4/debian/patches/0001-Fix-properties-extracting-from-image-with-glance-api.patch 2016-12-03 02:07:53.000000000 +0900 @@ -0,0 +1,247 @@ +From ac5b263dca3e481e6ccb32b6d2a3ca2f9eb83a6c Mon Sep 17 00:00:00 2001 +From: Seyeong Kim +Date: Fri, 2 Dec 2016 17:03:56 +0000 +Subject: [PATCH] Fix properties extracting from image with glance api v2 + +When a volume is created using the glance v1 API, the non based +properties places in 'properties' dict, and nova is expected +to find them here. Otherwise api's v2 return custom image properties +as base properties, so nova can't find them in volume 'image +properties'. + +This change add new glance call to get image schema, it allows +extract custom properties from image. + +Closes-Bug: 1323660 + +Change-Id: Ib54bb6759b27334294fb2c6d2c0bfe4eae3d0920 + +Conflicts: + cinder/image/glance.py +--- + cinder/image/glance.py | 59 +++++++++++++++++++++++++++++---------- + cinder/tests/glance/stubs.py | 23 +++++++++++---- + cinder/tests/image/test_glance.py | 21 ++------------ + 3 files changed, 65 insertions(+), 38 deletions(-) + +Index: cinder-2015.1.4/cinder/image/glance.py +=================================================================== +--- cinder-2015.1.4.orig/cinder/image/glance.py ++++ cinder-2015.1.4/cinder/image/glance.py +@@ -160,9 +160,7 @@ class GlanceClientWrapper(object): + If we get a connection error, + retry the request according to CONF.glance_num_retries. + """ +- version = self.version +- if version in kwargs: +- version = kwargs['version'] ++ version = kwargs.pop('version', self.version) + + retry_excs = (glanceclient.exc.ServiceUnavailable, + glanceclient.exc.InvalidEndpoint, +@@ -173,7 +171,9 @@ class GlanceClientWrapper(object): + client = self.client or self._create_onetime_client(context, + version) + try: +- return getattr(client.images, method)(*args, **kwargs) ++ controller = getattr(client, ++ kwargs.pop('controller', 'images')) ++ return getattr(controller, method)(*args, **kwargs) + except retry_excs as e: + netloc = self.netloc + extra = "retrying" +@@ -198,6 +198,7 @@ class GlanceImageService(object): + + def __init__(self, client=None): + self._client = client or GlanceClientWrapper() ++ self._image_schema = None + + def detail(self, context, **kwargs): + """Calls out to Glance for a list of detailed image information.""" +@@ -210,7 +211,7 @@ class GlanceImageService(object): + _images = [] + for image in images: + if self._is_image_available(context, image): +- _images.append(self._translate_from_glance(image)) ++ _images.append(self._translate_from_glance(context, image)) + + return _images + +@@ -239,7 +240,7 @@ class GlanceImageService(object): + if not self._is_image_available(context, image): + raise exception.ImageNotFound(image_id=image_id) + +- base_image_meta = self._translate_from_glance(image) ++ base_image_meta = self._translate_from_glance(context, image) + return base_image_meta + + def get_location(self, context, image_id): +@@ -304,7 +305,7 @@ class GlanceImageService(object): + recv_service_image_meta = self._client.call(context, 'create', + **sent_service_image_meta) + +- return self._translate_from_glance(recv_service_image_meta) ++ return self._translate_from_glance(context, recv_service_image_meta) + + def update(self, context, image_id, + image_meta, data=None, purge_props=True): +@@ -329,7 +330,7 @@ class GlanceImageService(object): + except Exception: + _reraise_translated_image_exception(image_id) + else: +- return self._translate_from_glance(image_meta) ++ return self._translate_from_glance(context, image_meta) + + def delete(self, context, image_id): + """Delete the given image. +@@ -344,6 +345,41 @@ class GlanceImageService(object): + raise exception.ImageNotFound(image_id=image_id) + return True + ++ def _translate_from_glance(self, context, image): ++ """Get image metadata from glance image. ++ ++ Extract metadata from image and convert it's properties ++ to type cinder expected. ++ ++ :param image: glance image object ++ :return: image metadata dictionary ++ """ ++ if CONF.glance_api_version == 2: ++ if self._image_schema is None: ++ self._image_schema = self._client.call(context, 'get', ++ controller='schemas', ++ schema_name='image', ++ version=2) ++ # NOTE(aarefiev): get base image property, store image 'schema' ++ # is redundant, so ignore it. ++ image_meta = {key: getattr(image, key) ++ for key in image.keys() ++ if self._image_schema.is_base_property(key) is True ++ and key != 'schema'} ++ ++ # NOTE(aarefiev): nova is expected that all image properties ++ # (custom or defined in schema-image.json) stores in ++ # 'properties' key. ++ image_meta['properties'] = { ++ key: getattr(image, key) for key in image.keys() ++ if self._image_schema.is_base_property(key) is False} ++ else: ++ image_meta = _extract_attributes(image) ++ ++ image_meta = _convert_timestamps_to_datetimes(image_meta) ++ image_meta = _convert_from_string(image_meta) ++ return image_meta ++ + @staticmethod + def _translate_to_glance(image_meta): + image_meta = _convert_to_string(image_meta) +@@ -351,13 +387,6 @@ class GlanceImageService(object): + return image_meta + + @staticmethod +- def _translate_from_glance(image): +- image_meta = _extract_attributes(image) +- image_meta = _convert_timestamps_to_datetimes(image_meta) +- image_meta = _convert_from_string(image_meta) +- return image_meta +- +- @staticmethod + def _is_image_available(context, image): + """Check image availability. + +Index: cinder-2015.1.4/cinder/tests/glance/stubs.py +=================================================================== +--- cinder-2015.1.4.orig/cinder/tests/glance/stubs.py ++++ cinder-2015.1.4/cinder/tests/glance/stubs.py +@@ -18,6 +18,13 @@ import glanceclient.exc + NOW_GLANCE_FORMAT = "2010-10-11T10:30:22" + + ++IMAGE_ATTRIBUTES = ['size', 'disk_format', 'owner', ++ 'container_format', 'checksum', 'id', ++ 'name', 'created_at', 'updated_at', ++ 'deleted', 'status', ++ 'min_disk', 'min_ram', 'is_public'] ++ ++ + class StubGlanceClient(object): + + def __init__(self, images=None): +@@ -88,11 +95,6 @@ class StubGlanceClient(object): + + class FakeImage(object): + def __init__(self, metadata): +- IMAGE_ATTRIBUTES = ['size', 'disk_format', 'owner', +- 'container_format', 'checksum', 'id', +- 'name', 'created_at', 'updated_at', +- 'deleted', 'status', +- 'min_disk', 'min_ram', 'is_public'] + raw = dict.fromkeys(IMAGE_ATTRIBUTES) + raw.update(metadata) + self.__dict__['raw'] = raw +@@ -108,3 +110,14 @@ class FakeImage(object): + self.__dict__['raw'][key] = value + except KeyError: + raise AttributeError(key) ++ ++ def keys(self): ++ return self.__dict__['raw'].keys() ++ ++ ++class FakeSchema(object): ++ def is_base_property(self, key): ++ if key in IMAGE_ATTRIBUTES: ++ return True ++ else: ++ return False +Index: cinder-2015.1.4/cinder/tests/image/test_glance.py +=================================================================== +--- cinder-2015.1.4.orig/cinder/tests/image/test_glance.py ++++ cinder-2015.1.4/cinder/tests/image/test_glance.py +@@ -614,10 +614,6 @@ class TestGlanceImageService(test.TestCa + + 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, +@@ -627,23 +623,13 @@ class TestGlanceImageService(test.TestCa + '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) ++ service._image_schema = glance_stubs.FakeSchema() ++ ++ actual = service._translate_from_glance('fake_context', image) + expected = { + 'id': 1, + 'name': None, +@@ -655,7 +641,6 @@ class TestGlanceImageService(test.TestCa + 'container_format': None, + 'checksum': None, + 'deleted': None, +- 'deleted_at': None, + 'status': None, + 'properties': {'kernel_id': 'foo', + 'ramdisk_id': 'bar'}, diff -Nru cinder-2015.1.4/debian/patches/series cinder-2015.1.4/debian/patches/series --- cinder-2015.1.4/debian/patches/series 2016-05-11 05:29:25.000000000 +0900 +++ cinder-2015.1.4/debian/patches/series 2016-12-03 02:07:49.000000000 +0900 @@ -2,3 +2,4 @@ fix-requirements.patch fix-long-casting.patch fix-assert-raises-regex-tests.patch +0001-Fix-properties-extracting-from-image-with-glance-api.patch