From edf00659aadaf898ae679f358a6ea8533f4dd891 Mon Sep 17 00:00:00 2001
From: Tomoki Sekiyama <tomoki.sekiyama.qu@hitachi.com>
Date: Fri, 18 Dec 2015 20:38:36 +0900
Subject: [PATCH] Fix volume upload failure with glance_api_version=2

When the volume has additional image properties, upload-to-image
using glance API version 2 will fail with the following error.

  Failed validation u'type' in schema[u'additionalProperties']:
      {u'type': u'string'}

This is due to non core properties passed as a dict to the key
'properties'. It is valid in Image API v1, but the additional
properties must be passed just like core properties in v2.

Change-Id: Ib32c92a8be170b5f43a34e69155398dfc1a8cbcd
Closes-Bug: #1527324
---
 cinder/image/glance.py                        |  9 ++++
 cinder/tests/unit/image/test_glance.py        | 46 +++++++++++++++++++
 .../glance_v2_upload-939c5693bcc25483.yaml    |  3 ++
 3 files changed, 58 insertions(+)
 create mode 100644 releasenotes/notes/glance_v2_upload-939c5693bcc25483.yaml

diff --git a/cinder/image/glance.py b/cinder/image/glance.py
index d0785718f..bb5810fb5 100644
--- a/cinder/image/glance.py
+++ b/cinder/image/glance.py
@@ -412,6 +412,15 @@ class GlanceImageService(object):
     def _translate_to_glance(image_meta):
         image_meta = _convert_to_string(image_meta)
         image_meta = _remove_read_only(image_meta)
+
+        # NOTE(tsekiyama): From the Image API v2, custom properties must
+        # be stored in image_meta directly, instead of the 'properties' key.
+        if CONF.glance_api_version >= 2:
+            properties = image_meta.get('properties')
+            if properties:
+                image_meta.update(properties)
+                del image_meta['properties']
+
         return image_meta
 
     @staticmethod
diff --git a/cinder/tests/unit/image/test_glance.py b/cinder/tests/unit/image/test_glance.py
index c8fcbebbf..f078e6143 100644
--- a/cinder/tests/unit/image/test_glance.py
+++ b/cinder/tests/unit/image/test_glance.py
@@ -665,6 +665,52 @@ class TestGlanceImageService(test.TestCase):
 
         self.assertEqual(expected, actual)
 
+    def test_translate_to_glance(self):
+        self.flags(glance_api_version=1)
+        client = glance_stubs.StubGlanceClient()
+        service = self._create_image_service(client)
+
+        metadata = {
+            'id': 1,
+            'size': 2,
+            'min_disk': 2,
+            'min_ram': 2,
+            'properties': {'kernel_id': 'foo',
+                           'ramdisk_id': 'bar',
+                           'x_billinginfo': '123'},
+        }
+
+        actual = service._translate_to_glance(metadata)
+        expected = metadata
+        self.assertEqual(expected, actual)
+
+    def test_translate_to_glance_v2(self):
+        self.flags(glance_api_version=2)
+        client = glance_stubs.StubGlanceClient()
+        service = self._create_image_service(client)
+
+        metadata = {
+            'id': 1,
+            'size': 2,
+            'min_disk': 2,
+            'min_ram': 2,
+            'properties': {'kernel_id': 'foo',
+                           'ramdisk_id': 'bar',
+                           'x_billinginfo': '123'},
+        }
+
+        actual = service._translate_to_glance(metadata)
+        expected = {
+            'id': 1,
+            'size': 2,
+            'min_disk': 2,
+            'min_ram': 2,
+            'kernel_id': 'foo',
+            'ramdisk_id': 'bar',
+            'x_billinginfo': '123',
+        }
+        self.assertEqual(expected, actual)
+
 
 class TestGlanceClientVersion(test.TestCase):
     """Tests the version of the glance client generated."""
diff --git a/releasenotes/notes/glance_v2_upload-939c5693bcc25483.yaml b/releasenotes/notes/glance_v2_upload-939c5693bcc25483.yaml
new file mode 100644
index 000000000..a737ff365
--- /dev/null
+++ b/releasenotes/notes/glance_v2_upload-939c5693bcc25483.yaml
@@ -0,0 +1,3 @@
+---
+fixes:
+  - upload-to-image using Image API v2 now correctly handles custom image properties.
-- 
2.45.2