LVM: Create thin pool with 100%FREE

For LVM versions new enough to support this,
this will ensure VG space is used efficiently.

This also removes size specification for
create_thin_pool since it does not apply to
the flow where Cinder uses this.

Change-Id: Ia9107280c418b6c568887ab5d459ad6386898313
This commit is contained in:
Eric Harney 2016-04-26 16:16:43 -05:00
parent 9640b73cc4
commit dc9bbb978a
2 changed files with 38 additions and 21 deletions

View File

@ -259,6 +259,19 @@ class LVM(executor.Executor):
return self._supports_lvchange_ignoreskipactivation return self._supports_lvchange_ignoreskipactivation
@property
def supports_full_pool_create(self):
"""Property indicating whether 100% pool creation is supported.
Check for LVM version >= 2.02.115.
Ref: https://bugzilla.redhat.com/show_bug.cgi?id=998347
"""
if self.get_lvm_version(self._root_helper) >= (2, 2, 115):
return True
else:
return False
@staticmethod @staticmethod
def get_lv_info(root_helper, vg_name=None, lv_name=None): def get_lv_info(root_helper, vg_name=None, lv_name=None):
"""Retrieve info about LVs (all, in a VG, or a single LV). """Retrieve info about LVs (all, in a VG, or a single LV).
@ -478,10 +491,13 @@ class LVM(executor.Executor):
# make sure volume group information is current # make sure volume group information is current
self.update_volume_group_info() self.update_volume_group_info()
# leave 5% free for metadata if LVM.supports_full_pool_create:
return "%sg" % (self.vg_free_space * 0.95) return ["-l", "100%FREE"]
def create_thin_pool(self, name=None, size_str=None): # leave 5% free for metadata
return ["-L", "%sg" % (self.vg_free_space * 0.95)]
def create_thin_pool(self, name=None):
"""Creates a thin provisioning pool for this VG. """Creates a thin provisioning pool for this VG.
The syntax here is slightly different than the default The syntax here is slightly different than the default
@ -489,7 +505,6 @@ class LVM(executor.Executor):
and do it. and do it.
:param name: Name to use for pool, default is "<vg-name>-pool" :param name: Name to use for pool, default is "<vg-name>-pool"
:param size_str: Size to allocate for pool, default is entire VG
:returns: The size string passed to the lvcreate command :returns: The size string passed to the lvcreate command
""" """
@ -505,14 +520,15 @@ class LVM(executor.Executor):
vg_pool_name = '%s/%s' % (self.vg_name, name) vg_pool_name = '%s/%s' % (self.vg_name, name)
if not size_str: size_args = self._calculate_thin_pool_size()
size_str = self._calculate_thin_pool_size()
cmd = LVM.LVM_CMD_PREFIX + ['lvcreate', '-T']
cmd.extend(size_args)
cmd.append(vg_pool_name)
cmd = LVM.LVM_CMD_PREFIX + ['lvcreate', '-T', '-L', size_str,
vg_pool_name]
LOG.debug("Creating thin pool '%(pool)s' with size %(size)s of " LOG.debug("Creating thin pool '%(pool)s' with size %(size)s of "
"total %(free)sg", {'pool': vg_pool_name, "total %(free)sg", {'pool': vg_pool_name,
'size': size_str, 'size': size_args,
'free': self.vg_free_space}) 'free': self.vg_free_space})
self._execute(*cmd, self._execute(*cmd,
@ -520,7 +536,8 @@ class LVM(executor.Executor):
run_as_root=True) run_as_root=True)
self.vg_thin_pool = name self.vg_thin_pool = name
return size_str
return
def create_volume(self, name, size_str, lv_type='default', mirror_count=0): def create_volume(self, name, size_str, lv_type='default', mirror_count=0):
"""Creates a logical volume on the object's VG. """Creates a logical volume on the object's VG.

View File

@ -50,7 +50,11 @@ class BrickLvmTestCase(base.TestCase):
def fake_customised_lvm_version(obj, *cmd, **kwargs): def fake_customised_lvm_version(obj, *cmd, **kwargs):
return (" LVM version: 2.02.100(2)-RHEL6 (2013-09-12)\n", "") return (" LVM version: 2.02.100(2)-RHEL6 (2013-09-12)\n", "")
def fake_f23_lvm_version(obj, *cmd, **kwargs):
return (" LVM version: 2.02.132(2) (2015-09-22)\n", "")
def fake_execute(obj, *cmd, **kwargs): def fake_execute(obj, *cmd, **kwargs):
# TODO(eharney): remove this and move to per-test mocked execute calls
cmd_string = ', '.join(cmd) cmd_string = ', '.join(cmd)
data = "\n" data = "\n"
@ -133,6 +137,8 @@ class BrickLvmTestCase(base.TestCase):
data = " 9:12\n" data = " 9:12\n"
elif 'lvcreate, -T, -L, ' in cmd_string: elif 'lvcreate, -T, -L, ' in cmd_string:
pass pass
elif 'lvcreate, -T, -l, 100%FREE' in cmd_string:
pass
elif 'lvcreate, -T, -V, ' in cmd_string: elif 'lvcreate, -T, -V, ' in cmd_string:
pass pass
elif 'lvcreate, -n, ' in cmd_string: elif 'lvcreate, -n, ' in cmd_string:
@ -277,22 +283,16 @@ class BrickLvmTestCase(base.TestCase):
self.vg._supports_lvchange_ignoreskipactivation = None self.vg._supports_lvchange_ignoreskipactivation = None
def test_thin_pool_creation(self): def test_thin_pool_creation_manual(self):
# The size of fake-vg volume group is 10g, so the calculated thin # The size of fake-vg volume group is 10g, so the calculated thin
# pool size should be 9.5g (95% of 10g). # pool size should be 9.5g (95% of 10g).
self.assertEqual("9.5g", self.vg.create_thin_pool()) self.vg.create_thin_pool()
# Passing a size parameter should result in a thin pool of that exact
# size.
for size in ("1g", "1.2g", "1.75g"):
self.assertEqual(size, self.vg.create_thin_pool(size_str=size))
def test_thin_pool_provisioned_capacity(self): def test_thin_pool_provisioned_capacity(self):
self.vg.vg_thin_pool = "test-prov-cap-pool-unit" self.vg.vg_thin_pool = "test-prov-cap-pool-unit"
self.vg.vg_name = 'test-prov-cap-vg-unit' self.vg.vg_name = 'test-prov-cap-vg-unit'
self.assertEqual( self.assertEqual(
"9.5g", None,
self.vg.create_thin_pool(name=self.vg.vg_thin_pool)) self.vg.create_thin_pool(name=self.vg.vg_thin_pool))
self.assertEqual("9.50", self.vg.vg_thin_pool_size) self.assertEqual("9.50", self.vg.vg_thin_pool_size)
self.assertEqual(7.6, self.vg.vg_thin_pool_free_space) self.assertEqual(7.6, self.vg.vg_thin_pool_free_space)
@ -301,7 +301,7 @@ class BrickLvmTestCase(base.TestCase):
self.vg.vg_thin_pool = "test-prov-cap-pool-no-unit" self.vg.vg_thin_pool = "test-prov-cap-pool-no-unit"
self.vg.vg_name = 'test-prov-cap-vg-no-unit' self.vg.vg_name = 'test-prov-cap-vg-no-unit'
self.assertEqual( self.assertEqual(
"9.5g", None,
self.vg.create_thin_pool(name=self.vg.vg_thin_pool)) self.vg.create_thin_pool(name=self.vg.vg_thin_pool))
self.assertEqual("9.50", self.vg.vg_thin_pool_size) self.assertEqual("9.50", self.vg.vg_thin_pool_size)
self.assertEqual(7.6, self.vg.vg_thin_pool_free_space) self.assertEqual(7.6, self.vg.vg_thin_pool_free_space)
@ -328,7 +328,7 @@ class BrickLvmTestCase(base.TestCase):
self.assertEqual(pool_path, cmd[-1]) self.assertEqual(pool_path, cmd[-1])
self.vg._executor = executor self.vg._executor = executor
self.vg.create_thin_pool(pool_name, "1G") self.vg.create_thin_pool(pool_name)
self.vg.create_volume("test", "1G", lv_type='thin') self.vg.create_volume("test", "1G", lv_type='thin')
self.assertEqual(pool_name, self.vg.vg_thin_pool) self.assertEqual(pool_name, self.vg.vg_thin_pool)