From: Bharat Kumar Kobagana Date: Wed, 11 Mar 2015 12:06:04 +0000 (+0530) Subject: GlusterFS: Support over subscription in thin provisioning X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=f119a62e60f5689b013203d4900aaeead6bff555;p=openstack-build%2Fcinder-build.git GlusterFS: Support over subscription in thin provisioning 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 Implements: blueprint glusterfs-over-subscription-thin-provisioning Change-Id: I7fbbe989c865dce42102b63f7d52a8edb63e7a9e --- diff --git a/cinder/tests/unit/test_glusterfs.py b/cinder/tests/unit/test_glusterfs.py index b85da1250..113b6ab06 100644 --- a/cinder/tests/unit/test_glusterfs.py +++ b/cinder/tests/unit/test_glusterfs.py @@ -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 diff --git a/cinder/volume/drivers/glusterfs.py b/cinder/volume/drivers/glusterfs.py index 325c7d221..7ef40abce 100644 --- a/cinder/volume/drivers/glusterfs.py +++ b/cinder/volume/drivers/glusterfs.py @@ -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.""" diff --git a/cinder/volume/drivers/remotefs.py b/cinder/volume/drivers/remotefs.py index 30e9feddf..cf1230e41 100644 --- a/cinder/volume/drivers/remotefs.py +++ b/cinder/volume/drivers/remotefs.py @@ -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.