From 73746bf94f0433cf96489c3e0c8df226664d395a Mon Sep 17 00:00:00 2001 From: Eric Harney Date: Mon, 16 Jun 2014 15:43:51 -0400 Subject: [PATCH] LVM Thin Provisioning auto-detect Add the ability to set lvm_type=auto, which will enable thin provisioning if the system supports it, and the configured volume group either: a) has a pool LV with the expected name or b) has no LVs This, along with thin-provisioning accounting, will give a path to move toward thin LVM as the default. DocImpact: new value 'auto' for option 'lvm_type' Partial-Bug: #1472803 Change-Id: Idfc1cd749bfd7aec659ab8e80629cc506cd9797a --- cinder/tests/unit/test_volume.py | 79 ++++++++++++++++++++++++++++++++ cinder/volume/drivers/lvm.py | 26 +++++++++-- 2 files changed, 102 insertions(+), 3 deletions(-) diff --git a/cinder/tests/unit/test_volume.py b/cinder/tests/unit/test_volume.py index 824a55775..693d964ce 100644 --- a/cinder/tests/unit/test_volume.py +++ b/cinder/tests/unit/test_volume.py @@ -6343,6 +6343,85 @@ class LVMVolumeDriverTestCase(DriverTestCase): execute=lvm_driver._execute, sparse=True) + @mock.patch.object(cinder.volume.utils, 'get_all_volume_groups', + return_value=[{'name': 'cinder-volumes'}]) + @mock.patch('cinder.brick.local_dev.lvm.LVM.update_volume_group_info') + @mock.patch('cinder.brick.local_dev.lvm.LVM.get_all_physical_volumes') + @mock.patch('cinder.brick.local_dev.lvm.LVM.supports_thin_provisioning', + return_value=True) + def test_lvm_type_auto_thin_pool_exists(self, *_unused_mocks): + configuration = conf.Configuration(fake_opt, 'fake_group') + configuration.lvm_type = 'auto' + + vg_obj = fake_lvm.FakeBrickLVM('cinder-volumes', + False, + None, + 'default') + + lvm_driver = lvm.LVMVolumeDriver(configuration=configuration, + vg_obj=vg_obj) + + lvm_driver.check_for_setup_error() + + self.assertEqual('thin', lvm_driver.configuration.lvm_type) + + @mock.patch.object(cinder.volume.utils, 'get_all_volume_groups', + return_value=[{'name': 'cinder-volumes'}]) + @mock.patch.object(cinder.brick.local_dev.lvm.LVM, 'get_volumes', + return_value=[]) + @mock.patch('cinder.brick.local_dev.lvm.LVM.update_volume_group_info') + @mock.patch('cinder.brick.local_dev.lvm.LVM.get_all_physical_volumes') + @mock.patch('cinder.brick.local_dev.lvm.LVM.supports_thin_provisioning', + return_value=True) + def test_lvm_type_auto_no_lvs(self, *_unused_mocks): + configuration = conf.Configuration(fake_opt, 'fake_group') + configuration.lvm_type = 'auto' + + vg_obj = fake_lvm.FakeBrickLVM('cinder-volumes', + False, + None, + 'default') + + lvm_driver = lvm.LVMVolumeDriver(configuration=configuration, + vg_obj=vg_obj) + + lvm_driver.check_for_setup_error() + + self.assertEqual('thin', lvm_driver.configuration.lvm_type) + + @mock.patch.object(cinder.volume.utils, 'get_all_volume_groups', + return_value=[{'name': 'cinder-volumes'}]) + @mock.patch('cinder.brick.local_dev.lvm.LVM.update_volume_group_info') + @mock.patch('cinder.brick.local_dev.lvm.LVM.get_all_physical_volumes') + @mock.patch('cinder.brick.local_dev.lvm.LVM.supports_thin_provisioning', + return_value=False) + def test_lvm_type_auto_no_thin_support(self, *_unused_mocks): + configuration = conf.Configuration(fake_opt, 'fake_group') + configuration.lvm_type = 'auto' + + lvm_driver = lvm.LVMVolumeDriver(configuration=configuration) + + lvm_driver.check_for_setup_error() + + self.assertEqual('default', lvm_driver.configuration.lvm_type) + + @mock.patch.object(cinder.volume.utils, 'get_all_volume_groups', + return_value=[{'name': 'cinder-volumes'}]) + @mock.patch('cinder.brick.local_dev.lvm.LVM.update_volume_group_info') + @mock.patch('cinder.brick.local_dev.lvm.LVM.get_all_physical_volumes') + @mock.patch('cinder.brick.local_dev.lvm.LVM.get_volume') + @mock.patch('cinder.brick.local_dev.lvm.LVM.supports_thin_provisioning', + return_value=False) + def test_lvm_type_auto_no_thin_pool(self, *_unused_mocks): + configuration = conf.Configuration(fake_opt, 'fake_group') + configuration.lvm_type = 'auto' + + lvm_driver = lvm.LVMVolumeDriver(configuration=configuration) + + lvm_driver.check_for_setup_error() + + self.assertEqual('default', lvm_driver.configuration.lvm_type) + class ISCSITestCase(DriverTestCase): """Test Case for ISCSIDriver""" diff --git a/cinder/volume/drivers/lvm.py b/cinder/volume/drivers/lvm.py index a78038dfb..e45f30bb6 100644 --- a/cinder/volume/drivers/lvm.py +++ b/cinder/volume/drivers/lvm.py @@ -51,8 +51,9 @@ volume_opts = [ 'this requires lvm_mirrors + 2 PVs with available space'), cfg.StrOpt('lvm_type', default='default', - choices=['default', 'thin'], - help='Type of LVM volumes to deploy'), + choices=['default', 'thin', 'auto'], + help='Type of LVM volumes to deploy; (default, thin, or auto). ' + 'Auto defaults to thin if thin is supported.'), cfg.StrOpt('lvm_conf_file', default='/etc/cinder/lvm.conf', help='LVM conf file to use for the LVM driver in Cinder; ' @@ -278,6 +279,26 @@ class LVMVolumeDriver(driver.VolumeDriver): self.configuration.volume_group) raise exception.VolumeBackendAPIException(data=message) + pool_name = "%s-pool" % self.configuration.volume_group + + if self.configuration.lvm_type == 'auto': + # Default to thin provisioning if it is supported and + # the volume group is empty, or contains a thin pool + # for us to use. + self.vg.update_volume_group_info() + + self.configuration.lvm_type = 'default' + + if volutils.supports_thin_provisioning(): + if self.vg.get_volume(pool_name) is not None: + LOG.info(_LI('Enabling LVM thin provisioning by default ' + 'because a thin pool exists.')) + self.configuration.lvm_type = 'thin' + elif len(self.vg.get_volumes()) == 0: + LOG.info(_LI('Enabling LVM thin provisioning by default ' + 'because no LVs exist.')) + self.configuration.lvm_type = 'thin' + if self.configuration.lvm_type == 'thin': # Specific checks for using Thin provisioned LV's if not volutils.supports_thin_provisioning(): @@ -285,7 +306,6 @@ class LVMVolumeDriver(driver.VolumeDriver): "on this version of LVM.") raise exception.VolumeBackendAPIException(data=message) - pool_name = "%s-pool" % self.configuration.volume_group if self.vg.get_volume(pool_name) is None: try: self.vg.create_thin_pool(pool_name) -- 2.45.2