prometheanfire    14/03/27 23:08:43

  Modified:             2013.2.2-CVE-2014-0134.patch
  Log:
  better patch
  
  (Portage version: 2.2.8-r1/cvs/Linux x86_64, signed Manifest commit with key 
0x2471eb3e40ac5ac3)

Revision  Changes    Path
1.2                  sys-cluster/nova/files/2013.2.2-CVE-2014-0134.patch

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
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
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

Index: 2013.2.2-CVE-2014-0134.patch
===================================================================
RCS file: 
/var/cvsroot/gentoo-x86/sys-cluster/nova/files/2013.2.2-CVE-2014-0134.patch,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- 2013.2.2-CVE-2014-0134.patch        25 Mar 2014 20:51:33 -0000      1.1
+++ 2013.2.2-CVE-2014-0134.patch        27 Mar 2014 23:08:43 -0000      1.2
@@ -1,6 +1,6 @@
-From e2527e64f77ca0211c744908031cf056cb144f07 Mon Sep 17 00:00:00 2001
+From 25e761acd56d4c820273fc0245ada06c500c1637 Mon Sep 17 00:00:00 2001
 From: David Ripton <[email protected]>
-Date: Mon, 17 Mar 2014 22:18:05 -0400
+Date: Tue, 28 Jan 2014 16:38:51 -0500
 Subject: [PATCH] Persist image format to a file, to prevent attacks based on
  changing it
 
@@ -10,21 +10,48 @@
 
 Now we store the image format to a 'disk.info' file, for Qcow2 and Raw
 images, and only autodetect for images that have never been written to
-that file.  Since glance takes the appropriate security precautions on
-image upload, this should be sufficient and backward-compatible.
+that file.
 
-Manually resolved one conflict in nova/virt/libvirt/imagebackend.py:
-snapshot_delete was removed in icehouse, but is still there in havana
+SecurityImpact
+
+Conflicts:
+       nova/virt/libvirt/imagebackend.py
+
+Manual tweaks to some mocking in test_imagebackend.py
 
 Change-Id: I2016efdb3f49a44ec4d677ac596eacc97871f30a
+Co-authored-by: Nikola Dipanov <[email protected]>
 Closes-bug: #1221190
 ---
- nova/tests/virt/libvirt/test_imagebackend.py | 331 ++++++++++++++++++++++-----
- nova/virt/libvirt/imagebackend.py            |  57 ++++-
- 2 files changed, 324 insertions(+), 64 deletions(-)
+ nova/exception.py                            |   8 +
+ nova/tests/virt/libvirt/test_imagebackend.py | 359 ++++++++++++++++++++++-----
+ nova/tests/virt/libvirt/test_libvirt.py      |   3 +
+ nova/tests/virt/test_virt_drivers.py         |   7 +
+ nova/utils.py                                |  14 ++
+ nova/virt/libvirt/imagebackend.py            |  76 +++++-
+ 6 files changed, 403 insertions(+), 64 deletions(-)
 
+diff --git a/nova/exception.py b/nova/exception.py
+index 7c17803..770a700 100644
+--- a/nova/exception.py
++++ b/nova/exception.py
+@@ -449,6 +449,14 @@ class InvalidDiskFormat(Invalid):
+     msg_fmt = _("Disk format %(disk_format)s is not acceptable")
+ 
+ 
++class InvalidDiskInfo(Invalid):
++    msg_fmt = _("Disk info file is invalid: %(reason)s")
++
++
++class DiskInfoReadWriteFail(Invalid):
++    msg_fmt = _("Failed to read or write disk info file: %(reason)s")
++
++
+ class ImageUnacceptable(Invalid):
+     msg_fmt = _("Image %(image_id)s is unacceptable: %(reason)s")
+ 
 diff --git a/nova/tests/virt/libvirt/test_imagebackend.py 
b/nova/tests/virt/libvirt/test_imagebackend.py
-index 2455ec8..3df22fa 100644
+index 5bfa94d..5424f7b 100644
 --- a/nova/tests/virt/libvirt/test_imagebackend.py
 +++ b/nova/tests/virt/libvirt/test_imagebackend.py
 @@ -16,6 +16,8 @@
@@ -36,7 +63,14 @@
  
  import fixtures
  from oslo.config import cfg
-@@ -31,7 +33,6 @@ CONF = cfg.CONF
+@@ -27,13 +29,13 @@
+ from nova import test
+ from nova.tests import fake_processutils
+ from nova.tests.virt.libvirt import fake_libvirt_utils
++from nova import utils
+ from nova.virt.libvirt import imagebackend
+ 
+ CONF = cfg.CONF
  
  
  class _ImageTestCase(object):
@@ -44,7 +78,7 @@
  
      def mock_create_image(self, image):
          def create_image(fn, base, size, *args, **kwargs):
-@@ -40,10 +41,13 @@ class _ImageTestCase(object):
+@@ -42,10 +44,13 @@ def create_image(fn, base, size, *args, **kwargs):
  
      def setUp(self):
          super(_ImageTestCase, self).setUp()
@@ -58,10 +92,14 @@
          self.NAME = 'fake.vm'
          self.TEMPLATE = 'template'
  
-@@ -61,6 +65,70 @@ class _ImageTestCase(object):
+@@ -63,6 +68,78 @@ def setUp(self):
              'nova.virt.libvirt.imagebackend.libvirt_utils',
              fake_libvirt_utils))
  
++        def fake_chown(path, owner_uid=None):
++            return None
++        self.stubs.Set(utils, 'chown', fake_chown)
++
 +    def tearDown(self):
 +        super(_ImageTestCase, self).tearDown()
 +        shutil.rmtree(self.INSTANCES_PATH)
@@ -118,6 +156,10 @@
 +        super(RawTestCase, self).setUp()
 +        self.stubs.Set(imagebackend.Raw, 'correct_format', lambda _: None)
 +
++        def fake_chown(path, owner_uid=None):
++            return None
++        self.stubs.Set(utils, 'chown', fake_chown)
++
 +    def prepare_mocks(self):
 +        fn = self.mox.CreateMockAnything()
 +        self.mox.StubOutWithMock(imagebackend.utils.synchronized,
@@ -129,7 +171,7 @@
      def test_cache(self):
          self.mox.StubOutWithMock(os.path, 'exists')
          if self.OLD_STYLE_INSTANCE_PATH:
-@@ -128,66 +196,6 @@ class _ImageTestCase(object):
+@@ -130,66 +207,6 @@ def test_cache_template_exists(self):
  
          self.mox.VerifyAll()
  
@@ -196,7 +238,7 @@
      def test_create_image(self):
          fn = self.prepare_mocks()
          fn(target=self.TEMPLATE_PATH, max_size=None, image_id=None)
-@@ -222,16 +230,17 @@ class RawTestCase(_ImageTestCase, test.NoDBTestCase):
+@@ -224,16 +241,21 @@ def test_create_image_extend(self):
          self.mox.VerifyAll()
  
      def test_correct_format(self):
@@ -206,6 +248,10 @@
          self.mox.StubOutWithMock(os.path, 'exists')
          self.mox.StubOutWithMock(imagebackend.images, 'qemu_img_info')
  
++        def fake_chown(path, owner_uid=None):
++            return None
++        self.stubs.Set(utils, 'chown', fake_chown)
++
          os.path.exists(self.PATH).AndReturn(True)
 +        os.path.exists(self.DISK_INFO_PATH).AndReturn(False)
          info = self.mox.CreateMockAnything()
@@ -215,7 +261,7 @@
          self.mox.ReplayAll()
  
          image = self.image_class(self.INSTANCE, self.NAME, path=self.PATH)
-@@ -239,6 +248,11 @@ class RawTestCase(_ImageTestCase, test.NoDBTestCase):
+@@ -241,6 +263,11 @@ def test_correct_format(self):
  
          self.mox.VerifyAll()
  
@@ -227,7 +273,18 @@
  
  class Qcow2TestCase(_ImageTestCase, test.NoDBTestCase):
      SIZE = 1024 * 1024 * 1024
-@@ -259,6 +273,77 @@ class Qcow2TestCase(_ImageTestCase, test.NoDBTestCase):
+@@ -251,6 +278,10 @@ def setUp(self):
+         self.QCOW2_BASE = (self.TEMPLATE_PATH +
+                            '_%d' % (self.SIZE / (1024 * 1024 * 1024)))
+ 
++        def fake_chown(path, owner_uid=None):
++            return None
++        self.stubs.Set(utils, 'chown', fake_chown)
++
+     def prepare_mocks(self):
+         fn = self.mox.CreateMockAnything()
+         self.mox.StubOutWithMock(imagebackend.utils.synchronized,
+@@ -261,6 +292,80 @@ def prepare_mocks(self):
          self.mox.StubOutWithMock(imagebackend.disk, 'extend')
          return fn
  
@@ -240,6 +297,7 @@
 +        os.path.exists(self.TEMPLATE_DIR).AndReturn(False)
 +        os.path.exists(self.INSTANCES_PATH).AndReturn(True)
 +        os.path.exists(self.PATH).AndReturn(False)
++        os.path.exists(self.TEMPLATE_PATH).AndReturn(False)
 +        fn = self.mox.CreateMockAnything()
 +        fn(target=self.TEMPLATE_PATH)
 +        self.mox.ReplayAll()
@@ -274,6 +332,7 @@
 +        os.path.exists(self.INSTANCES_PATH).AndReturn(True)
 +        os.path.exists(self.TEMPLATE_DIR).AndReturn(True)
 +        os.path.exists(self.PATH).AndReturn(False)
++        os.path.exists(self.TEMPLATE_PATH).AndReturn(False)
 +        fn = self.mox.CreateMockAnything()
 +        fn(target=self.TEMPLATE_PATH)
 +        self.mox.ReplayAll()
@@ -292,6 +351,7 @@
 +        os.path.exists(self.INSTANCES_PATH).AndReturn(True)
 +        os.path.exists(self.TEMPLATE_DIR).AndReturn(True)
 +        os.path.exists(self.PATH).AndReturn(False)
++        os.path.exists(self.TEMPLATE_PATH).AndReturn(False)
 +        fn = self.mox.CreateMockAnything()
 +        fn(target=self.TEMPLATE_PATH)
 +        self.mox.ReplayAll()
@@ -305,7 +365,7 @@
      def test_create_image(self):
          fn = self.prepare_mocks()
          fn(max_size=None, target=self.TEMPLATE_PATH)
-@@ -277,6 +362,8 @@ class Qcow2TestCase(_ImageTestCase, test.NoDBTestCase):
+@@ -279,6 +384,8 @@ def test_create_image_with_size(self):
          self.mox.StubOutWithMock(os.path, 'exists')
          if self.OLD_STYLE_INSTANCE_PATH:
              os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False)
@@ -314,7 +374,7 @@
          os.path.exists(self.TEMPLATE_PATH).AndReturn(False)
          os.path.exists(self.PATH).AndReturn(False)
          os.path.exists(self.PATH).AndReturn(False)
-@@ -296,6 +383,8 @@ class Qcow2TestCase(_ImageTestCase, test.NoDBTestCase):
+@@ -298,6 +405,8 @@ def test_create_image_too_small(self):
          self.mox.StubOutWithMock(imagebackend.disk, 'get_disk_size')
          if self.OLD_STYLE_INSTANCE_PATH:
              os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False)
@@ -323,7 +383,7 @@
          os.path.exists(self.TEMPLATE_PATH).AndReturn(True)
          imagebackend.disk.get_disk_size(self.TEMPLATE_PATH
                                         ).AndReturn(self.SIZE)
-@@ -314,6 +403,8 @@ class Qcow2TestCase(_ImageTestCase, test.NoDBTestCase):
+@@ -316,6 +425,8 @@ def test_generate_resized_backing_files(self):
                                   'get_disk_backing_file')
          if self.OLD_STYLE_INSTANCE_PATH:
              os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False)
@@ -332,7 +392,7 @@
          os.path.exists(self.TEMPLATE_PATH).AndReturn(False)
          os.path.exists(self.PATH).AndReturn(True)
  
-@@ -340,6 +431,9 @@ class Qcow2TestCase(_ImageTestCase, test.NoDBTestCase):
+@@ -342,6 +453,9 @@ def test_qcow2_exists_and_has_no_backing_file(self):
                                   'get_disk_backing_file')
          if self.OLD_STYLE_INSTANCE_PATH:
              os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False)
@@ -342,7 +402,7 @@
          os.path.exists(self.TEMPLATE_PATH).AndReturn(False)
          os.path.exists(self.PATH).AndReturn(True)
  
-@@ -353,6 +447,55 @@ class Qcow2TestCase(_ImageTestCase, test.NoDBTestCase):
+@@ -355,6 +469,53 @@ def test_qcow2_exists_and_has_no_backing_file(self):
  
          self.mox.VerifyAll()
  
@@ -369,8 +429,7 @@
 +        image.cache(fake_fetch, self.TEMPLATE_PATH, self.SIZE)
 +
 +        self.assertEqual(fake_processutils.fake_execute_get_log(),
-+            ['chown root:root %s' % self.DISK_INFO_PATH,
-+             'fallocate -n -l 1 %s.fallocate_test' % self.PATH,
++            ['fallocate -n -l 1 %s.fallocate_test' % self.PATH,
 +             'fallocate -n -l %s %s' % (self.SIZE, self.PATH),
 +             'fallocate -n -l %s %s' % (self.SIZE, self.PATH)])
 +
@@ -392,13 +451,12 @@
 +        # Testing fallocate is only called when user has write access.
 +        image.cache(fake_fetch, self.TEMPLATE_PATH, self.SIZE)
 +
-+        self.assertEqual(fake_processutils.fake_execute_get_log(),
-+            ['chown root:root %s' % self.DISK_INFO_PATH])
++        self.assertEqual(fake_processutils.fake_execute_get_log(), [])
 +
  
  class LvmTestCase(_ImageTestCase, test.NoDBTestCase):
      VG = 'FakeVG'
-@@ -429,6 +572,56 @@ class LvmTestCase(_ImageTestCase, test.NoDBTestCase):
+@@ -431,6 +592,58 @@ def _create_image_resize(self, sparse):
  
          self.mox.VerifyAll()
  
@@ -408,6 +466,7 @@
 +            os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False)
 +        os.path.exists(self.TEMPLATE_DIR).AndReturn(False)
 +        os.path.exists(self.PATH).AndReturn(False)
++        os.path.exists(self.TEMPLATE_PATH).AndReturn(False)
 +
 +        fn = self.mox.CreateMockAnything()
 +        fn(target=self.TEMPLATE_PATH)
@@ -441,6 +500,7 @@
 +            os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False)
 +        os.path.exists(self.TEMPLATE_DIR).AndReturn(True)
 +        os.path.exists(self.PATH).AndReturn(False)
++        os.path.exists(self.TEMPLATE_PATH).AndReturn(False)
 +        fn = self.mox.CreateMockAnything()
 +        fn(target=self.TEMPLATE_PATH)
 +        self.mox.StubOutWithMock(imagebackend.fileutils, 'ensure_tree')
@@ -455,13 +515,14 @@
      def test_create_image(self):
          self._create_image(False)
  
-@@ -594,6 +787,20 @@ class RbdTestCase(_ImageTestCase, test.NoDBTestCase):
+@@ -596,6 +809,21 @@ def test_cache_template_exists(self):
  
          self.mox.VerifyAll()
  
 +    def test_cache_base_dir_exists(self):
 +        self.mox.StubOutWithMock(os.path, 'exists')
 +        os.path.exists(self.TEMPLATE_DIR).AndReturn(True)
++        os.path.exists(self.TEMPLATE_PATH).AndReturn(False)
 +        fn = self.mox.CreateMockAnything()
 +        fn(target=self.TEMPLATE_PATH)
 +        self.mox.StubOutWithMock(imagebackend.fileutils, 'ensure_tree')
@@ -476,11 +537,89 @@
      def test_create_image(self):
          fn = self.prepare_mocks()
          fn(max_size=None, rbd=self.rbd, target=self.TEMPLATE_PATH)
+@@ -642,6 +870,13 @@ class BackendTestCase(test.NoDBTestCase):
+                 'uuid': uuidutils.generate_uuid()}
+     NAME = 'fake-name.suffix'
+ 
++    def setUp(self):
++        super(BackendTestCase, self).setUp()
++
++        def fake_chown(path, owner_uid=None):
++            return None
++        self.stubs.Set(utils, 'chown', fake_chown)
++
+     def get_image(self, use_cow, image_type):
+         return imagebackend.Backend(use_cow).image(self.INSTANCE,
+                                                    self.NAME,
+diff --git a/nova/tests/virt/libvirt/test_libvirt.py 
b/nova/tests/virt/libvirt/test_libvirt.py
+index ba842ad..ea8ac13 100644
+--- a/nova/tests/virt/libvirt/test_libvirt.py
++++ b/nova/tests/virt/libvirt/test_libvirt.py
+@@ -390,6 +390,9 @@ def fake_extend(image, size, use_cow=False):
+ 
+         self.stubs.Set(libvirt_driver.disk, 'extend', fake_extend)
+ 
++        self.stubs.Set(imagebackend.Image, 'resolve_driver_format',
++                       imagebackend.Image._get_driver_format)
++
+         class FakeConn():
+             def getCapabilities(self):
+                 """Ensure standard capabilities being returned."""
+diff --git a/nova/tests/virt/test_virt_drivers.py 
b/nova/tests/virt/test_virt_drivers.py
+index 832d9d6..8f1bd23 100644
+--- a/nova/tests/virt/test_virt_drivers.py
++++ b/nova/tests/virt/test_virt_drivers.py
+@@ -30,6 +30,7 @@
+ from nova.tests.virt.libvirt import fake_libvirt_utils
+ from nova.virt import event as virtevent
+ from nova.virt import fake
++from nova.virt.libvirt import imagebackend
+ 
+ LOG = logging.getLogger(__name__)
+ 
+@@ -201,6 +202,12 @@ def setUp(self):
+                                                     fake.FakeVirtAPI())
+         self.ctxt = test_utils.get_test_admin_context()
+         self.image_service = fake_image.FakeImageService()
++        # NOTE(dripton): resolve_driver_format does some file reading and
++        # writing and chowning that complicate testing too much by requiring
++        # using real directories with proper permissions.  Just stub it out
++        # here; we test it in test_imagebackend.py
++        self.stubs.Set(imagebackend.Image, 'resolve_driver_format',
++                       imagebackend.Image._get_driver_format)
+ 
+     def _get_running_instance(self):
+         instance_ref = test_utils.get_test_instance()
+diff --git a/nova/utils.py b/nova/utils.py
+index 599cb64..4757f3a 100755
+--- a/nova/utils.py
++++ b/nova/utils.py
+@@ -924,6 +924,20 @@ def temporary_chown(path, owner_uid=None):
+             execute('chown', orig_uid, path, run_as_root=True)
+ 
+ 
++def chown(path, owner_uid=None):
++    """chown a path.
++
++    :param owner_uid: UID of owner (defaults to current user)
++    """
++    if owner_uid is None:
++        owner_uid = os.getuid()
++
++    orig_uid = os.stat(path).st_uid
++
++    if orig_uid != owner_uid:
++        execute('chown', owner_uid, path, run_as_root=True)
++
++
+ @contextlib.contextmanager
+ def tempdir(**kwargs):
+     argdict = kwargs.copy()
 diff --git a/nova/virt/libvirt/imagebackend.py 
b/nova/virt/libvirt/imagebackend.py
-index e900789..21c7641 100644
+index 51872cf..ed11c90 100644
 --- a/nova/virt/libvirt/imagebackend.py
 +++ b/nova/virt/libvirt/imagebackend.py
-@@ -88,6 +88,11 @@ class Image(object):
+@@ -88,6 +88,11 @@ def __init__(self, source_type, driver_format, 
is_block_dev=False):
          self.is_block_dev = is_block_dev
          self.preallocate = False
  
@@ -492,7 +631,7 @@
          # NOTE(mikal): We need a lock directory which is shared along with
          # instance files, to cover the scenario where multiple compute nodes
          # are trying to create a base file at the same time
-@@ -232,6 +237,46 @@ class Image(object):
+@@ -232,6 +237,65 @@ def snapshot_extract(self, target, out_format):
      def snapshot_delete(self):
          raise NotImplementedError()
  
@@ -508,38 +647,57 @@
 +
 +        See https://bugs.launchpad.net/nova/+bug/1221190
 +        """
++        def _dict_from_line(line):
++            if not line:
++                return {}
++            try:
++                return jsonutils.loads(line)
++            except (TypeError, ValueError) as e:
++                msg = (_("Could not load line %(line)s, got error "
++                        "%(error)s") %
++                        {'line': line, 'error': unicode(e)})
++                raise exception.InvalidDiskInfo(reason=msg)
++
 +        @utils.synchronized(self.disk_info_path, external=False,
 +                            lock_path=self.lock_path)
 +        def write_to_disk_info_file():
-+            with open(self.disk_info_path, "w") as disk_info_file:
-+                disk_info_file.write('%s\n' %
-+                                  jsonutils.dumps((self.path, driver_format)))
-+            # Ensure the file is always owned by root so qemu can't write it.
-+            utils.execute('chown', 'root:root', self.disk_info_path,
-+                          run_as_root=True)
-+
-+        if (self.disk_info_path is not None and
-+                    os.path.exists(self.disk_info_path)):
-+            with open(self.disk_info_path) as disk_info_file:
++            # Use os.open to create it without group or world write 
permission.
++            fd = os.open(self.disk_info_path, os.O_RDWR | os.O_CREAT, 0o644)
++            with os.fdopen(fd, "r+") as disk_info_file:
 +                line = disk_info_file.read().rstrip()
-+                try:
-+                    parts = jsonutils.loads(line)
-+                except (TypeError, ValueError):
-+                    parts = []
-+                if len(parts) == 2:
-+                    (path, driver_format) = parts
-+                    if path == self.path:
-+                        return driver_format
-+        driver_format = self._get_driver_format()
-+        if self.disk_info_path is not None:
-+            fileutils.ensure_tree(os.path.dirname(self.disk_info_path))
-+            write_to_disk_info_file()
++                dct = _dict_from_line(line)
++                if self.path in dct:
++                    msg = _("Attempted overwrite of an existing value.")
++                    raise exception.InvalidDiskInfo(reason=msg)
++                dct.update({self.path: driver_format})
++                disk_info_file.seek(0)
++                disk_info_file.truncate()
++                disk_info_file.write('%s\n' % jsonutils.dumps(dct))
++            # Ensure the file is always owned by the nova user so qemu can't
++            # write it.
++            utils.chown(self.disk_info_path, owner_uid=os.getuid())
++
++        try:
++            if (self.disk_info_path is not None and
++                        os.path.exists(self.disk_info_path)):
++                with open(self.disk_info_path) as disk_info_file:
++                    line = disk_info_file.read().rstrip()
++                    dct = _dict_from_line(line)
++                    for path, driver_format in dct.iteritems():
++                        if path == self.path:
++                            return driver_format
++            driver_format = self._get_driver_format()
++            if self.disk_info_path is not None:
++                fileutils.ensure_tree(os.path.dirname(self.disk_info_path))
++                write_to_disk_info_file()
++        except OSError as e:
++            raise exception.DiskInfoReadWriteFail(reason=unicode(e))
 +        return driver_format
 +
  
  class Raw(Image):
      def __init__(self, instance=None, disk_name=None, path=None,
-@@ -243,12 +288,17 @@ class Raw(Image):
+@@ -243,12 +307,17 @@ def __init__(self, instance=None, disk_name=None, 
path=None,
                                    disk_name))
          self.snapshot_name = snapshot_name
          self.preallocate = CONF.preallocate_images != 'none'
@@ -559,7 +717,7 @@
  
      def create_image(self, prepare_template, base, size, *args, **kwargs):
          @utils.synchronized(base, external=True, lock_path=self.lock_path)
-@@ -291,6 +341,9 @@ class Qcow2(Image):
+@@ -291,6 +360,9 @@ def __init__(self, instance=None, disk_name=None, 
path=None,
                                    disk_name))
          self.snapshot_name = snapshot_name
          self.preallocate = CONF.preallocate_images != 'none'
@@ -570,7 +728,5 @@
      def create_image(self, prepare_template, base, size, *args, **kwargs):
          @utils.synchronized(base, external=True, lock_path=self.lock_path)
 -- 
-1.8.5.3
-
-
+1.8.5.5
 




Reply via email to