From 1679acd53d1f0c330edf583afe8b347a7304499c Mon Sep 17 00:00:00 2001 From: Giulio Fidente Date: Tue, 3 Dec 2013 13:44:20 +0100 Subject: [PATCH] Returns thin pool free space calculated from actual usage This change adds a hidden method which calculates the thin pool free space from the data_percent LVM options and reports it accordingly in _update_volume_stats() Change-Id: Id6a69644505ca10811db458ea90ed10f643054b2 Closes-Bug: 1249782 --- cinder/brick/local_dev/lvm.py | 39 ++++++++++++++++++++++++++++ cinder/tests/brick/test_brick_lvm.py | 10 +++++++ cinder/volume/drivers/lvm.py | 3 +++ 3 files changed, 52 insertions(+) diff --git a/cinder/brick/local_dev/lvm.py b/cinder/brick/local_dev/lvm.py index 433251e2d..d0f41097d 100644 --- a/cinder/brick/local_dev/lvm.py +++ b/cinder/brick/local_dev/lvm.py @@ -64,6 +64,7 @@ class LVM(executor.Executor): self.vg_uuid = None self.vg_thin_pool = None self.vg_thin_pool_size = 0 + self.vg_thin_pool_free_space = 0 self._supports_snapshot_lv_activation = None self._supports_lvchange_ignoreskipactivation = None @@ -121,6 +122,41 @@ class LVM(executor.Executor): else: return [] + def _get_thin_pool_free_space(self, vg_name, thin_pool_name): + """Returns available thin pool free space. + + :param vg_name: the vg where the pool is placed + :param thin_pool_name: the thin pool to gather info for + :returns: Free space, calculated after the data_percent value + + """ + cmd = ['env', 'LC_ALL=C', 'LANG=C', 'lvs', '--noheadings', '--unit=g', + '-o', 'size,data_percent', '--separator', ':', '--nosuffix'] + + # NOTE(gfidente): data_percent only applies to some types of LV so we + # make sure to append the actual thin pool name + cmd.append("/dev/%s/%s" % (vg_name, thin_pool_name)) + + free_space = 0 + + try: + (out, err) = self._execute(*cmd, + root_helper=self._root_helper, + run_as_root=True) + if out is not None: + out = out.strip() + data = out.split(':') + consumed_space = float(data[0]) / 100 * (float(data[1])) + free_space = float(data[0]) - consumed_space + free_space = round(free_space, 2) + except putils.ProcessExecutionError as err: + LOG.exception(_('Error querying thin pool about data_percent')) + LOG.error(_('Cmd :%s') % err.cmd) + LOG.error(_('StdOut :%s') % err.stdout) + LOG.error(_('StdErr :%s') % err.stderr) + + return free_space + @staticmethod def get_lvm_version(root_helper): """Static method to get LVM version from system. @@ -355,6 +391,9 @@ class LVM(executor.Executor): for lv in self.get_all_volumes(self._root_helper, self.vg_name): if lv['name'] == self.vg_thin_pool: self.vg_thin_pool_size = lv['size'] + tpfs = self._get_thin_pool_free_space(self.vg_name, + self.vg_thin_pool) + self.vg_thin_pool_free_space = tpfs def _calculate_thin_pool_size(self): """Calculates the correct size for a thin pool. diff --git a/cinder/tests/brick/test_brick_lvm.py b/cinder/tests/brick/test_brick_lvm.py index beb60ecd9..6a6f3acb4 100644 --- a/cinder/tests/brick/test_brick_lvm.py +++ b/cinder/tests/brick/test_brick_lvm.py @@ -101,6 +101,9 @@ class BrickLvmTestCase(test.TestCase): data = " fake-volumes:/dev/sda:10.00g:8.99g\n" data += " fake-volumes-2:/dev/sdb:10.00g:8.99g\n" data += " fake-volumes-3:/dev/sdc:10.00g:8.99g\n" + elif 'lvs, --noheadings, --unit=g, -o, size,data_percent, ' \ + '--separator, :' in cmd_string: + data = " 9:12\n" else: raise AssertionError('unexpected command called: %s' % cmd_string) @@ -225,6 +228,13 @@ class BrickLvmTestCase(test.TestCase): for size in ("1g", "1.2g", "1.75g"): self.assertEqual(size, self.vg.create_thin_pool(size_str=size)) + def test_thin_pool_free_space(self): + # The size of fake-volumes-pool is 9g and the allocated data sums up to + # 12% so the calculated free space should be 7.92 + self.assertEqual(float("7.92"), + self.vg._get_thin_pool_free_space("fake-vg", + "fake-vg-pool")) + def test_volume_create_after_thin_creation(self): """Test self.vg.vg_thin_pool is set to pool_name diff --git a/cinder/volume/drivers/lvm.py b/cinder/volume/drivers/lvm.py index 29fc556fc..0c1b65992 100644 --- a/cinder/volume/drivers/lvm.py +++ b/cinder/volume/drivers/lvm.py @@ -368,6 +368,9 @@ class LVMVolumeDriver(driver.VolumeDriver): data['total_capacity_gb'] = float(self.vg.vg_size) data['free_capacity_gb'] = float(self.vg.vg_free_space) + if self.configuration.lvm_type == 'thin': + data['total_capacity_gb'] = float(self.vg.vg_thin_pool_size) + data['free_capacity_gb'] = float(self.vg.vg_thin_pool_free_space) data['reserved_percentage'] = self.configuration.reserved_percentage data['QoS_support'] = False data['location_info'] =\ -- 2.45.2