Merge "Software RAID: Get component devices by md UUID"
This commit is contained in:
commit
99dee5067e
|
@ -136,10 +136,34 @@ def _check_for_iscsi():
|
|||
"Error: %s", e)
|
||||
|
||||
|
||||
def _get_md_uuid(raid_device):
|
||||
"""Get the md UUID of a Software RAID device.
|
||||
|
||||
:param raid_device: A Software RAID block device name.
|
||||
:returns: A string containing the UUID of an md device.
|
||||
"""
|
||||
try:
|
||||
out, _ = utils.execute('mdadm', '--detail', raid_device,
|
||||
use_standard_locale=True)
|
||||
except processutils.ProcessExecutionError as e:
|
||||
msg = ('Could not get the details of %(dev)s: %(err)s' %
|
||||
{'dev': raid_device, 'err': e})
|
||||
LOG.warning(msg)
|
||||
return
|
||||
|
||||
lines = out.splitlines()
|
||||
# the first line contains the md device itself
|
||||
for line in lines[1:]:
|
||||
match = re.search(r'UUID : ([a-f0-9:]+)', line)
|
||||
if match:
|
||||
return match.group(1)
|
||||
|
||||
|
||||
def _get_component_devices(raid_device):
|
||||
"""Get the component devices of a Software RAID device.
|
||||
|
||||
Examine an md device and return its constituent devices.
|
||||
Get the UUID of the md device and scan all other devices
|
||||
for the same md UUID.
|
||||
|
||||
:param raid_device: A Software RAID block device name.
|
||||
:returns: A list of the component devices.
|
||||
|
@ -147,22 +171,35 @@ def _get_component_devices(raid_device):
|
|||
if not raid_device:
|
||||
return []
|
||||
|
||||
try:
|
||||
out, _ = utils.execute('mdadm', '--detail', raid_device,
|
||||
use_standard_locale=True)
|
||||
except processutils.ProcessExecutionError as e:
|
||||
msg = ('Could not get component devices of %(dev)s: %(err)s' %
|
||||
{'dev': raid_device, 'err': e})
|
||||
LOG.warning(msg)
|
||||
md_uuid = _get_md_uuid(raid_device)
|
||||
if not md_uuid:
|
||||
return []
|
||||
LOG.debug('%s has UUID %s', raid_device, md_uuid)
|
||||
|
||||
component_devices = []
|
||||
lines = out.splitlines()
|
||||
# the first line contains the md device itself
|
||||
for line in lines[1:]:
|
||||
device = re.findall(r'/dev/\w+', line)
|
||||
component_devices += device
|
||||
block_devices = list_all_block_devices()
|
||||
block_devices.extend(list_all_block_devices(block_type='part',
|
||||
ignore_raid=True))
|
||||
for bdev in block_devices:
|
||||
try:
|
||||
out, _ = utils.execute('mdadm', '--examine', bdev.name,
|
||||
use_standard_locale=True)
|
||||
except processutils.ProcessExecutionError as e:
|
||||
if "No md superblock detected" in str(e):
|
||||
# actually not a component device
|
||||
LOG.debug('Not a component device %s', bdev.name)
|
||||
continue
|
||||
else:
|
||||
LOG.warning("Failed to examine device %s: %s",
|
||||
bdev.name, e)
|
||||
continue
|
||||
lines = out.splitlines()
|
||||
for line in lines:
|
||||
if md_uuid in line:
|
||||
component_devices.append(bdev.name)
|
||||
|
||||
LOG.info('Found component devices for %s:',
|
||||
raid_device, component_devices)
|
||||
return component_devices
|
||||
|
||||
|
||||
|
|
|
@ -801,6 +801,64 @@ MDADM_DETAIL_OUTPUT_BROKEN_RAID0 = ("""/dev/md126:
|
|||
""")
|
||||
|
||||
|
||||
MDADM_EXAMINE_OUTPUT_MEMBER = ("""/dev/sda1:
|
||||
Magic : a92b4efc
|
||||
Version : 1.2
|
||||
Feature Map : 0x0
|
||||
Array UUID : 83143055:2781ddf5:2c8f44c7:9b45d92e
|
||||
Name : horse.cern.ch:1 (local to host abc.xyz.com)
|
||||
Creation Time : Tue Jun 11 12:43:37 2019
|
||||
Raid Level : raid1
|
||||
Raid Devices : 2
|
||||
|
||||
Avail Dev Size : 2093056 sectors (1022.00 MiB 1071.64 MB)
|
||||
Array Size : 1046528 KiB (1022.00 MiB 1071.64 MB)
|
||||
Data Offset : 2048 sectors
|
||||
Super Offset : 8 sectors
|
||||
Unused Space : before=1968 sectors, after=0 sectors
|
||||
State : clean
|
||||
Device UUID : 88bf2723:d082f14f:f95e87cf:b7c59b83
|
||||
|
||||
Update Time : Sun Sep 27 01:00:08 2020
|
||||
Bad Block Log : 512 entries available at offset 16 sectors
|
||||
Checksum : 340a1610 - correct
|
||||
Events : 178
|
||||
|
||||
|
||||
Device Role : Active device 0
|
||||
Array State : A. ('A' == active, '.' == missing, 'R' == replacing)
|
||||
""")
|
||||
|
||||
|
||||
MDADM_EXAMINE_OUTPUT_NON_MEMBER = ("""/dev/sdz1:
|
||||
Magic : a92b4efc
|
||||
Version : 1.2
|
||||
Feature Map : 0x0
|
||||
Array UUID : 83143055:2781ddf5:2c8f44c7:9b45d92f
|
||||
Name : horse.cern.ch:1 (local to host abc.xyz.com)
|
||||
Creation Time : Tue Jun 11 12:43:37 2019
|
||||
Raid Level : raid1
|
||||
Raid Devices : 2
|
||||
|
||||
Avail Dev Size : 2093056 sectors (1022.00 MiB 1071.64 MB)
|
||||
Array Size : 1046528 KiB (1022.00 MiB 1071.64 MB)
|
||||
Data Offset : 2048 sectors
|
||||
Super Offset : 8 sectors
|
||||
Unused Space : before=1968 sectors, after=0 sectors
|
||||
State : clean
|
||||
Device UUID : 88bf2723:d082f14f:f95e87cf:b7c59b84
|
||||
|
||||
Update Time : Sun Sep 27 01:00:08 2020
|
||||
Bad Block Log : 512 entries available at offset 16 sectors
|
||||
Checksum : 340a1610 - correct
|
||||
Events : 178
|
||||
|
||||
|
||||
Device Role : Active device 0
|
||||
Array State : A. ('A' == active, '.' == missing, 'R' == replacing)
|
||||
""")
|
||||
|
||||
|
||||
class FakeHardwareManager(hardware.GenericHardwareManager):
|
||||
def __init__(self, hardware_support):
|
||||
self._hardware_support = hardware_support
|
||||
|
@ -3908,16 +3966,47 @@ class TestGenericHardwareManager(base.IronicAgentTest):
|
|||
self.node, [])
|
||||
|
||||
@mock.patch.object(utils, 'execute', autospec=True)
|
||||
def test__get_component_devices(self, mocked_execute):
|
||||
def test__get_md_uuid(self, mocked_execute):
|
||||
mocked_execute.side_effect = [(MDADM_DETAIL_OUTPUT, '')]
|
||||
component_devices = hardware._get_component_devices('/dev/md0')
|
||||
self.assertEqual(['/dev/vde1', '/dev/vdf1'], component_devices)
|
||||
md_uuid = hardware._get_md_uuid('/dev/md0')
|
||||
self.assertEqual('83143055:2781ddf5:2c8f44c7:9b45d92e', md_uuid)
|
||||
|
||||
@mock.patch.object(hardware, '_get_md_uuid', autospec=True)
|
||||
@mock.patch.object(hardware, 'list_all_block_devices', autospec=True)
|
||||
@mock.patch.object(utils, 'execute', autospec=True)
|
||||
def test__get_component_devices_broken_raid0(self, mocked_execute):
|
||||
mocked_execute.side_effect = [(MDADM_DETAIL_OUTPUT_BROKEN_RAID0, '')]
|
||||
component_devices = hardware._get_component_devices('/dev/md126')
|
||||
self.assertEqual(['/dev/sda2'], component_devices)
|
||||
def test__get_component_devices(self, mocked_execute,
|
||||
mocked_list_all_block_devices,
|
||||
mocked_md_uuid):
|
||||
raid_device1 = hardware.BlockDevice('/dev/md0', 'RAID-1',
|
||||
107374182400, True)
|
||||
sda = hardware.BlockDevice('/dev/sda', 'model12', 21, True)
|
||||
sdz = hardware.BlockDevice('/dev/sdz', 'model12', 21, True)
|
||||
sda1 = hardware.BlockDevice('/dev/sda1', 'model12', 21, True)
|
||||
sdz1 = hardware.BlockDevice('/dev/sdz1', 'model12', 21, True)
|
||||
|
||||
mocked_md_uuid.return_value = '83143055:2781ddf5:2c8f44c7:9b45d92e'
|
||||
hardware.list_all_block_devices.side_effect = [
|
||||
[sda, sdz], # list_all_block_devices
|
||||
[sda1, sdz1], # list_all_block_devices partitions
|
||||
]
|
||||
mocked_execute.side_effect = [
|
||||
['mdadm --examine output for sda', '_'],
|
||||
['mdadm --examine output for sdz', '_'],
|
||||
[MDADM_EXAMINE_OUTPUT_MEMBER, '_'],
|
||||
[MDADM_EXAMINE_OUTPUT_NON_MEMBER, '_'],
|
||||
]
|
||||
|
||||
component_devices = hardware._get_component_devices(raid_device1)
|
||||
self.assertEqual(['/dev/sda1'], component_devices)
|
||||
mocked_execute.assert_has_calls([
|
||||
mock.call('mdadm', '--examine', '/dev/sda',
|
||||
use_standard_locale=True),
|
||||
mock.call('mdadm', '--examine', '/dev/sdz',
|
||||
use_standard_locale=True),
|
||||
mock.call('mdadm', '--examine', '/dev/sda1',
|
||||
use_standard_locale=True),
|
||||
mock.call('mdadm', '--examine', '/dev/sdz1',
|
||||
use_standard_locale=True)])
|
||||
|
||||
@mock.patch.object(utils, 'execute', autospec=True)
|
||||
def test_get_holder_disks(self, mocked_execute):
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
fixes:
|
||||
- |
|
||||
Detects md component devices by their UUID, rather than by scanning the
|
||||
output of mdadm. This will prevent that devices miss md superblock
|
||||
cleanup when they are currently not part of an array.
|
Loading…
Reference in New Issue