~ubuntu-server-dev/cinder/icehouse

« back to all changes in this revision

Viewing changes to debian/patches/fix-properties-extracting-from-image-with-glance-api.patch

  • Committer: Corey Bryant
  • Date: 2016-11-14 13:22:42 UTC
  • Revision ID: corey.bryant@canonical.com-20161114132242-r4azjyadxww3pebz
* Include boot properties from glance v2 images (LP: #1439371):
  - d/p/include-boot-properties-from-glance-v2-images.patch
* Fix extract properties from image with glance api v2 (LP: #1323660):
  - d/p/fix-properties-extracting-from-image-with-glance-api.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
From aa036a66f32ba137895852d9dc59086634483b92 Mon Sep 17 00:00:00 2001
 
2
From: Anton Arefiev <aarefiev@mirantis.com>
 
3
Date: Tue, 31 Mar 2015 19:44:57 +0300
 
4
Subject: [PATCH 2/2] Fix properties extracting from image with glance api v2
 
5
 
 
6
When a volume is created using the glance v1 API, the non based
 
7
properties places in 'properties' dict, and nova is expected
 
8
to find them here. Otherwise api's v2 return custom image properties
 
9
as base properties, so nova can't find them in volume 'image
 
10
properties'.
 
11
 
 
12
This change add new glance call to get image schema, it allows
 
13
extract custom properties from image.
 
14
 
 
15
Closes-Bug: 1323660
 
16
 
 
17
Change-Id: Ib54bb6759b27334294fb2c6d2c0bfe4eae3d0920
 
18
(cherry picked from commit f20643ca44e139e3384b9dea638b54c2235b1169)
 
19
---
 
20
 cinder/image/glance.py            | 59 +++++++++++++++++++++++++++++----------
 
21
 cinder/tests/glance/stubs.py      | 23 +++++++++++----
 
22
 cinder/tests/image/test_glance.py | 21 ++------------
 
23
 3 files changed, 65 insertions(+), 38 deletions(-)
 
24
 
 
25
diff --git a/cinder/image/glance.py b/cinder/image/glance.py
 
26
index 6d79b28..e7a48c1 100644
 
27
--- a/cinder/image/glance.py
 
28
+++ b/cinder/image/glance.py
 
29
@@ -142,9 +142,7 @@ class GlanceClientWrapper(object):
 
30
         If we get a connection error,
 
31
         retry the request according to CONF.glance_num_retries.
 
32
         """
 
33
-        version = self.version
 
34
-        if version in kwargs:
 
35
-            version = kwargs['version']
 
36
+        version = kwargs.pop('version', self.version)
 
37
 
 
38
         retry_excs = (glanceclient.exc.ServiceUnavailable,
 
39
                       glanceclient.exc.InvalidEndpoint,
 
40
@@ -155,7 +153,9 @@ class GlanceClientWrapper(object):
 
41
             client = self.client or self._create_onetime_client(context,
 
42
                                                                 version)
 
43
             try:
 
44
-                return getattr(client.images, method)(*args, **kwargs)
 
45
+                controller = getattr(client,
 
46
+                                     kwargs.pop('controller', 'images'))
 
47
+                return getattr(controller, method)(*args, **kwargs)
 
48
             except retry_excs as e:
 
49
                 netloc = self.netloc
 
50
                 extra = "retrying"
 
51
@@ -184,6 +184,7 @@ class GlanceImageService(object):
 
52
 
 
53
     def __init__(self, client=None):
 
54
         self._client = client or GlanceClientWrapper()
 
55
+        self._image_schema = None
 
56
 
 
57
     def detail(self, context, **kwargs):
 
58
         """Calls out to Glance for a list of detailed image information."""
 
59
@@ -196,7 +197,7 @@ class GlanceImageService(object):
 
60
         _images = []
 
61
         for image in images:
 
62
             if self._is_image_available(context, image):
 
63
-                _images.append(self._translate_from_glance(image))
 
64
+                _images.append(self._translate_from_glance(context, image))
 
65
 
 
66
         return _images
 
67
 
 
68
@@ -225,7 +226,7 @@ class GlanceImageService(object):
 
69
         if not self._is_image_available(context, image):
 
70
             raise exception.ImageNotFound(image_id=image_id)
 
71
 
 
72
-        base_image_meta = self._translate_from_glance(image)
 
73
+        base_image_meta = self._translate_from_glance(context, image)
 
74
         return base_image_meta
 
75
 
 
76
     def get_location(self, context, image_id):
 
77
@@ -285,7 +286,7 @@ class GlanceImageService(object):
 
78
         recv_service_image_meta = self._client.call(context, 'create',
 
79
                                                     **sent_service_image_meta)
 
80
 
 
81
-        return self._translate_from_glance(recv_service_image_meta)
 
82
+        return self._translate_from_glance(context, recv_service_image_meta)
 
83
 
 
84
     def update(self, context, image_id,
 
85
                image_meta, data=None, purge_props=True):
 
86
@@ -310,7 +311,7 @@ class GlanceImageService(object):
 
87
         except Exception:
 
88
             _reraise_translated_image_exception(image_id)
 
89
         else:
 
90
-            return self._translate_from_glance(image_meta)
 
91
+            return self._translate_from_glance(context, image_meta)
 
92
 
 
93
     def delete(self, context, image_id):
 
94
         """Delete the given image.
 
95
@@ -325,6 +326,41 @@ class GlanceImageService(object):
 
96
             raise exception.ImageNotFound(image_id=image_id)
 
97
         return True
 
98
 
 
99
+    def _translate_from_glance(self, context, image):
 
100
+        """Get image metadata from glance image.
 
101
+
 
102
+        Extract metadata from image and convert it's properties
 
103
+        to type cinder expected.
 
104
+
 
105
+        :param image: glance image object
 
106
+        :return: image metadata dictionary
 
107
+        """
 
108
+        if CONF.glance_api_version == 2:
 
109
+            if self._image_schema is None:
 
110
+                self._image_schema = self._client.call(context, 'get',
 
111
+                                                       controller='schemas',
 
112
+                                                       schema_name='image',
 
113
+                                                       version=2)
 
114
+            # NOTE(aarefiev): get base image property, store image 'schema'
 
115
+            #                 is redundant, so ignore it.
 
116
+            image_meta = {key: getattr(image, key)
 
117
+                          for key in image.keys()
 
118
+                          if self._image_schema.is_base_property(key) is True
 
119
+                          and key != 'schema'}
 
120
+
 
121
+            # NOTE(aarefiev): nova is expected that all image properties
 
122
+            # (custom or defined in schema-image.json) stores in
 
123
+            # 'properties' key.
 
124
+            image_meta['properties'] = {
 
125
+                key: getattr(image, key) for key in image.keys()
 
126
+                if self._image_schema.is_base_property(key) is False}
 
127
+        else:
 
128
+            image_meta = _extract_attributes(image)
 
129
+
 
130
+        image_meta = _convert_timestamps_to_datetimes(image_meta)
 
131
+        image_meta = _convert_from_string(image_meta)
 
132
+        return image_meta
 
133
+
 
134
     @staticmethod
 
135
     def _translate_to_glance(image_meta):
 
136
         image_meta = _convert_to_string(image_meta)
 
137
@@ -332,13 +368,6 @@ class GlanceImageService(object):
 
138
         return image_meta
 
139
 
 
140
     @staticmethod
 
141
-    def _translate_from_glance(image):
 
142
-        image_meta = _extract_attributes(image)
 
143
-        image_meta = _convert_timestamps_to_datetimes(image_meta)
 
144
-        image_meta = _convert_from_string(image_meta)
 
145
-        return image_meta
 
146
-
 
147
-    @staticmethod
 
148
     def _is_image_available(context, image):
 
149
         """Check image availability.
 
150
 
 
151
diff --git a/cinder/tests/glance/stubs.py b/cinder/tests/glance/stubs.py
 
152
index 9a1bbdd..7ad45d0 100644
 
153
--- a/cinder/tests/glance/stubs.py
 
154
+++ b/cinder/tests/glance/stubs.py
 
155
@@ -18,6 +18,13 @@ import glanceclient.exc
 
156
 NOW_GLANCE_FORMAT = "2010-10-11T10:30:22"
 
157
 
 
158
 
 
159
+IMAGE_ATTRIBUTES = ['size', 'disk_format', 'owner',
 
160
+                    'container_format', 'checksum', 'id',
 
161
+                    'name', 'created_at', 'updated_at',
 
162
+                    'deleted', 'status',
 
163
+                    'min_disk', 'min_ram', 'is_public']
 
164
+
 
165
+
 
166
 class StubGlanceClient(object):
 
167
 
 
168
     def __init__(self, images=None):
 
169
@@ -88,11 +95,6 @@ class StubGlanceClient(object):
 
170
 
 
171
 class FakeImage(object):
 
172
     def __init__(self, metadata):
 
173
-        IMAGE_ATTRIBUTES = ['size', 'disk_format', 'owner',
 
174
-                            'container_format', 'checksum', 'id',
 
175
-                            'name', 'created_at', 'updated_at',
 
176
-                            'deleted', 'status',
 
177
-                            'min_disk', 'min_ram', 'is_public']
 
178
         raw = dict.fromkeys(IMAGE_ATTRIBUTES)
 
179
         raw.update(metadata)
 
180
         self.__dict__['raw'] = raw
 
181
@@ -108,3 +110,14 @@ class FakeImage(object):
 
182
             self.__dict__['raw'][key] = value
 
183
         except KeyError:
 
184
             raise AttributeError(key)
 
185
+
 
186
+    def keys(self):
 
187
+        return self.__dict__['raw'].keys()
 
188
+
 
189
+
 
190
+class FakeSchema(object):
 
191
+    def is_base_property(self, key):
 
192
+        if key in IMAGE_ATTRIBUTES:
 
193
+            return True
 
194
+        else:
 
195
+            return False
 
196
diff --git a/cinder/tests/image/test_glance.py b/cinder/tests/image/test_glance.py
 
197
index 1333f77..7817b90 100644
 
198
--- a/cinder/tests/image/test_glance.py
 
199
+++ b/cinder/tests/image/test_glance.py
 
200
@@ -590,10 +590,6 @@ class TestGlanceImageService(test.TestCase):
 
201
 
 
202
         config.glance_api_version = 2
 
203
 
 
204
-        attributes = ['size', 'disk_format', 'owner', 'container_format',
 
205
-                      'checksum', 'id', 'name', 'created_at', 'updated_at',
 
206
-                      'deleted', 'status', 'min_disk', 'min_ram', 'is_public']
 
207
-
 
208
         metadata = {
 
209
             'id': 1,
 
210
             'size': 2,
 
211
@@ -603,23 +599,13 @@ class TestGlanceImageService(test.TestCase):
 
212
             'ramdisk_id': 'bar',
 
213
         }
 
214
 
 
215
-        class FakeSchema(object):
 
216
-
 
217
-            def __init__(self, base):
 
218
-                self.base = base
 
219
-
 
220
-            def is_base_property(self, key):
 
221
-                if key in self.base:
 
222
-                    return True
 
223
-                else:
 
224
-                    return False
 
225
-
 
226
         image = glance_stubs.FakeImage(metadata)
 
227
         client = glance_stubs.StubGlanceClient()
 
228
 
 
229
         service = self._create_image_service(client)
 
230
-        service._image_schema = FakeSchema(attributes)
 
231
-        actual = service._translate_from_glance(image)
 
232
+        service._image_schema = glance_stubs.FakeSchema()
 
233
+
 
234
+        actual = service._translate_from_glance('fake_context', image)
 
235
         expected = {
 
236
             'id': 1,
 
237
             'name': None,
 
238
@@ -631,7 +617,6 @@ class TestGlanceImageService(test.TestCase):
 
239
             'container_format': None,
 
240
             'checksum': None,
 
241
             'deleted': None,
 
242
-            'deleted_at': None,
 
243
             'status': None,
 
244
             'properties': {'kernel_id': 'foo',
 
245
                            'ramdisk_id': 'bar'},
 
246
-- 
 
247
2.9.3
 
248