LVM: Activate source LV before cloning from it
LVM may be configured to not automatically activate thin-provisioned LVs. Ensure they are activated when performing a clone, otherwise dd will fail as the device does not exist in /dev/mapper/. Closes-Bug: #1252423 Change-Id: Ibcb946ffe7804b1976bf1b1863c48340c8cc7fd5
This commit is contained in:
parent
1099f09a2d
commit
01a2199d85
|
@ -64,6 +64,7 @@ class LVM(executor.Executor):
|
|||
self.vg_uuid = None
|
||||
self.vg_thin_pool = None
|
||||
self.vg_thin_pool_size = 0
|
||||
self._supports_lvchange_ignoreskipactivation = None
|
||||
|
||||
if create_vg and physical_volumes is not None:
|
||||
self.pv_list = physical_volumes
|
||||
|
@ -146,6 +147,29 @@ class LVM(executor.Executor):
|
|||
return True
|
||||
return False
|
||||
|
||||
@property
|
||||
def supports_lvchange_ignoreskipactivation(self):
|
||||
"""Property indicating whether lvchange can ignore skip activation.
|
||||
|
||||
Tests whether lvchange -K/--ignoreactivationskip exists.
|
||||
"""
|
||||
|
||||
if self._supports_lvchange_ignoreskipactivation is not None:
|
||||
return self._supports_lvchange_ignoreskipactivation
|
||||
|
||||
cmd = ['lvchange', '--help']
|
||||
(out, err) = self._execute(*cmd)
|
||||
|
||||
self._supports_lvchange_ignoreskipactivation = False
|
||||
|
||||
lines = out.split('\n')
|
||||
for line in lines:
|
||||
if '-K' in line and '--ignoreactivationskip' in line:
|
||||
self._supports_lvchange_ignoreskipactivation = True
|
||||
break
|
||||
|
||||
return self._supports_lvchange_ignoreskipactivation
|
||||
|
||||
@staticmethod
|
||||
def get_all_volumes(root_helper, vg_name=None, no_suffix=True):
|
||||
"""Static method to get all LV's on a system.
|
||||
|
@ -404,6 +428,38 @@ class LVM(executor.Executor):
|
|||
LOG.error(_('StdErr :%s') % err.stderr)
|
||||
raise
|
||||
|
||||
def _mangle_lv_name(self, name):
|
||||
# Linux LVM reserves name that starts with snapshot, so that
|
||||
# such volume name can't be created. Mangle it.
|
||||
if not name.startswith('snapshot'):
|
||||
return name
|
||||
return '_' + name
|
||||
|
||||
def activate_lv(self, name):
|
||||
"""Ensure that logical volume/snapshot logical volume is activated.
|
||||
|
||||
:param name: Name of LV to activate
|
||||
"""
|
||||
lv_path = self.vg_name + '/' + self._mangle_lv_name(name)
|
||||
|
||||
cmd = ['lvchange', '-a', 'y']
|
||||
|
||||
if self.supports_lvchange_ignoreskipactivation:
|
||||
cmd.append('-K')
|
||||
|
||||
cmd.append(lv_path)
|
||||
|
||||
try:
|
||||
self._execute(*cmd,
|
||||
root_helper=self._root_helper,
|
||||
run_as_root=True)
|
||||
except putils.ProcessExecutionError as err:
|
||||
LOG.exception(_('Error activating LV'))
|
||||
LOG.error(_('Cmd :%s') % err.cmd)
|
||||
LOG.error(_('StdOut :%s') % err.stdout)
|
||||
LOG.error(_('StdErr :%s') % err.stderr)
|
||||
raise
|
||||
|
||||
def delete(self, name):
|
||||
"""Delete logical volume or snapshot.
|
||||
|
||||
|
|
|
@ -153,6 +153,48 @@ class BrickLvmTestCase(test.TestCase):
|
|||
self.fake_customised_lvm_version)
|
||||
self.assertTrue(self.vg.supports_thin_provisioning('sudo'))
|
||||
|
||||
def test_lvchange_ignskipact_support_yes(self):
|
||||
"""Tests the ability to test support for lvchange -K
|
||||
|
||||
Stubs provide output for "lvchange --help".
|
||||
"""
|
||||
|
||||
def lvchange_ign_yes(obj, *args, **kwargs):
|
||||
return ("""
|
||||
WARNING: Running as a non-root user. Functionality may be
|
||||
unavailable.
|
||||
lvchange: Change the attributes of logical volume(s)
|
||||
|
||||
lvchange
|
||||
[-A|--autobackup y|n]
|
||||
[-k|--setactivationskip {y|n}]
|
||||
[-K|--ignoreactivationskip]
|
||||
[-y|--yes]
|
||||
[-Z|--zero {y|n}]
|
||||
LogicalVolume[Path] [LogicalVolume[Path]...]
|
||||
""", "")
|
||||
|
||||
self.stubs.Set(self.vg, '_execute', lvchange_ign_yes)
|
||||
self.assertTrue(self.vg.supports_lvchange_ignoreskipactivation)
|
||||
|
||||
def test_lvchange_ignskipact_support_no(self):
|
||||
def lvchange_ign_no(obj, *args, **kwargs):
|
||||
return ("""
|
||||
WARNING: Running as a non-root user. Functionality may be
|
||||
unavailable.
|
||||
lvchange: Change the attributes of logical volume(s)
|
||||
|
||||
lvchange
|
||||
[-A|--autobackup y|n]
|
||||
[-k|--setactivationskip {y|n}]
|
||||
[-y|--yes]
|
||||
[-Z|--zero {y|n}]
|
||||
LogicalVolume[Path] [LogicalVolume[Path]...]
|
||||
""", "")
|
||||
|
||||
self.stubs.Set(self.vg, '_execute', lvchange_ign_no)
|
||||
self.assertFalse(self.vg.supports_lvchange_ignoreskipactivation)
|
||||
|
||||
def test_volume_create_after_thin_creation(self):
|
||||
"""Test self.vg.vg_thin_pool is set to pool_name
|
||||
|
||||
|
@ -175,3 +217,16 @@ class BrickLvmTestCase(test.TestCase):
|
|||
def test_lv_has_snapshot(self):
|
||||
self.assertTrue(self.vg.lv_has_snapshot('fake-volumes'))
|
||||
self.assertFalse(self.vg.lv_has_snapshot('test-volumes'))
|
||||
|
||||
def test_activate_lv(self):
|
||||
self._mox.StubOutWithMock(self.vg, '_execute')
|
||||
self.vg._supports_lvchange_ignoreskipactivation = True
|
||||
|
||||
self.vg._execute('lvchange', '-a', 'y', '-K', 'fake-volumes/my-lv',
|
||||
root_helper='sudo', run_as_root=True)
|
||||
|
||||
self._mox.ReplayAll()
|
||||
|
||||
self.vg.activate_lv('my-lv')
|
||||
|
||||
self._mox.VerifyAll()
|
||||
|
|
|
@ -166,6 +166,10 @@ class LVMVolumeDriver(driver.VolumeDriver):
|
|||
self.configuration.lvm_type,
|
||||
self.configuration.lvm_mirrors)
|
||||
|
||||
# Some configurations of LVM do not automatically activate
|
||||
# ThinLVM snapshot LVs.
|
||||
self.vg.activate_lv(snapshot['name'])
|
||||
|
||||
volutils.copy_volume(self.local_path(snapshot),
|
||||
self.local_path(volume),
|
||||
snapshot['volume_size'] * 1024,
|
||||
|
|
|
@ -30,6 +30,9 @@ lvrename: CommandFilter, lvrename, root
|
|||
# cinder/volume/driver.py: 'lvextend', '-L' '%(new_size)s', '%(lv_name)s' ...
|
||||
lvextend: CommandFilter, lvextend, root
|
||||
|
||||
# cinder/brick/local_dev/lvm.py: 'lvchange -a y -K <lv>'
|
||||
lvchange: CommandFilter, lvchange, root
|
||||
|
||||
# cinder/volume/driver.py: 'iscsiadm', '-m', 'discovery', '-t',...
|
||||
# cinder/volume/driver.py: 'iscsiadm', '-m', 'node', '-T', ...
|
||||
iscsiadm: CommandFilter, iscsiadm, root
|
||||
|
|
Loading…
Reference in New Issue