From a4fc0c800502338e4530cad910efb64a5483e1ea Mon Sep 17 00:00:00 2001
From: Chet Burgess <cfb@metacloud.com>
Date: Thu, 9 May 2013 09:57:28 +0000
Subject: [PATCH] Check QCOW2 image size during root disk creation

glance can only tell us the size of the file, not the virtual
size of the QCOW2. As such we need to check the virtual size of
the image once its cached and ensure it's <= to the flavor's
root disk size.

Change-Id: I833467284126557eb598b8350a84e10c06292fa9
Fixes: bug 1177830
(cherry picked from commit 44a8aba1d5da87d54db48079103fdef946666d80)
---
 nova/tests/test_imagebackend.py   | 21 +++++++++++++++++++++
 nova/virt/libvirt/imagebackend.py |  8 ++++++++
 2 files changed, 29 insertions(+)

diff --git a/nova/tests/test_imagebackend.py b/nova/tests/test_imagebackend.py
index d571bbf..4ec36da 100644
--- a/nova/tests/test_imagebackend.py
+++ b/nova/tests/test_imagebackend.py
@@ -20,6 +20,7 @@ import os
 import fixtures
 from oslo.config import cfg
 
+from nova import exception
 from nova.openstack.common import uuidutils
 from nova import test
 from nova.tests import fake_libvirt_utils
@@ -253,9 +254,12 @@ class Qcow2TestCase(_ImageTestCase, test.TestCase):
         fn = self.prepare_mocks()
         fn(target=self.TEMPLATE_PATH)
         self.mox.StubOutWithMock(os.path, 'exists')
+        self.mox.StubOutWithMock(imagebackend.disk, 'get_disk_size')
         if self.OLD_STYLE_INSTANCE_PATH:
             os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False)
         os.path.exists(self.TEMPLATE_PATH).AndReturn(False)
+        imagebackend.disk.get_disk_size(self.TEMPLATE_PATH
+                                       ).AndReturn(self.SIZE)
         os.path.exists(self.PATH).AndReturn(False)
         imagebackend.libvirt_utils.create_cow_image(self.TEMPLATE_PATH,
                                                     self.PATH)
@@ -267,6 +271,23 @@ class Qcow2TestCase(_ImageTestCase, test.TestCase):
 
         self.mox.VerifyAll()
 
+    def test_create_image_too_small(self):
+        fn = self.prepare_mocks()
+        fn(target=self.TEMPLATE_PATH)
+        self.mox.StubOutWithMock(os.path, 'exists')
+        self.mox.StubOutWithMock(imagebackend.disk, 'get_disk_size')
+        if self.OLD_STYLE_INSTANCE_PATH:
+            os.path.exists(self.OLD_STYLE_INSTANCE_PATH).AndReturn(False)
+        os.path.exists(self.TEMPLATE_PATH).AndReturn(False)
+        imagebackend.disk.get_disk_size(self.TEMPLATE_PATH
+                                       ).AndReturn(self.SIZE)
+        self.mox.ReplayAll()
+
+        image = self.image_class(self.INSTANCE, self.NAME)
+        self.assertRaises(exception.ImageTooLarge, image.create_image, fn,
+                          self.TEMPLATE_PATH, 1)
+        self.mox.VerifyAll()
+
 
 class LvmTestCase(_ImageTestCase, test.TestCase):
     VG = 'FakeVG'
diff --git a/nova/virt/libvirt/imagebackend.py b/nova/virt/libvirt/imagebackend.py
index b6b1b88..2ca71cc 100755
--- a/nova/virt/libvirt/imagebackend.py
+++ b/nova/virt/libvirt/imagebackend.py
@@ -21,6 +21,7 @@ import os
 
 from oslo.config import cfg
 
+from nova import exception
 from nova.openstack.common import excutils
 from nova.openstack.common import fileutils
 from nova.openstack.common import lockutils
@@ -255,6 +256,13 @@ class Qcow2(Image):
 
         if not os.path.exists(base):
             prepare_template(target=base, *args, **kwargs)
+        # NOTE(cfb): Having a flavor that sets the root size to 0 and having
+        #            nova effectively ignore that size and use the size of the
+        #            image is considered a feature at this time, not a bug.
+        if size and size < disk.get_disk_size(base):
+            LOG.error('%s virtual size larger than flavor root disk size %s' %
+                      (base, size))
+            raise exception.ImageTooLarge()
         if not os.path.exists(self.path):
             with utils.remove_path_on_error(self.path):
                 copy_qcow2_image(base, self.path, size)
-- 
1.8.1.5

