]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Add support for extend volume in GPFS vol driver
authorBill Owen <billowen@us.ibm.com>
Mon, 18 Nov 2013 22:52:00 +0000 (15:52 -0700)
committerBill Owen <billowen@us.ibm.com>
Fri, 22 Nov 2013 01:02:02 +0000 (18:02 -0700)
Add support for extend volume support to the GPFS volume
driver.

Ensure that requested volume size is implemented for each
of the volume creation paths.

Replace instances where units.GiB could be used but was not.

Implements: blueprint gpfs-extend-volume-support
Change-Id: I79295205f4147fca109f5cb59497a6e1fbe6d296

cinder/tests/test_gpfs.py
cinder/volume/drivers/gpfs.py

index f6909a17ef29beaa7a9930002a38d67ebee5f28c..3dd7eaf1ea33a40d26bc84901d81bf83792f8b9a 100644 (file)
@@ -14,6 +14,7 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
+import mox as mox_lib
 import os
 import tempfile
 
@@ -23,6 +24,7 @@ from cinder import context
 from cinder import db
 from cinder import exception
 from cinder.image import image_utils
+from cinder.openstack.common import imageutils
 from cinder.openstack.common import importutils
 from cinder.openstack.common import log as logging
 from cinder.openstack.common import processutils
@@ -362,6 +364,43 @@ class GPFSDriverTestCase(test.TestCase):
         self.assertEqual(stats['volume_backend_name'], 'GPFS')
         self.assertEqual(stats['storage_protocol'], 'file')
 
+    def test_extend_volume(self):
+        new_vol_size = 15
+        mox = mox_lib.Mox()
+        volume = test_utils.create_volume(self.context, host=CONF.host)
+        volpath = os.path.join(self.volumes_path, volume['name'])
+
+        qemu_img_info_output = """image: %s
+        file format: raw
+        virtual size: %sG (%s bytes)
+        backing file: %s
+        """ % (volume['name'], new_vol_size, new_vol_size * units.GiB, volpath)
+        mox.StubOutWithMock(image_utils, 'resize_image')
+        image_utils.resize_image(volpath, new_vol_size)
+
+        mox.StubOutWithMock(image_utils, 'qemu_img_info')
+        img_info = imageutils.QemuImgInfo(qemu_img_info_output)
+        image_utils.qemu_img_info(volpath).AndReturn(img_info)
+        mox.ReplayAll()
+
+        self.driver.extend_volume(volume, new_vol_size)
+        mox.VerifyAll()
+
+    def test_extend_volume_with_failure(self):
+        new_vol_size = 15
+        mox = mox_lib.Mox()
+        volume = test_utils.create_volume(self.context, host=CONF.host)
+        volpath = os.path.join(self.volumes_path, volume['name'])
+
+        mox.StubOutWithMock(image_utils, 'resize_image')
+        image_utils.resize_image(volpath, new_vol_size).AndRaise(
+            processutils.ProcessExecutionError('error'))
+        mox.ReplayAll()
+
+        self.assertRaises(exception.VolumeBackendAPIException,
+                          self.driver.extend_volume, volume, new_vol_size)
+        mox.VerifyAll()
+
     def test_check_for_setup_error_ok(self):
         self.stubs.Set(GPFSDriver, '_get_gpfs_state',
                        self._fake_gpfs_get_state_active)
@@ -497,6 +536,7 @@ class GPFSDriverTestCase(test.TestCase):
         return data
 
     def _fake_qemu_image_resize(self, path, size):
+        LOG.info('wtf')
         pass
 
     def _fake_delete_gpfs_file(self, fchild):
index f64d67febc327879a145369d68ce5ab244b9d96e..407bd595633d9055cd5fe71f565a3cbf2eb7175c 100644 (file)
@@ -287,15 +287,15 @@ class GPFSDriver(driver.VolumeDriver):
         snapshot_path = self.local_path(snapshot)
         self._create_gpfs_copy(src=snapshot_path, dest=volume_path)
         self._gpfs_redirect(volume_path)
-        data = image_utils.qemu_img_info(volume_path)
-        return {'size': math.ceil(data.virtual_size / 1024.0 ** 3)}
+        virt_size = self._resize_volume_file(volume, volume['size'])
+        return {'size': math.ceil(virt_size / units.GiB)}
 
     def create_cloned_volume(self, volume, src_vref):
         src = self.local_path(src_vref)
         dest = self.local_path(volume)
         self._create_gpfs_clone(src, dest)
-        data = image_utils.qemu_img_info(dest)
-        return {'size': math.ceil(data.virtual_size / 1024.0 ** 3)}
+        virt_size = self._resize_volume_file(volume, volume['size'])
+        return {'size': math.ceil(virt_size / units.GiB)}
 
     def _delete_gpfs_file(self, fchild):
         if not os.path.exists(fchild):
@@ -452,8 +452,8 @@ class GPFSDriver(driver.VolumeDriver):
         data["storage_protocol"] = 'file'
         free, capacity = self._get_available_capacity(self.configuration.
                                                       gpfs_mount_point_base)
-        data['total_capacity_gb'] = math.ceil(capacity / 1024.0 ** 3)
-        data['free_capacity_gb'] = math.ceil(free / 1024.0 ** 3)
+        data['total_capacity_gb'] = math.ceil(capacity / units.GiB)
+        data['free_capacity_gb'] = math.ceil(free / units.GiB)
         data['reserved_percentage'] = 0
         data['QoS_support'] = False
         self._stats = data
@@ -526,7 +526,7 @@ class GPFSDriver(driver.VolumeDriver):
             image_utils.convert_image(image_path, vol_path, 'raw')
             self._execute('chmod', '666', vol_path, run_as_root=True)
 
-        image_utils.resize_image(vol_path, volume['size'])
+        self._resize_volume_file(volume, volume['size'])
 
         return {'provider_location': None}, True
 
@@ -546,7 +546,26 @@ class GPFSDriver(driver.VolumeDriver):
                   volume['id'])
         image_utils.fetch_to_raw(context, image_service, image_id,
                                  self.local_path(volume), size=volume['size'])
-        image_utils.resize_image(self.local_path(volume), volume['size'])
+        self._resize_volume_file(volume, volume['size'])
+
+    def _resize_volume_file(self, volume, new_size):
+        """Resize volume file to new size."""
+        vol_path = self.local_path(volume)
+        try:
+            image_utils.resize_image(vol_path, new_size)
+        except processutils.ProcessExecutionError as exc:
+            LOG.error(_("Failed to resize volume "
+                        "%(volume_id)s, error: %(error)s") %
+                      {'volume_id': volume['id'],
+                       'error': exc.stderr})
+            raise exception.VolumeBackendAPIException(data=exc.stderr)
+
+        data = image_utils.qemu_img_info(vol_path)
+        return data.virtual_size
+
+    def extend_volume(self, volume, new_size):
+        """Extend an existing volume."""
+        self._resize_volume_file(volume, new_size)
 
     def copy_volume_to_image(self, context, volume, image_service, image_meta):
         """Copy the volume to the specified image."""