Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add LVM based image support to MD scenario #77

Draft
wants to merge 1 commit into
base: stackhpc/2023.1
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions ironic_python_agent/hardware.py
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,13 @@ def md_restart(raid_device):
"""
try:
LOG.debug('Restarting software RAID device %s', raid_device)
# NOTE(mnasiadka): If the image is LVM based we need to clean
# dmsetup devices, because mdadm --stop will fail.
dmsetup_stdout, _ = il_utils.execute('dmsetup', 'table',
use_standard_locale=True)
if 'No devices found' not in dmsetup_stdout:
LOG.debug('Deactivating LVM')
il_utils.execute('dmsetup', 'remove_all')
component_devices = get_component_devices(raid_device)
il_utils.execute('mdadm', '--stop', raid_device)
il_utils.execute('mdadm', '--assemble', raid_device,
Expand Down Expand Up @@ -550,6 +557,7 @@ def _is_known_device(existing, new_device_name):
report_json = json.loads(report)
except json.decoder.JSONDecodeError as ex:
LOG.error("Unable to decode lsblk output, invalid JSON: %s", ex)
raise

context = pyudev.Context()
devices_raw = report_json['blockdevices']
Expand Down Expand Up @@ -605,11 +613,11 @@ def _is_known_device(existing, new_device_name):
{'device_raw': device_raw})
elif (devtype == 'md'
and (block_type == 'part'
or block_type == 'md')):
# NOTE(dszumski): Partitions on software RAID devices have type
# 'md'. This may also contain RAID devices in a broken state in
# rare occasions. See https://review.opendev.org/#/c/670807 for
# more detail.
or block_type == 'lvm')):
# NOTE(dszumski): Partitions and LVM volumes on software RAID
# devices have type 'md'. This may also contain RAID devices in
# a broken state in rare occasions. See
# https://review.opendev.org/#/c/670807 for more detail.
LOG.debug(
"TYPE detected to contain 'md', signifying a "
"RAID partition. Found: %(device_raw)s",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,9 @@
{"kname":"md0", "model":"RAID", "size":1765517033470, "rota":false,
"type":"raid1", "serial":null, "uuid":null, "partuuid":null},
{"kname":"md1", "model":"RAID", "size":0, "rota":false, "type":"raid1",
"serial":null, "uuid":null, "partuuid":null}
"serial":null, "uuid":null, "partuuid":null},
{"kname":"dm-0", "model":"RAID", "size":1765517033470, "rota":false,
"type":"md", "uuid":null, "partuuid":null}
]
}
""")
Expand Down
66 changes: 63 additions & 3 deletions ironic_python_agent/tests/unit/test_hardware.py
Original file line number Diff line number Diff line change
Expand Up @@ -1701,9 +1701,9 @@ def test_list_block_devices_check_skip_list_with_complete_skip_list(
@mock.patch.object(hardware, '_get_device_info', autospec=True)
@mock.patch.object(pyudev.Devices, 'from_device_file', autospec=False)
@mock.patch.object(il_utils, 'execute', autospec=True)
def test_list_all_block_device(self, mocked_execute, mocked_udev,
mocked_dev_vendor, mock_listdir,
mock_readlink):
def test_list_all_block_devices(self, mocked_execute, mocked_udev,
mocked_dev_vendor, mock_listdir,
mock_readlink):
by_path_map = {
'/dev/disk/by-path/1:0:0:0': '../../dev/sda',
'/dev/disk/by-path/1:0:0:1': '../../dev/sdb',
Expand Down Expand Up @@ -5602,6 +5602,66 @@ def test_list_all_block_devices_success_raid(self, mocked_fromdevfile,
@mock.patch.object(hardware, '_get_device_info',
lambda x, y, z: 'FooTastic')
@mock.patch.object(hardware, '_udev_settle', autospec=True)
@mock.patch.object(hardware.pyudev.Devices, "from_device_file",
autospec=False)
def test_list_all_block_devices_success_raid_lvm(self, mocked_fromdevfile,
mocked_udev,
mocked_readlink,
mocked_mpath,
mocked_execute):
mocked_readlink.return_value = '../../sda'
mocked_fromdevfile.return_value = {}
mocked_mpath.return_value = True
mocked_execute.side_effect = [
(hws.RAID_BLK_DEVICE_TEMPLATE, ''),
processutils.ProcessExecutionError(
stderr=hws.MULTIPATH_INVALID_PATH % '/dev/sda'),
processutils.ProcessExecutionError(
stderr=hws.MULTIPATH_INVALID_PATH % '/dev/sda1'),
processutils.ProcessExecutionError(
stderr=hws.MULTIPATH_INVALID_PATH % '/dev/sdb'),
processutils.ProcessExecutionError(
stderr=hws.MULTIPATH_INVALID_PATH % '/dev/sdb1'),
processutils.ProcessExecutionError(
stderr=hws.MULTIPATH_INVALID_PATH % '/dev/sda'),
processutils.ProcessExecutionError(
stderr='the -c option requires a path to check'), # md0p1
processutils.ProcessExecutionError(
stderr='the -c option requires a path to check'), # md0
processutils.ProcessExecutionError(
stderr='the -c option requires a path to check'), # md0
processutils.ProcessExecutionError(
stderr='the -c option requires a path to check'), # md1
processutils.ProcessExecutionError(
stderr='the -c option requires a path to check'), # dm-0
]
expected_calls = [
mock.call('lsblk', '-bia', '--json',
'-oKNAME,MODEL,SIZE,ROTA,TYPE,UUID,PARTUUID',
check_exit_code=[0]),
mock.call('multipath', '-c', '/dev/sda'),
mock.call('multipath', '-c', '/dev/sda1'),
mock.call('multipath', '-c', '/dev/sdb'),
mock.call('multipath', '-c', '/dev/sdb'),
mock.call('multipath', '-c', '/dev/sdb1'),
mock.call('multipath', '-c', '/dev/md0p1'),
mock.call('multipath', '-c', '/dev/md0'),
mock.call('multipath', '-c', '/dev/md0'),
mock.call('multipath', '-c', '/dev/md1'),
mock.call('multipath', '-c', '/dev/dm-0'),
]
result = hardware.list_all_block_devices(block_type='lvm',
ignore_empty=False)
mocked_execute.assert_has_calls(expected_calls)
hardware.LOG.error(result[0].__dict__)
self.assertEqual(RAID_BLK_DEVICE_TEMPLATE_DEVICES[3:4], result)
mocked_udev.assert_called_once_with()

@mock.patch.object(hardware, 'get_multipath_status', autospec=True)
@mock.patch.object(os, 'readlink', autospec=True)
@mock.patch.object(hardware, '_get_device_info',
lambda x, y, z: 'FooTastic')
@mock.patch.object(disk_utils, 'udev_settle', autospec=True)
@mock.patch.object(hardware.pyudev.Devices, "from_device_file",
autospec=False)
def test_list_all_block_devices_partuuid_success(
Expand Down
4 changes: 4 additions & 0 deletions releasenotes/notes/lvm-md-322bdd582b407606.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
features:
- |
Add support for LVM based images in MD (software RAID) scenario.
Loading