]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
NFS drivers don't honor vm size with volume from an image
authorleseb <sebastien.han@enovance.com>
Thu, 23 May 2013 17:09:06 +0000 (19:09 +0200)
committerleseb <sebastien.han@enovance.com>
Fri, 7 Jun 2013 10:16:47 +0000 (12:16 +0200)
The bug has been encountered with the NFS generic driver
(cinder.volume.nfs.NfsDriver) and the NetApp NFS driver
(cinder.volume.drivers.netapp.nfs.NetAppDirectCmodeNfsDriver). I believe
that drivers based on distributed filesystem such as GlusterFS, nexenta
and scality are also impacted however I didn't test it those backends.
However since most of them already inherit from the RemoteFsDriver
class, this should be fine.

Change-Id: I14575da69a2c99c7cbcece27b40a171153371ee3
Fixes: bug #1183459
cinder/image/image_utils.py
cinder/tests/test_image_utils.py [new file with mode: 0644]
cinder/tests/test_nfs.py
cinder/volume/drivers/nfs.py

index 417f2b90c980535ba2e229c8aa3144a54c6b7a38..f27ccd77b2a69446aa4b9271c4daabffb09fea05 100644 (file)
@@ -191,6 +191,12 @@ def convert_image(source, dest, out_format):
     utils.execute(*cmd, run_as_root=True)
 
 
+def resize_image(source, size):
+    """Changes the virtual size of the image."""
+    cmd = ('qemu-img', 'resize', source, '%sG' % size)
+    utils.execute(*cmd, run_as_root=False)
+
+
 def fetch(context, image_service, image_id, path, _user_id, _project_id):
     # TODO(vish): Improve context handling and add owner and auth data
     #             when it is added to glance.  Right now there is no
diff --git a/cinder/tests/test_image_utils.py b/cinder/tests/test_image_utils.py
new file mode 100644 (file)
index 0000000..f7d19fa
--- /dev/null
@@ -0,0 +1,45 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (c) 2013 eNovance , Inc.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+"""Unit tests for image utils."""
+
+from cinder.image import image_utils
+from cinder import test
+from cinder import utils
+import mox
+
+
+class TestUtils(test.TestCase):
+    def setUp(self):
+        super(TestUtils, self).setUp()
+        self._mox = mox.Mox()
+        self.addCleanup(self._mox.UnsetStubs)
+
+    def test_resize_image(self):
+        mox = self._mox
+        mox.StubOutWithMock(utils, 'execute')
+
+        TEST_IMG_SOURCE = 'boobar.img'
+        TEST_IMG_SIZE_IN_GB = 1
+
+        utils.execute('qemu-img', 'resize', TEST_IMG_SOURCE,
+                      '%sG' % TEST_IMG_SIZE_IN_GB, run_as_root=False)
+
+        mox.ReplayAll()
+
+        image_utils.resize_image(TEST_IMG_SOURCE, TEST_IMG_SIZE_IN_GB)
+
+        mox.VerifyAll()
index 3f967c6f2eb5159300cec23a3569ee087d558644..89173d07175d3e1a06e4b9559ba90d6c43efa7f5 100644 (file)
@@ -33,6 +33,8 @@ from cinder.exception import ProcessExecutionError
 from cinder import test
 from cinder import units
 
+from cinder.image import image_utils
+
 from cinder.volume import configuration as conf
 from cinder.volume.drivers import nfs
 
@@ -167,6 +169,37 @@ class NfsDriverTestCase(test.TestCase):
 
         mox.VerifyAll()
 
+    def test_copy_image_to_volume(self):
+        """resize_image common case usage."""
+        mox = self._mox
+        drv = self._driver
+
+        TEST_IMG_SOURCE = 'foo.img'
+
+        volume = {'size': self.TEST_SIZE_IN_GB, 'name': TEST_IMG_SOURCE}
+
+        def fake_local_path(volume):
+            return volume['name']
+
+        self.stubs.Set(drv, 'local_path', fake_local_path)
+
+        mox.StubOutWithMock(image_utils, 'fetch_to_raw')
+        image_utils.fetch_to_raw(None, None, None, TEST_IMG_SOURCE)
+
+        mox.StubOutWithMock(image_utils, 'resize_image')
+        image_utils.resize_image(TEST_IMG_SOURCE, self.TEST_SIZE_IN_GB)
+
+        mox.StubOutWithMock(image_utils, 'qemu_img_info')
+        data = mox_lib.MockAnything()
+        data.virtual_size = 1024 ** 3
+        image_utils.qemu_img_info(TEST_IMG_SOURCE).AndReturn(data)
+
+        mox.ReplayAll()
+
+        drv.copy_image_to_volume(None, volume, None, None)
+
+        mox.VerifyAll()
+
     def test_mount_nfs_should_suppress_already_mounted_error(self):
         """_mount_nfs should suppress already mounted error if ensure=True
         """
index a162a7d256f10408412815f808052ff5e46c45cf..b92b713528b0a05ae3d98e6c67765a7715a89c0c 100644 (file)
@@ -122,6 +122,23 @@ class RemoteFsDriver(driver.VolumeDriver):
                                  image_id,
                                  self.local_path(volume))
 
+        # NOTE (leseb): Set the virtual size of the image
+        # the raw conversion overwrote the destination file
+        # (which had the correct size)
+        # with the fetched glance image size,
+        # thus the initial 'size' parameter is not honored
+        # this sets the size to the one asked in the first place by the user
+        # and then verify the final virtual size
+        image_utils.resize_image(self.local_path(volume), volume['size'])
+
+        data = image_utils.qemu_img_info(self.local_path(volume))
+        virt_size = data.virtual_size / units.GiB
+        if virt_size != volume['size']:
+            raise exception.ImageUnacceptable(
+                image_id=image_id,
+                reason=(_("Expected volume size was %d") % volume['size'])
+                + (_(" but size is now %d") % virt_size))
+
     def copy_volume_to_image(self, context, volume, image_service, image_meta):
         """Copy the volume to the specified image."""
         image_utils.upload_volume(context,