]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
GlusterFS: Support over subscription in thin provisioning
authorBharat Kumar Kobagana <bharat.kobagana@redhat.com>
Wed, 11 Mar 2015 12:06:04 +0000 (17:36 +0530)
committerBharat Kumar Kobagana <bharat.kobagana@redhat.com>
Mon, 27 Apr 2015 11:04:23 +0000 (16:34 +0530)
This patch adds "over subscription in thin provisioning" support to
GlusterFS driver.

The following changes are proposed:
* GlusterFS driver reports the following new capacities and ratios:
  * provisioned_capacity
  * max_over_subscription_ratio
  * thin_provisioning_support (True or False)
  * thick_provisioning_support (True or False)

Co-Authored-By: Deepak C Shetty <deepakcs@redhat.com>
Implements: blueprint glusterfs-over-subscription-thin-provisioning
Change-Id: I7fbbe989c865dce42102b63f7d52a8edb63e7a9e

cinder/tests/unit/test_glusterfs.py
cinder/volume/drivers/glusterfs.py
cinder/volume/drivers/remotefs.py

index b85da12501bf3cf53ed59882771e7dbd5d31c3ee..113b6ab06cd259f0a156641ab2025e683de51b01 100644 (file)
@@ -37,6 +37,7 @@ from cinder import test
 from cinder import utils
 from cinder.volume import driver as base_driver
 from cinder.volume.drivers import glusterfs
+from cinder.volume.drivers import remotefs as remotefs_drv
 
 
 CONF = cfg.CONF
@@ -256,6 +257,93 @@ class GlusterFsDriverTestCase(test.TestCase):
             result = drv._get_available_capacity(self.TEST_EXPORT1)
             self.assertEqual((df_avail, df_total_size), result)
 
+    def test_get_provisioned_capacity(self):
+        """_get_provisioned_size should calculate correct value."""
+        drv = self._driver
+
+        drv.shares = {'127.7.7.7:/gluster1': None}
+        with mock.patch.object(drv, '_get_mount_point_for_share') as \
+                mock_get_mount_point_for_share,\
+                mock.patch.object(drv, '_execute') as mock_execute:
+            mock_get_mount_point_for_share.\
+                return_value = self.TEST_MNT_POINT
+            mock_execute.return_value = ("3221225472 /mount/point", '')
+            provisioned_capacity = drv._get_provisioned_capacity()
+
+            self.assertEqual(3.0, provisioned_capacity)
+
+    def test_update_volume_stats_sparse(self):
+        """_update_volume_stats_sparse with sparse files."""
+        drv = self._driver
+        rfsdriver = remotefs_drv.RemoteFSSnapDriver
+
+        with mock.patch.object(rfsdriver, '_update_volume_stats') as \
+                mock_update_volume_stats,\
+                mock.patch.object(drv, '_get_provisioned_capacity') as \
+                mock_get_provisioned_capacity:
+            data = {'total_capacity_gb': 10.0,
+                    'free_capacity_gb': 2.0}
+            drv._stats = data
+            drv.configuration.glusterfs_sparsed_volumes = True
+            drv.configuration.glusterfs_qcow2_volumes = False
+            drv.configuration.max_over_subscription_ratio = 20.0
+            mock_get_provisioned_capacity.return_value = 8.0
+            drv._update_volume_stats()
+            data['max_over_subscription_ratio'] = 20.0
+            data['thick_provisioning_support'] = False
+            data['thin_provisioning_support'] = True
+
+            self.assertEqual(data, drv._stats)
+            self.assertTrue(mock_get_provisioned_capacity.called)
+            self.assertTrue(mock_update_volume_stats.called)
+
+    def test_update_volume_stats_qcow2(self):
+        """_update_volume_stats_sparse with qcow2 files."""
+        drv = self._driver
+        rfsdriver = remotefs_drv.RemoteFSSnapDriver
+
+        with mock.patch.object(rfsdriver, '_update_volume_stats') as \
+                mock_update_volume_stats,\
+                mock.patch.object(drv, '_get_provisioned_capacity') as \
+                mock_get_provisioned_capacity:
+            data = {'total_capacity_gb': 10.0,
+                    'free_capacity_gb': 2.0}
+            drv._stats = data
+            drv.configuration.glusterfs_sparsed_volumes = False
+            drv.configuration.glusterfs_qcow2_volumes = True
+            drv.configuration.max_over_subscription_ratio = 20.0
+            mock_get_provisioned_capacity.return_value = 8.0
+            drv._update_volume_stats()
+            data['max_over_subscription_ratio'] = 20.0
+            data['thick_provisioning_support'] = False
+            data['thin_provisioning_support'] = True
+
+            self.assertEqual(data, drv._stats)
+            self.assertTrue(mock_get_provisioned_capacity.called)
+            self.assertTrue(mock_update_volume_stats.called)
+
+    def test_update_volume_stats_thick(self):
+        """_update_volume_stats_sparse with raw files."""
+        drv = self._driver
+        rfsdriver = remotefs_drv.RemoteFSSnapDriver
+
+        with mock.patch.object(rfsdriver, '_update_volume_stats') as \
+                mock_update_volume_stats:
+            data = {'total_capacity_gb': 10.0,
+                    'free_capacity_gb': 2.0}
+            drv._stats = data
+            drv.configuration.glusterfs_sparsed_volumes = False
+            drv.configuration.glusterfs_qcow2_volumes = False
+            drv.configuration.max_over_subscription_ratio = 20.0
+            drv._update_volume_stats()
+            data['provisioned_capacity_gb'] = 8.0
+            data['max_over_subscription_ratio'] = 20.0
+            data['thick_provisioning_support'] = True
+            data['thin_provisioning_support'] = False
+
+            self.assertEqual(data, drv._stats)
+            self.assertTrue(mock_update_volume_stats.called)
+
     def test_load_shares_config(self):
         drv = self._driver
 
index 325c7d2214506e3ad666785dd77efd612e03d4b9..7ef40abce04cd375d54613fca69943fcad825f72 100644 (file)
@@ -160,6 +160,29 @@ class GlusterfsDriver(remotefs_drv.RemoteFSSnapDriver):
                           hashed)
         return path
 
+    def _update_volume_stats(self):
+        """Retrieve stats info from volume group."""
+        super(GlusterfsDriver, self)._update_volume_stats()
+        data = self._stats
+
+        global_capacity = data['total_capacity_gb']
+        global_free = data['free_capacity_gb']
+
+        thin_enabled = (self.configuration.glusterfs_sparsed_volumes or
+                        self.configuration.glusterfs_qcow2_volumes)
+        if thin_enabled:
+            provisioned_capacity = self._get_provisioned_capacity()
+        else:
+            provisioned_capacity = round(global_capacity - global_free, 2)
+
+        data['provisioned_capacity_gb'] = provisioned_capacity
+        data['max_over_subscription_ratio'] = (
+            self.configuration.max_over_subscription_ratio)
+        data['thin_provisioning_support'] = thin_enabled
+        data['thick_provisioning_support'] = not thin_enabled
+
+        self._stats = data
+
     @remotefs_drv.locked_volume_id_operation
     def create_volume(self, volume):
         """Creates a volume."""
index 30e9feddf0b1a149cd486c428a105c7d74570faf..cf1230e41c652e532fd4e09e0f36b97ceed054ed 100644 (file)
@@ -181,6 +181,20 @@ class RemoteFSDriver(driver.VolumeDriver):
                 LOG.error(msg)
                 raise exception.InvalidConfigurationValue(msg)
 
+    def _get_provisioned_capacity(self):
+        """Returns the provisioned capacity.
+
+        Get the sum of sizes of volumes, snapshots and any other
+        files on the mountpoint.
+        """
+        provisioned_size = 0.0
+        for share in self.shares.keys():
+            mount_path = self._get_mount_point_for_share(share)
+            out, _ = self._execute('du', '--bytes', mount_path,
+                                   run_as_root=True)
+            provisioned_size += int(out.split()[0])
+        return round(provisioned_size / units.Gi, 2)
+
     def _get_mount_point_base(self):
         """Returns the mount point base for the remote fs.