Gentoo Archives: gentoo-commits

From: "Matt Thode (prometheanfire)" <prometheanfire@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] gentoo-x86 commit in sys-cluster/nova/files: 2013.2.2-CVE-2014-0134.patch
Date: Thu, 27 Mar 2014 23:08:49
Message-Id: 20140327230843.635432004F@flycatcher.gentoo.org
1 prometheanfire 14/03/27 23:08:43
2
3 Modified: 2013.2.2-CVE-2014-0134.patch
4 Log:
5 better patch
6
7 (Portage version: 2.2.8-r1/cvs/Linux x86_64, signed Manifest commit with key 0x2471eb3e40ac5ac3)
8
9 Revision Changes Path
10 1.2 sys-cluster/nova/files/2013.2.2-CVE-2014-0134.patch
11
12 file : http://sources.gentoo.org/viewvc.cgi/gentoo-x86/sys-cluster/nova/files/2013.2.2-CVE-2014-0134.patch?rev=1.2&view=markup
13 plain: http://sources.gentoo.org/viewvc.cgi/gentoo-x86/sys-cluster/nova/files/2013.2.2-CVE-2014-0134.patch?rev=1.2&content-type=text/plain
14 diff : http://sources.gentoo.org/viewvc.cgi/gentoo-x86/sys-cluster/nova/files/2013.2.2-CVE-2014-0134.patch?r1=1.1&r2=1.2
15
16 Index: 2013.2.2-CVE-2014-0134.patch
17 ===================================================================
18 RCS file: /var/cvsroot/gentoo-x86/sys-cluster/nova/files/2013.2.2-CVE-2014-0134.patch,v
19 retrieving revision 1.1
20 retrieving revision 1.2
21 diff -u -r1.1 -r1.2
22 --- 2013.2.2-CVE-2014-0134.patch 25 Mar 2014 20:51:33 -0000 1.1
23 +++ 2013.2.2-CVE-2014-0134.patch 27 Mar 2014 23:08:43 -0000 1.2
24 @@ -1,6 +1,6 @@
25 -From e2527e64f77ca0211c744908031cf056cb144f07 Mon Sep 17 00:00:00 2001
26 +From 25e761acd56d4c820273fc0245ada06c500c1637 Mon Sep 17 00:00:00 2001
27 From: David Ripton <dripton@××××××.com>
28 -Date: Mon, 17 Mar 2014 22:18:05 -0400
29 +Date: Tue, 28 Jan 2014 16:38:51 -0500
30 Subject: [PATCH] Persist image format to a file, to prevent attacks based on
31 changing it
32
33 @@ -10,21 +10,48 @@
34
35 Now we store the image format to a 'disk.info' file, for Qcow2 and Raw
36 images, and only autodetect for images that have never been written to
37 -that file. Since glance takes the appropriate security precautions on
38 -image upload, this should be sufficient and backward-compatible.
39 +that file.
40
41 -Manually resolved one conflict in nova/virt/libvirt/imagebackend.py:
42 -snapshot_delete was removed in icehouse, but is still there in havana
43 +SecurityImpact
44 +
45 +Conflicts:
46 + nova/virt/libvirt/imagebackend.py
47 +
48 +Manual tweaks to some mocking in test_imagebackend.py
49
50 Change-Id: I2016efdb3f49a44ec4d677ac596eacc97871f30a
51 +Co-authored-by: Nikola Dipanov <ndipanov@××××××.com>
52 Closes-bug: #1221190
53 ---
54 - nova/tests/virt/libvirt/test_imagebackend.py | 331 ++++++++++++++++++++++-----
55 - nova/virt/libvirt/imagebackend.py | 57 ++++-
56 - 2 files changed, 324 insertions(+), 64 deletions(-)
57 + nova/exception.py | 8 +
58 + nova/tests/virt/libvirt/test_imagebackend.py | 359 ++++++++++++++++++++++-----
59 + nova/tests/virt/libvirt/test_libvirt.py | 3 +
60 + nova/tests/virt/test_virt_drivers.py | 7 +
61 + nova/utils.py | 14 ++
62 + nova/virt/libvirt/imagebackend.py | 76 +++++-
63 + 6 files changed, 403 insertions(+), 64 deletions(-)
64
65 +diff --git a/nova/exception.py b/nova/exception.py
66 +index 7c17803..770a700 100644
67 +--- a/nova/exception.py
68 ++++ b/nova/exception.py
69 +@@ -449,6 +449,14 @@ class InvalidDiskFormat(Invalid):
70 + msg_fmt = _("Disk format %(disk_format)s is not acceptable")
71 +
72 +
73 ++class InvalidDiskInfo(Invalid):
74 ++ msg_fmt = _("Disk info file is invalid: %(reason)s")
75 ++
76 ++
77 ++class DiskInfoReadWriteFail(Invalid):
78 ++ msg_fmt = _("Failed to read or write disk info file: %(reason)s")
79 ++
80 ++
81 + class ImageUnacceptable(Invalid):
82 + msg_fmt = _("Image %(image_id)s is unacceptable: %(reason)s")
83 +
84 diff --git a/nova/tests/virt/libvirt/test_imagebackend.py b/nova/tests/virt/libvirt/test_imagebackend.py
85 -index 2455ec8..3df22fa 100644
86 +index 5bfa94d..5424f7b 100644
87 --- a/nova/tests/virt/libvirt/test_imagebackend.py
88 +++ b/nova/tests/virt/libvirt/test_imagebackend.py
89 @@ -16,6 +16,8 @@
90 @@ -36,7 +63,14 @@
91
92 import fixtures
93 from oslo.config import cfg
94 -@@ -31,7 +33,6 @@ CONF = cfg.CONF
95 +@@ -27,13 +29,13 @@
96 + from nova import test
97 + from nova.tests import fake_processutils
98 + from nova.tests.virt.libvirt import fake_libvirt_utils
99 ++from nova import utils
100 + from nova.virt.libvirt import imagebackend
101 +
102 + CONF = cfg.CONF
103
104
105 class _ImageTestCase(object):
106 @@ -44,7 +78,7 @@
107
108 def mock_create_image(self, image):
109 def create_image(fn, base, size, *args, **kwargs):
110 -@@ -40,10 +41,13 @@ class _ImageTestCase(object):
111 +@@ -42,10 +44,13 @@ def create_image(fn, base, size, *args, **kwargs):
112
113 def setUp(self):
114 super(_ImageTestCase, self).setUp()
115 @@ -58,10 +92,14 @@
116 self.NAME = 'fake.vm'
117 self.TEMPLATE = 'template'
118
119 -@@ -61,6 +65,70 @@ class _ImageTestCase(object):
120 +@@ -63,6 +68,78 @@ def setUp(self):
121 'nova.virt.libvirt.imagebackend.libvirt_utils',
122 fake_libvirt_utils))
123
124 ++ def fake_chown(path, owner_uid=None):
125 ++ return None
126 ++ self.stubs.Set(utils, 'chown', fake_chown)
127 ++
128 + def tearDown(self):
129 + super(_ImageTestCase, self).tearDown()
130 + shutil.rmtree(self.INSTANCES_PATH)
131 @@ -118,6 +156,10 @@
132 + super(RawTestCase, self).setUp()
133 + self.stubs.Set(imagebackend.Raw, 'correct_format', lambda _: None)
134 +
135 ++ def fake_chown(path, owner_uid=None):
136 ++ return None
137 ++ self.stubs.Set(utils, 'chown', fake_chown)
138 ++
139 + def prepare_mocks(self):
140 + fn = self.mox.CreateMockAnything()
141 + self.mox.StubOutWithMock(imagebackend.utils.synchronized,
142 @@ -129,7 +171,7 @@
143 def test_cache(self):
144 self.mox.StubOutWithMock(os.path, 'exists')
145 if self.OLD_STYLE_INSTANCE_PATH:
146 -@@ -128,66 +196,6 @@ class _ImageTestCase(object):
147 +@@ -130,66 +207,6 @@ def test_cache_template_exists(self):
148
149 self.mox.VerifyAll()
150
151 @@ -196,7 +238,7 @@
152 def test_create_image(self):
153 fn = self.prepare_mocks()
154 fn(target=self.TEMPLATE_PATH, max_size=None, image_id=None)
155 -@@ -222,16 +230,17 @@ class RawTestCase(_ImageTestCase, test.NoDBTestCase):
156 +@@ -224,16 +241,21 @@ def test_create_image_extend(self):
157 self.mox.VerifyAll()
158
159 def test_correct_format(self):
160 @@ -206,6 +248,10 @@
161 self.mox.StubOutWithMock(os.path, 'exists')
162 self.mox.StubOutWithMock(imagebackend.images, 'qemu_img_info')
163
164 ++ def fake_chown(path, owner_uid=None):
165 ++ return None
166 ++ self.stubs.Set(utils, 'chown', fake_chown)
167 ++
168 os.path.exists(self.PATH).AndReturn(True)
169 + os.path.exists(self.DISK_INFO_PATH).AndReturn(False)
170 info = self.mox.CreateMockAnything()
171 @@ -215,7 +261,7 @@
172 self.mox.ReplayAll()
173
174 image = self.image_class(self.INSTANCE, self.NAME, path=self.PATH)
175 -@@ -239,6 +248,11 @@ class RawTestCase(_ImageTestCase, test.NoDBTestCase):
176 +@@ -241,6 +263,11 @@ def test_correct_format(self):
177
178 self.mox.VerifyAll()
179
180 @@ -227,7 +273,18 @@
181
182 class Qcow2TestCase(_ImageTestCase, test.NoDBTestCase):
183 SIZE = 1024 * 1024 * 1024
184 -@@ -259,6 +273,77 @@ class Qcow2TestCase(_ImageTestCase, test.NoDBTestCase):
185 +@@ -251,6 +278,10 @@ def setUp(self):
186 + self.QCOW2_BASE = (self.TEMPLATE_PATH +
187 + '_%d' % (self.SIZE / (1024 * 1024 * 1024)))
188 +
189 ++ def fake_chown(path, owner_uid=None):
190 ++ return None
191 ++ self.stubs.Set(utils, 'chown', fake_chown)
192 ++
193 + def prepare_mocks(self):
194 + fn = self.mox.CreateMockAnything()
195 + self.mox.StubOutWithMock(imagebackend.utils.synchronized,
196 +@@ -261,6 +292,80 @@ def prepare_mocks(self):
197 self.mox.StubOutWithMock(imagebackend.disk, 'extend')
198 return fn
199
200 @@ -240,6 +297,7 @@
201 + os.path.exists(self.TEMPLATE_DIR).AndReturn(False)
202 + os.path.exists(self.INSTANCES_PATH).AndReturn(True)
203 + os.path.exists(self.PATH).AndReturn(False)
204 ++ os.path.exists(self.TEMPLATE_PATH).AndReturn(False)
205 + fn = self.mox.CreateMockAnything()
206 + fn(target=self.TEMPLATE_PATH)
207 + self.mox.ReplayAll()
208 @@ -274,6 +332,7 @@
209 + os.path.exists(self.INSTANCES_PATH).AndReturn(True)
210 + os.path.exists(self.TEMPLATE_DIR).AndReturn(True)
211 + os.path.exists(self.PATH).AndReturn(False)
212 ++ os.path.exists(self.TEMPLATE_PATH).AndReturn(False)
213 + fn = self.mox.CreateMockAnything()
214 + fn(target=self.TEMPLATE_PATH)
215 + self.mox.ReplayAll()
216 @@ -292,6 +351,7 @@
217 + os.path.exists(self.INSTANCES_PATH).AndReturn(True)
218 + os.path.exists(self.TEMPLATE_DIR).AndReturn(True)
219 + os.path.exists(self.PATH).AndReturn(False)
220 ++ os.path.exists(self.TEMPLATE_PATH).AndReturn(False)
221 + fn = self.mox.CreateMockAnything()
222 + fn(target=self.TEMPLATE_PATH)
223 + self.mox.ReplayAll()
224 @@ -305,7 +365,7 @@
225 def test_create_image(self):
226 fn = self.prepare_mocks()
227 fn(max_size=None, target=self.TEMPLATE_PATH)
228 -@@ -277,6 +362,8 @@ class Qcow2TestCase(_ImageTestCase, test.NoDBTestCase):
229 +@@ -279,6 +384,8 @@ def test_create_image_with_size(self):
230 self.mox.StubOutWithMock(os.path, 'exists')
231 if self.OLD_STYLE_INSTANCE_PATH:
232 os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False)
233 @@ -314,7 +374,7 @@
234 os.path.exists(self.TEMPLATE_PATH).AndReturn(False)
235 os.path.exists(self.PATH).AndReturn(False)
236 os.path.exists(self.PATH).AndReturn(False)
237 -@@ -296,6 +383,8 @@ class Qcow2TestCase(_ImageTestCase, test.NoDBTestCase):
238 +@@ -298,6 +405,8 @@ def test_create_image_too_small(self):
239 self.mox.StubOutWithMock(imagebackend.disk, 'get_disk_size')
240 if self.OLD_STYLE_INSTANCE_PATH:
241 os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False)
242 @@ -323,7 +383,7 @@
243 os.path.exists(self.TEMPLATE_PATH).AndReturn(True)
244 imagebackend.disk.get_disk_size(self.TEMPLATE_PATH
245 ).AndReturn(self.SIZE)
246 -@@ -314,6 +403,8 @@ class Qcow2TestCase(_ImageTestCase, test.NoDBTestCase):
247 +@@ -316,6 +425,8 @@ def test_generate_resized_backing_files(self):
248 'get_disk_backing_file')
249 if self.OLD_STYLE_INSTANCE_PATH:
250 os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False)
251 @@ -332,7 +392,7 @@
252 os.path.exists(self.TEMPLATE_PATH).AndReturn(False)
253 os.path.exists(self.PATH).AndReturn(True)
254
255 -@@ -340,6 +431,9 @@ class Qcow2TestCase(_ImageTestCase, test.NoDBTestCase):
256 +@@ -342,6 +453,9 @@ def test_qcow2_exists_and_has_no_backing_file(self):
257 'get_disk_backing_file')
258 if self.OLD_STYLE_INSTANCE_PATH:
259 os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False)
260 @@ -342,7 +402,7 @@
261 os.path.exists(self.TEMPLATE_PATH).AndReturn(False)
262 os.path.exists(self.PATH).AndReturn(True)
263
264 -@@ -353,6 +447,55 @@ class Qcow2TestCase(_ImageTestCase, test.NoDBTestCase):
265 +@@ -355,6 +469,53 @@ def test_qcow2_exists_and_has_no_backing_file(self):
266
267 self.mox.VerifyAll()
268
269 @@ -369,8 +429,7 @@
270 + image.cache(fake_fetch, self.TEMPLATE_PATH, self.SIZE)
271 +
272 + self.assertEqual(fake_processutils.fake_execute_get_log(),
273 -+ ['chown root:root %s' % self.DISK_INFO_PATH,
274 -+ 'fallocate -n -l 1 %s.fallocate_test' % self.PATH,
275 ++ ['fallocate -n -l 1 %s.fallocate_test' % self.PATH,
276 + 'fallocate -n -l %s %s' % (self.SIZE, self.PATH),
277 + 'fallocate -n -l %s %s' % (self.SIZE, self.PATH)])
278 +
279 @@ -392,13 +451,12 @@
280 + # Testing fallocate is only called when user has write access.
281 + image.cache(fake_fetch, self.TEMPLATE_PATH, self.SIZE)
282 +
283 -+ self.assertEqual(fake_processutils.fake_execute_get_log(),
284 -+ ['chown root:root %s' % self.DISK_INFO_PATH])
285 ++ self.assertEqual(fake_processutils.fake_execute_get_log(), [])
286 +
287
288 class LvmTestCase(_ImageTestCase, test.NoDBTestCase):
289 VG = 'FakeVG'
290 -@@ -429,6 +572,56 @@ class LvmTestCase(_ImageTestCase, test.NoDBTestCase):
291 +@@ -431,6 +592,58 @@ def _create_image_resize(self, sparse):
292
293 self.mox.VerifyAll()
294
295 @@ -408,6 +466,7 @@
296 + os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False)
297 + os.path.exists(self.TEMPLATE_DIR).AndReturn(False)
298 + os.path.exists(self.PATH).AndReturn(False)
299 ++ os.path.exists(self.TEMPLATE_PATH).AndReturn(False)
300 +
301 + fn = self.mox.CreateMockAnything()
302 + fn(target=self.TEMPLATE_PATH)
303 @@ -441,6 +500,7 @@
304 + os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False)
305 + os.path.exists(self.TEMPLATE_DIR).AndReturn(True)
306 + os.path.exists(self.PATH).AndReturn(False)
307 ++ os.path.exists(self.TEMPLATE_PATH).AndReturn(False)
308 + fn = self.mox.CreateMockAnything()
309 + fn(target=self.TEMPLATE_PATH)
310 + self.mox.StubOutWithMock(imagebackend.fileutils, 'ensure_tree')
311 @@ -455,13 +515,14 @@
312 def test_create_image(self):
313 self._create_image(False)
314
315 -@@ -594,6 +787,20 @@ class RbdTestCase(_ImageTestCase, test.NoDBTestCase):
316 +@@ -596,6 +809,21 @@ def test_cache_template_exists(self):
317
318 self.mox.VerifyAll()
319
320 + def test_cache_base_dir_exists(self):
321 + self.mox.StubOutWithMock(os.path, 'exists')
322 + os.path.exists(self.TEMPLATE_DIR).AndReturn(True)
323 ++ os.path.exists(self.TEMPLATE_PATH).AndReturn(False)
324 + fn = self.mox.CreateMockAnything()
325 + fn(target=self.TEMPLATE_PATH)
326 + self.mox.StubOutWithMock(imagebackend.fileutils, 'ensure_tree')
327 @@ -476,11 +537,89 @@
328 def test_create_image(self):
329 fn = self.prepare_mocks()
330 fn(max_size=None, rbd=self.rbd, target=self.TEMPLATE_PATH)
331 +@@ -642,6 +870,13 @@ class BackendTestCase(test.NoDBTestCase):
332 + 'uuid': uuidutils.generate_uuid()}
333 + NAME = 'fake-name.suffix'
334 +
335 ++ def setUp(self):
336 ++ super(BackendTestCase, self).setUp()
337 ++
338 ++ def fake_chown(path, owner_uid=None):
339 ++ return None
340 ++ self.stubs.Set(utils, 'chown', fake_chown)
341 ++
342 + def get_image(self, use_cow, image_type):
343 + return imagebackend.Backend(use_cow).image(self.INSTANCE,
344 + self.NAME,
345 +diff --git a/nova/tests/virt/libvirt/test_libvirt.py b/nova/tests/virt/libvirt/test_libvirt.py
346 +index ba842ad..ea8ac13 100644
347 +--- a/nova/tests/virt/libvirt/test_libvirt.py
348 ++++ b/nova/tests/virt/libvirt/test_libvirt.py
349 +@@ -390,6 +390,9 @@ def fake_extend(image, size, use_cow=False):
350 +
351 + self.stubs.Set(libvirt_driver.disk, 'extend', fake_extend)
352 +
353 ++ self.stubs.Set(imagebackend.Image, 'resolve_driver_format',
354 ++ imagebackend.Image._get_driver_format)
355 ++
356 + class FakeConn():
357 + def getCapabilities(self):
358 + """Ensure standard capabilities being returned."""
359 +diff --git a/nova/tests/virt/test_virt_drivers.py b/nova/tests/virt/test_virt_drivers.py
360 +index 832d9d6..8f1bd23 100644
361 +--- a/nova/tests/virt/test_virt_drivers.py
362 ++++ b/nova/tests/virt/test_virt_drivers.py
363 +@@ -30,6 +30,7 @@
364 + from nova.tests.virt.libvirt import fake_libvirt_utils
365 + from nova.virt import event as virtevent
366 + from nova.virt import fake
367 ++from nova.virt.libvirt import imagebackend
368 +
369 + LOG = logging.getLogger(__name__)
370 +
371 +@@ -201,6 +202,12 @@ def setUp(self):
372 + fake.FakeVirtAPI())
373 + self.ctxt = test_utils.get_test_admin_context()
374 + self.image_service = fake_image.FakeImageService()
375 ++ # NOTE(dripton): resolve_driver_format does some file reading and
376 ++ # writing and chowning that complicate testing too much by requiring
377 ++ # using real directories with proper permissions. Just stub it out
378 ++ # here; we test it in test_imagebackend.py
379 ++ self.stubs.Set(imagebackend.Image, 'resolve_driver_format',
380 ++ imagebackend.Image._get_driver_format)
381 +
382 + def _get_running_instance(self):
383 + instance_ref = test_utils.get_test_instance()
384 +diff --git a/nova/utils.py b/nova/utils.py
385 +index 599cb64..4757f3a 100755
386 +--- a/nova/utils.py
387 ++++ b/nova/utils.py
388 +@@ -924,6 +924,20 @@ def temporary_chown(path, owner_uid=None):
389 + execute('chown', orig_uid, path, run_as_root=True)
390 +
391 +
392 ++def chown(path, owner_uid=None):
393 ++ """chown a path.
394 ++
395 ++ :param owner_uid: UID of owner (defaults to current user)
396 ++ """
397 ++ if owner_uid is None:
398 ++ owner_uid = os.getuid()
399 ++
400 ++ orig_uid = os.stat(path).st_uid
401 ++
402 ++ if orig_uid != owner_uid:
403 ++ execute('chown', owner_uid, path, run_as_root=True)
404 ++
405 ++
406 + @contextlib.contextmanager
407 + def tempdir(**kwargs):
408 + argdict = kwargs.copy()
409 diff --git a/nova/virt/libvirt/imagebackend.py b/nova/virt/libvirt/imagebackend.py
410 -index e900789..21c7641 100644
411 +index 51872cf..ed11c90 100644
412 --- a/nova/virt/libvirt/imagebackend.py
413 +++ b/nova/virt/libvirt/imagebackend.py
414 -@@ -88,6 +88,11 @@ class Image(object):
415 +@@ -88,6 +88,11 @@ def __init__(self, source_type, driver_format, is_block_dev=False):
416 self.is_block_dev = is_block_dev
417 self.preallocate = False
418
419 @@ -492,7 +631,7 @@
420 # NOTE(mikal): We need a lock directory which is shared along with
421 # instance files, to cover the scenario where multiple compute nodes
422 # are trying to create a base file at the same time
423 -@@ -232,6 +237,46 @@ class Image(object):
424 +@@ -232,6 +237,65 @@ def snapshot_extract(self, target, out_format):
425 def snapshot_delete(self):
426 raise NotImplementedError()
427
428 @@ -508,38 +647,57 @@
429 +
430 + See https://bugs.launchpad.net/nova/+bug/1221190
431 + """
432 ++ def _dict_from_line(line):
433 ++ if not line:
434 ++ return {}
435 ++ try:
436 ++ return jsonutils.loads(line)
437 ++ except (TypeError, ValueError) as e:
438 ++ msg = (_("Could not load line %(line)s, got error "
439 ++ "%(error)s") %
440 ++ {'line': line, 'error': unicode(e)})
441 ++ raise exception.InvalidDiskInfo(reason=msg)
442 ++
443 + @utils.synchronized(self.disk_info_path, external=False,
444 + lock_path=self.lock_path)
445 + def write_to_disk_info_file():
446 -+ with open(self.disk_info_path, "w") as disk_info_file:
447 -+ disk_info_file.write('%s\n' %
448 -+ jsonutils.dumps((self.path, driver_format)))
449 -+ # Ensure the file is always owned by root so qemu can't write it.
450 -+ utils.execute('chown', 'root:root', self.disk_info_path,
451 -+ run_as_root=True)
452 -+
453 -+ if (self.disk_info_path is not None and
454 -+ os.path.exists(self.disk_info_path)):
455 -+ with open(self.disk_info_path) as disk_info_file:
456 ++ # Use os.open to create it without group or world write permission.
457 ++ fd = os.open(self.disk_info_path, os.O_RDWR | os.O_CREAT, 0o644)
458 ++ with os.fdopen(fd, "r+") as disk_info_file:
459 + line = disk_info_file.read().rstrip()
460 -+ try:
461 -+ parts = jsonutils.loads(line)
462 -+ except (TypeError, ValueError):
463 -+ parts = []
464 -+ if len(parts) == 2:
465 -+ (path, driver_format) = parts
466 -+ if path == self.path:
467 -+ return driver_format
468 -+ driver_format = self._get_driver_format()
469 -+ if self.disk_info_path is not None:
470 -+ fileutils.ensure_tree(os.path.dirname(self.disk_info_path))
471 -+ write_to_disk_info_file()
472 ++ dct = _dict_from_line(line)
473 ++ if self.path in dct:
474 ++ msg = _("Attempted overwrite of an existing value.")
475 ++ raise exception.InvalidDiskInfo(reason=msg)
476 ++ dct.update({self.path: driver_format})
477 ++ disk_info_file.seek(0)
478 ++ disk_info_file.truncate()
479 ++ disk_info_file.write('%s\n' % jsonutils.dumps(dct))
480 ++ # Ensure the file is always owned by the nova user so qemu can't
481 ++ # write it.
482 ++ utils.chown(self.disk_info_path, owner_uid=os.getuid())
483 ++
484 ++ try:
485 ++ if (self.disk_info_path is not None and
486 ++ os.path.exists(self.disk_info_path)):
487 ++ with open(self.disk_info_path) as disk_info_file:
488 ++ line = disk_info_file.read().rstrip()
489 ++ dct = _dict_from_line(line)
490 ++ for path, driver_format in dct.iteritems():
491 ++ if path == self.path:
492 ++ return driver_format
493 ++ driver_format = self._get_driver_format()
494 ++ if self.disk_info_path is not None:
495 ++ fileutils.ensure_tree(os.path.dirname(self.disk_info_path))
496 ++ write_to_disk_info_file()
497 ++ except OSError as e:
498 ++ raise exception.DiskInfoReadWriteFail(reason=unicode(e))
499 + return driver_format
500 +
501
502 class Raw(Image):
503 def __init__(self, instance=None, disk_name=None, path=None,
504 -@@ -243,12 +288,17 @@ class Raw(Image):
505 +@@ -243,12 +307,17 @@ def __init__(self, instance=None, disk_name=None, path=None,
506 disk_name))
507 self.snapshot_name = snapshot_name
508 self.preallocate = CONF.preallocate_images != 'none'
509 @@ -559,7 +717,7 @@
510
511 def create_image(self, prepare_template, base, size, *args, **kwargs):
512 @utils.synchronized(base, external=True, lock_path=self.lock_path)
513 -@@ -291,6 +341,9 @@ class Qcow2(Image):
514 +@@ -291,6 +360,9 @@ def __init__(self, instance=None, disk_name=None, path=None,
515 disk_name))
516 self.snapshot_name = snapshot_name
517 self.preallocate = CONF.preallocate_images != 'none'
518 @@ -570,7 +728,5 @@
519 def create_image(self, prepare_template, base, size, *args, **kwargs):
520 @utils.synchronized(base, external=True, lock_path=self.lock_path)
521 --
522 -1.8.5.3
523 -
524 -
525 +1.8.5.5