Set rd.md.uuid kernel parameter when deploying on software raid
When deploying an image to a software raid array, it is currently required that the deployed image assembles the md arrays automatically so that the rootfs can be mounted. In order to remove this requirement/limitation on the deployed image we can add rd.md.uuid to the kernel command line with the raid array's uuid. Story: 2006648 Task: 36884 Change-Id: I42cb198753ecd84b7eaef6b5aa7c2064535bfe0e
This commit is contained in:
parent
5e3153825a
commit
1975478097
@ -14,6 +14,7 @@
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
import shutil
|
||||
import stat
|
||||
@ -98,6 +99,16 @@ def _get_partition(device, uuid):
|
||||
raise errors.CommandExecutionError(error_msg)
|
||||
|
||||
|
||||
def _has_dracut(root):
|
||||
try:
|
||||
utils.execute('chroot %(path)s /bin/sh -c '
|
||||
'"which dracut"' %
|
||||
{'path': root}, shell=True)
|
||||
except processutils.ProcessExecutionError:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def _install_grub2(device, root_uuid, efi_system_part_uuid=None,
|
||||
prep_boot_part_uuid=None):
|
||||
"""Install GRUB2 bootloader on a given device."""
|
||||
@ -177,6 +188,22 @@ def _install_grub2(device, root_uuid, efi_system_part_uuid=None,
|
||||
{'path': path, 'bin': binary_name, 'dev': device},
|
||||
shell=True, env_variables={'PATH': path_variable})
|
||||
|
||||
# If the image has dracut installed, set the rd.md.uuid kernel
|
||||
# parameter for discovered md devices.
|
||||
if hardware.is_md_device(device) and _has_dracut(path):
|
||||
rd_md_uuids = ["rd.md.uuid=%s" % x['UUID']
|
||||
for x in hardware.md_get_raid_devices().values()]
|
||||
|
||||
LOG.debug("Setting rd.md.uuid kernel parameters: %s", rd_md_uuids)
|
||||
with open('%s/etc/default/grub' % path, 'r') as g:
|
||||
contents = g.read()
|
||||
with open('%s/etc/default/grub' % path, 'w') as g:
|
||||
g.write(
|
||||
re.sub(r'GRUB_CMDLINE_LINUX="(.*)"',
|
||||
r'GRUB_CMDLINE_LINUX="\1 %s"'
|
||||
% " ".join(rd_md_uuids),
|
||||
contents))
|
||||
|
||||
# Generate the grub configuration file
|
||||
utils.execute('chroot %(path)s /bin/sh -c '
|
||||
'"%(bin)s-mkconfig -o '
|
||||
|
@ -224,6 +224,24 @@ def md_restart(raid_device):
|
||||
raise errors.CommandExecutionError(error_msg)
|
||||
|
||||
|
||||
def md_get_raid_devices():
|
||||
"""Get all discovered Software RAID (md) devices
|
||||
|
||||
:return: A python dict containing details about the discovered RAID
|
||||
devices
|
||||
"""
|
||||
report = utils.execute('mdadm', '--examine', '--scan')[0]
|
||||
lines = report.splitlines()
|
||||
result = {}
|
||||
for line in lines:
|
||||
vals = shlex.split(line)
|
||||
device = vals[1]
|
||||
result[device] = {}
|
||||
for key, val in (v.split('=', 1) for v in vals[2:]):
|
||||
result[device][key] = val.strip()
|
||||
return result
|
||||
|
||||
|
||||
def _md_scan_and_assemble():
|
||||
"""Scan all md devices and assemble RAID arrays from them.
|
||||
|
||||
|
@ -92,14 +92,16 @@ class TestImageExtension(base.IronicAgentTest):
|
||||
mock_iscsi_clean.assert_called_once_with(self.fake_dev)
|
||||
|
||||
@mock.patch.object(hardware, 'is_md_device', autospec=True)
|
||||
@mock.patch.object(hardware, 'md_get_raid_devices', autospec=True)
|
||||
@mock.patch.object(os, 'environ', autospec=True)
|
||||
@mock.patch.object(image, '_get_partition', autospec=True)
|
||||
def test__install_grub2(self, mock_get_part_uuid, environ_mock,
|
||||
mock_is_md_device, mock_execute,
|
||||
mock_dispatch):
|
||||
mock_md_get_raid_devices, mock_is_md_device,
|
||||
mock_execute, mock_dispatch):
|
||||
mock_get_part_uuid.return_value = self.fake_root_part
|
||||
environ_mock.get.return_value = '/sbin'
|
||||
mock_is_md_device.side_effect = [False]
|
||||
mock_is_md_device.side_effect = [False, False]
|
||||
mock_md_get_raid_devices.return_value = {}
|
||||
image._install_grub2(self.fake_dev, self.fake_root_uuid)
|
||||
|
||||
expected = [mock.call('mount', '/dev/fake2', self.fake_dir),
|
||||
@ -136,15 +138,18 @@ class TestImageExtension(base.IronicAgentTest):
|
||||
self.assertFalse(mock_dispatch.called)
|
||||
|
||||
@mock.patch.object(hardware, 'is_md_device', autospec=True)
|
||||
@mock.patch.object(hardware, 'md_get_raid_devices', autospec=True)
|
||||
@mock.patch.object(os, 'environ', autospec=True)
|
||||
@mock.patch.object(image, '_get_partition', autospec=True)
|
||||
def test__install_grub2_prep(self, mock_get_part_uuid, environ_mock,
|
||||
mock_is_md_device, mock_execute,
|
||||
mock_dispatch):
|
||||
mock_md_get_raid_devices, mock_is_md_device,
|
||||
mock_execute, mock_dispatch):
|
||||
mock_get_part_uuid.side_effect = [self.fake_root_part,
|
||||
self.fake_prep_boot_part]
|
||||
environ_mock.get.return_value = '/sbin'
|
||||
mock_is_md_device.side_effect = [False]
|
||||
mock_is_md_device.side_effect = [False, False]
|
||||
mock_md_get_raid_devices.return_value = {}
|
||||
|
||||
image._install_grub2(self.fake_dev, self.fake_root_uuid,
|
||||
prep_boot_part_uuid=self.fake_prep_boot_part_uuid)
|
||||
|
||||
@ -185,16 +190,19 @@ class TestImageExtension(base.IronicAgentTest):
|
||||
self.assertFalse(mock_dispatch.called)
|
||||
|
||||
@mock.patch.object(hardware, 'is_md_device', autospec=True)
|
||||
@mock.patch.object(hardware, 'md_get_raid_devices', autospec=True)
|
||||
@mock.patch.object(os, 'environ', autospec=True)
|
||||
@mock.patch.object(os, 'makedirs', autospec=True)
|
||||
@mock.patch.object(image, '_get_partition', autospec=True)
|
||||
def test__install_grub2_uefi(self, mock_get_part_uuid, mkdir_mock,
|
||||
environ_mock, mock_is_md_device,
|
||||
mock_execute, mock_dispatch):
|
||||
environ_mock, mock_md_get_raid_devices,
|
||||
mock_is_md_device, mock_execute,
|
||||
mock_dispatch):
|
||||
mock_get_part_uuid.side_effect = [self.fake_root_part,
|
||||
self.fake_efi_system_part]
|
||||
environ_mock.get.return_value = '/sbin'
|
||||
mock_is_md_device.return_value = False
|
||||
mock_md_get_raid_devices.return_value = {}
|
||||
|
||||
image._install_grub2(
|
||||
self.fake_dev, root_uuid=self.fake_root_uuid,
|
||||
@ -245,15 +253,18 @@ class TestImageExtension(base.IronicAgentTest):
|
||||
self.assertFalse(mock_dispatch.called)
|
||||
|
||||
@mock.patch.object(hardware, 'is_md_device', autospec=True)
|
||||
@mock.patch.object(hardware, 'md_get_raid_devices', autospec=True)
|
||||
@mock.patch.object(os, 'environ', autospec=True)
|
||||
@mock.patch.object(os, 'makedirs', autospec=True)
|
||||
@mock.patch.object(image, '_get_partition', autospec=True)
|
||||
def test__install_grub2_uefi_umount_fails(
|
||||
self, mock_get_part_uuid, mkdir_mock, environ_mock,
|
||||
mock_is_md_device, mock_execute, mock_dispatch):
|
||||
mock_md_get_raid_devices, mock_is_md_device, mock_execute,
|
||||
mock_dispatch):
|
||||
mock_get_part_uuid.side_effect = [self.fake_root_part,
|
||||
self.fake_efi_system_part]
|
||||
mock_is_md_device.return_value = False
|
||||
mock_md_get_raid_devices.return_value = {}
|
||||
|
||||
def umount_raise_func(*args, **kwargs):
|
||||
if args[0] == 'umount':
|
||||
@ -295,15 +306,18 @@ class TestImageExtension(base.IronicAgentTest):
|
||||
mock_execute.assert_has_calls(expected)
|
||||
|
||||
@mock.patch.object(hardware, 'is_md_device', autospec=True)
|
||||
@mock.patch.object(hardware, 'md_get_raid_devices', autospec=True)
|
||||
@mock.patch.object(os, 'environ', autospec=True)
|
||||
@mock.patch.object(os, 'makedirs', autospec=True)
|
||||
@mock.patch.object(image, '_get_partition', autospec=True)
|
||||
def test__install_grub2_uefi_mount_fails(
|
||||
self, mock_get_part_uuid, mkdir_mock, environ_mock,
|
||||
mock_is_md_device, mock_execute, mock_dispatch):
|
||||
mock_is_md_device, mock_md_get_raid_devices, mock_execute,
|
||||
mock_dispatch):
|
||||
mock_get_part_uuid.side_effect = [self.fake_root_part,
|
||||
self.fake_efi_system_part]
|
||||
mock_is_md_device.side_effect = [False]
|
||||
mock_is_md_device.side_effect = [False, False]
|
||||
mock_md_get_raid_devices.return_value = {}
|
||||
|
||||
def mount_raise_func(*args, **kwargs):
|
||||
if args[0] == 'mount':
|
||||
@ -345,7 +359,7 @@ class TestImageExtension(base.IronicAgentTest):
|
||||
@mock.patch.object(hardware, 'is_md_device', autospec=True)
|
||||
def test__get_partition(self, mock_is_md_device, mock_execute,
|
||||
mock_dispatch):
|
||||
mock_is_md_device.side_effect = [False]
|
||||
mock_is_md_device.side_effect = [False, False]
|
||||
lsblk_output = ('''KNAME="test" UUID="" TYPE="disk"
|
||||
KNAME="test1" UUID="256a39e3-ca3c-4fb8-9cc2-b32eec441f47" TYPE="part"
|
||||
KNAME="test2" UUID="%s" TYPE="part"''' % self.fake_root_uuid)
|
||||
@ -364,7 +378,7 @@ class TestImageExtension(base.IronicAgentTest):
|
||||
@mock.patch.object(hardware, 'is_md_device', autospec=True)
|
||||
def test__get_partition_no_device_found(self, mock_is_md_device,
|
||||
mock_execute, mock_dispatch):
|
||||
mock_is_md_device.side_effect = [False]
|
||||
mock_is_md_device.side_effect = [False, False]
|
||||
lsblk_output = ('''KNAME="test" UUID="" TYPE="disk"
|
||||
KNAME="test1" UUID="256a39e3-ca3c-4fb8-9cc2-b32eec441f47" TYPE="part"
|
||||
KNAME="test2" UUID="" TYPE="part"''')
|
||||
@ -384,7 +398,7 @@ class TestImageExtension(base.IronicAgentTest):
|
||||
@mock.patch.object(hardware, 'is_md_device', autospec=True)
|
||||
def test__get_partition_command_fail(self, mock_is_md_device,
|
||||
mock_execute, mock_dispatch):
|
||||
mock_is_md_device.side_effect = [False]
|
||||
mock_is_md_device.side_effect = [False, False]
|
||||
mock_execute.side_effect = (None, None,
|
||||
processutils.ProcessExecutionError('boom'))
|
||||
self.assertRaises(errors.CommandExecutionError,
|
||||
@ -402,7 +416,7 @@ class TestImageExtension(base.IronicAgentTest):
|
||||
@mock.patch.object(hardware, 'is_md_device', autospec=True)
|
||||
def test__get_partition_partuuid(self, mock_is_md_device, mock_execute,
|
||||
mock_dispatch):
|
||||
mock_is_md_device.side_effect = [False]
|
||||
mock_is_md_device.side_effect = [False, False]
|
||||
lsblk_output = ('''KNAME="test" UUID="" TYPE="disk"
|
||||
KNAME="test1" UUID="256a39e3-ca3c-4fb8-9cc2-b32eec441f47" TYPE="part"
|
||||
KNAME="test2" PARTUUID="%s" TYPE="part"''' % self.fake_root_uuid)
|
||||
|
Loading…
Reference in New Issue
Block a user