Merge "Software RAID: Pass the boot mode to the IPA"
This commit is contained in:
commit
fcea89a016
@ -1037,6 +1037,9 @@ class AgentDeployMixin(HeartbeatMixin):
|
||||
on encountering error while setting the boot device on the node.
|
||||
"""
|
||||
node = task.node
|
||||
# Almost never taken into account on agent side, just used for softraid
|
||||
# Can be useful with whole_disk_images
|
||||
target_boot_mode = boot_mode_utils.get_boot_mode(task.node)
|
||||
LOG.debug('Configuring local boot for node %s', node.uuid)
|
||||
|
||||
# If the target RAID configuration is set to 'software' for the
|
||||
@ -1091,7 +1094,9 @@ class AgentDeployMixin(HeartbeatMixin):
|
||||
result = self._client.install_bootloader(
|
||||
node, root_uuid=root_uuid,
|
||||
efi_system_part_uuid=efi_system_part_uuid,
|
||||
prep_boot_part_uuid=prep_boot_part_uuid)
|
||||
prep_boot_part_uuid=prep_boot_part_uuid,
|
||||
target_boot_mode=target_boot_mode
|
||||
)
|
||||
if result['command_status'] == 'FAILED':
|
||||
if not whole_disk_image:
|
||||
msg = (_("Failed to install a bootloader when "
|
||||
|
@ -259,12 +259,14 @@ class AgentClient(object):
|
||||
wait=True)
|
||||
|
||||
@METRICS.timer('AgentClient.install_bootloader')
|
||||
def install_bootloader(self, node, root_uuid, efi_system_part_uuid=None,
|
||||
def install_bootloader(self, node, root_uuid, target_boot_mode,
|
||||
efi_system_part_uuid=None,
|
||||
prep_boot_part_uuid=None):
|
||||
"""Install a boot loader on the image.
|
||||
|
||||
:param node: A node object.
|
||||
:param root_uuid: The UUID of the root partition.
|
||||
:param target_boot_mode: The target deployment boot mode.
|
||||
:param efi_system_part_uuid: The UUID of the efi system partition
|
||||
where the bootloader will be installed to, only used for uefi
|
||||
boot mode.
|
||||
@ -279,7 +281,9 @@ class AgentClient(object):
|
||||
"""
|
||||
params = {'root_uuid': root_uuid,
|
||||
'efi_system_part_uuid': efi_system_part_uuid,
|
||||
'prep_boot_part_uuid': prep_boot_part_uuid}
|
||||
'prep_boot_part_uuid': prep_boot_part_uuid,
|
||||
'target_boot_mode': target_boot_mode
|
||||
}
|
||||
|
||||
# NOTE(TheJulia): This command explicitly sends a larger timeout
|
||||
# factor to the _command call such that the agent ramdisk has enough
|
||||
@ -289,11 +293,34 @@ class AgentClient(object):
|
||||
# compatible. We could at least begin to delineate the commands apart
|
||||
# over the next cycle or two so we don't need a command timeout
|
||||
# extension factor.
|
||||
return self._command(node=node,
|
||||
method='image.install_bootloader',
|
||||
params=params,
|
||||
wait=True,
|
||||
command_timeout_factor=2)
|
||||
try:
|
||||
return self._command(node=node,
|
||||
method='image.install_bootloader',
|
||||
params=params,
|
||||
wait=True,
|
||||
command_timeout_factor=2)
|
||||
except exception.AgentAPIError:
|
||||
# NOTE(arne_wiebalck): If we require to pass 'uefi' as the boot
|
||||
# mode, but find that the IPA does not yet support the additional
|
||||
# 'target_boot_mode' parameter, we need to fail. For 'bios' boot
|
||||
# mode on the other hand we can retry without the parameter,
|
||||
# since 'bios' is the default value the IPA will use.
|
||||
if target_boot_mode == 'uefi':
|
||||
LOG.error('Unable to pass UEFI boot mode to an out of date '
|
||||
'agent ramdisk. Please contact the administrator '
|
||||
'to update the ramdisk to contain an '
|
||||
'ironic-python-agent version of at least 6.0.0.')
|
||||
raise
|
||||
else:
|
||||
params = {'root_uuid': root_uuid,
|
||||
'efi_system_part_uuid': efi_system_part_uuid,
|
||||
'prep_boot_part_uuid': prep_boot_part_uuid
|
||||
}
|
||||
return self._command(node=node,
|
||||
method='image.install_bootloader',
|
||||
params=params,
|
||||
wait=True,
|
||||
command_timeout_factor=2)
|
||||
|
||||
@METRICS.timer('AgentClient.get_clean_steps')
|
||||
def get_clean_steps(self, node, ports):
|
||||
|
@ -1084,7 +1084,10 @@ class AgentDeployMixinTest(AgentDeployMixinBaseTest):
|
||||
@mock.patch.object(agent_client.AgentClient, 'install_bootloader',
|
||||
autospec=True)
|
||||
@mock.patch.object(deploy_utils, 'try_set_boot_device', autospec=True)
|
||||
def test_configure_local_boot(self, try_set_boot_device_mock,
|
||||
@mock.patch.object(boot_mode_utils, 'get_boot_mode', autospec=True,
|
||||
return_value='whatever')
|
||||
def test_configure_local_boot(self, boot_mode_mock,
|
||||
try_set_boot_device_mock,
|
||||
install_bootloader_mock):
|
||||
install_bootloader_mock.return_value = {
|
||||
'command_status': 'SUCCESS', 'command_error': None}
|
||||
@ -1094,17 +1097,24 @@ class AgentDeployMixinTest(AgentDeployMixinBaseTest):
|
||||
self.deploy.configure_local_boot(task, root_uuid='some-root-uuid')
|
||||
try_set_boot_device_mock.assert_called_once_with(
|
||||
task, boot_devices.DISK, persistent=True)
|
||||
boot_mode_mock.assert_called_once_with(task.node)
|
||||
install_bootloader_mock.assert_called_once_with(
|
||||
mock.ANY, task.node, root_uuid='some-root-uuid',
|
||||
efi_system_part_uuid=None, prep_boot_part_uuid=None)
|
||||
efi_system_part_uuid=None, prep_boot_part_uuid=None,
|
||||
target_boot_mode='whatever'
|
||||
)
|
||||
|
||||
@mock.patch.object(agent_client.AgentClient, 'install_bootloader',
|
||||
autospec=True)
|
||||
@mock.patch.object(deploy_utils, 'try_set_boot_device', autospec=True)
|
||||
def test_configure_local_boot_with_prep(self, try_set_boot_device_mock,
|
||||
@mock.patch.object(boot_mode_utils, 'get_boot_mode', autospec=True,
|
||||
return_value='whatever')
|
||||
def test_configure_local_boot_with_prep(self, boot_mode_mock,
|
||||
try_set_boot_device_mock,
|
||||
install_bootloader_mock):
|
||||
install_bootloader_mock.return_value = {
|
||||
'command_status': 'SUCCESS', 'command_error': None}
|
||||
|
||||
with task_manager.acquire(self.context, self.node['uuid'],
|
||||
shared=False) as task:
|
||||
task.node.driver_internal_info['is_whole_disk_image'] = False
|
||||
@ -1112,14 +1122,20 @@ class AgentDeployMixinTest(AgentDeployMixinBaseTest):
|
||||
prep_boot_part_uuid='fake-prep')
|
||||
try_set_boot_device_mock.assert_called_once_with(
|
||||
task, boot_devices.DISK, persistent=True)
|
||||
boot_mode_mock.assert_called_once_with(task.node)
|
||||
install_bootloader_mock.assert_called_once_with(
|
||||
mock.ANY, task.node, root_uuid='some-root-uuid',
|
||||
efi_system_part_uuid=None, prep_boot_part_uuid='fake-prep')
|
||||
efi_system_part_uuid=None, prep_boot_part_uuid='fake-prep',
|
||||
target_boot_mode='whatever'
|
||||
)
|
||||
|
||||
@mock.patch.object(agent_client.AgentClient, 'install_bootloader',
|
||||
autospec=True)
|
||||
@mock.patch.object(deploy_utils, 'try_set_boot_device', autospec=True)
|
||||
def test_configure_local_boot_uefi(self, try_set_boot_device_mock,
|
||||
@mock.patch.object(boot_mode_utils, 'get_boot_mode', autospec=True,
|
||||
return_value='uefi')
|
||||
def test_configure_local_boot_uefi(self, boot_mode_mock,
|
||||
try_set_boot_device_mock,
|
||||
install_bootloader_mock):
|
||||
install_bootloader_mock.return_value = {
|
||||
'command_status': 'SUCCESS', 'command_error': None}
|
||||
@ -1131,10 +1147,13 @@ class AgentDeployMixinTest(AgentDeployMixinBaseTest):
|
||||
efi_system_part_uuid='efi-system-part-uuid')
|
||||
try_set_boot_device_mock.assert_called_once_with(
|
||||
task, boot_devices.DISK, persistent=True)
|
||||
boot_mode_mock.assert_called_once_with(task.node)
|
||||
install_bootloader_mock.assert_called_once_with(
|
||||
mock.ANY, task.node, root_uuid='some-root-uuid',
|
||||
efi_system_part_uuid='efi-system-part-uuid',
|
||||
prep_boot_part_uuid=None)
|
||||
prep_boot_part_uuid=None,
|
||||
target_boot_mode='uefi'
|
||||
)
|
||||
|
||||
@mock.patch.object(deploy_utils, 'try_set_boot_device', autospec=True)
|
||||
@mock.patch.object(agent_client.AgentClient, 'install_bootloader',
|
||||
@ -1180,7 +1199,7 @@ class AgentDeployMixinTest(AgentDeployMixinBaseTest):
|
||||
install_bootloader_mock.assert_called_once_with(
|
||||
mock.ANY, task.node, root_uuid=None,
|
||||
efi_system_part_uuid='efi-system-part-uuid',
|
||||
prep_boot_part_uuid=None)
|
||||
prep_boot_part_uuid=None, target_boot_mode='uefi')
|
||||
|
||||
@mock.patch.object(image_service, 'GlanceImageService', autospec=True)
|
||||
@mock.patch.object(deploy_utils, 'try_set_boot_device', autospec=True)
|
||||
@ -1244,7 +1263,8 @@ class AgentDeployMixinTest(AgentDeployMixinBaseTest):
|
||||
# check if the root_uuid comes from the driver_internal_info
|
||||
install_bootloader_mock.assert_called_once_with(
|
||||
mock.ANY, task.node, root_uuid=root_uuid,
|
||||
efi_system_part_uuid=None, prep_boot_part_uuid=None)
|
||||
efi_system_part_uuid=None, prep_boot_part_uuid=None,
|
||||
target_boot_mode='bios')
|
||||
try_set_boot_device_mock.assert_called_once_with(
|
||||
task, boot_devices.DISK, persistent=True)
|
||||
|
||||
@ -1326,8 +1346,11 @@ class AgentDeployMixinTest(AgentDeployMixinBaseTest):
|
||||
autospec=True)
|
||||
@mock.patch.object(agent_client.AgentClient, 'install_bootloader',
|
||||
autospec=True)
|
||||
@mock.patch.object(boot_mode_utils, 'get_boot_mode', autospec=True,
|
||||
return_value='whatever')
|
||||
def test_configure_local_boot_boot_loader_install_fail(
|
||||
self, install_bootloader_mock, collect_logs_mock):
|
||||
self, boot_mode_mock, install_bootloader_mock,
|
||||
collect_logs_mock):
|
||||
install_bootloader_mock.return_value = {
|
||||
'command_status': 'FAILED', 'command_error': 'boom'}
|
||||
self.node.provision_state = states.DEPLOYING
|
||||
@ -1339,9 +1362,12 @@ class AgentDeployMixinTest(AgentDeployMixinBaseTest):
|
||||
self.assertRaises(exception.InstanceDeployFailure,
|
||||
self.deploy.configure_local_boot,
|
||||
task, root_uuid='some-root-uuid')
|
||||
boot_mode_mock.assert_called_once_with(task.node)
|
||||
install_bootloader_mock.assert_called_once_with(
|
||||
mock.ANY, task.node, root_uuid='some-root-uuid',
|
||||
efi_system_part_uuid=None, prep_boot_part_uuid=None)
|
||||
efi_system_part_uuid=None, prep_boot_part_uuid=None,
|
||||
target_boot_mode='whatever'
|
||||
)
|
||||
collect_logs_mock.assert_called_once_with(mock.ANY, task.node)
|
||||
self.assertEqual(states.DEPLOYFAIL, task.node.provision_state)
|
||||
self.assertEqual(states.ACTIVE, task.node.target_provision_state)
|
||||
@ -1351,9 +1377,11 @@ class AgentDeployMixinTest(AgentDeployMixinBaseTest):
|
||||
@mock.patch.object(deploy_utils, 'try_set_boot_device', autospec=True)
|
||||
@mock.patch.object(agent_client.AgentClient, 'install_bootloader',
|
||||
autospec=True)
|
||||
@mock.patch.object(boot_mode_utils, 'get_boot_mode', autospec=True,
|
||||
return_value='whatever')
|
||||
def test_configure_local_boot_set_boot_device_fail(
|
||||
self, install_bootloader_mock, try_set_boot_device_mock,
|
||||
collect_logs_mock):
|
||||
self, boot_mode_mock, install_bootloader_mock,
|
||||
try_set_boot_device_mock, collect_logs_mock):
|
||||
install_bootloader_mock.return_value = {
|
||||
'command_status': 'SUCCESS', 'command_error': None}
|
||||
try_set_boot_device_mock.side_effect = RuntimeError('error')
|
||||
@ -1367,9 +1395,11 @@ class AgentDeployMixinTest(AgentDeployMixinBaseTest):
|
||||
self.deploy.configure_local_boot,
|
||||
task, root_uuid='some-root-uuid',
|
||||
prep_boot_part_uuid=None)
|
||||
boot_mode_mock.assert_called_once_with(task.node)
|
||||
install_bootloader_mock.assert_called_once_with(
|
||||
mock.ANY, task.node, root_uuid='some-root-uuid',
|
||||
efi_system_part_uuid=None, prep_boot_part_uuid=None)
|
||||
efi_system_part_uuid=None, prep_boot_part_uuid=None,
|
||||
target_boot_mode='whatever')
|
||||
try_set_boot_device_mock.assert_called_once_with(
|
||||
task, boot_devices.DISK, persistent=True)
|
||||
collect_logs_mock.assert_called_once_with(mock.ANY, task.node)
|
||||
|
@ -276,11 +276,12 @@ class TestAgentClient(base.TestCase):
|
||||
self.client._command = mock.MagicMock(spec_set=[])
|
||||
params = {'root_uuid': root_uuid,
|
||||
'efi_system_part_uuid': efi_system_part_uuid,
|
||||
'prep_boot_part_uuid': prep_boot_part_uuid}
|
||||
'prep_boot_part_uuid': prep_boot_part_uuid,
|
||||
'target_boot_mode': 'hello'}
|
||||
|
||||
self.client.install_bootloader(
|
||||
self.node, root_uuid, efi_system_part_uuid=efi_system_part_uuid,
|
||||
prep_boot_part_uuid=prep_boot_part_uuid)
|
||||
prep_boot_part_uuid=prep_boot_part_uuid, target_boot_mode='hello')
|
||||
self.client._command.assert_called_once_with(
|
||||
command_timeout_factor=2, node=self.node,
|
||||
method='image.install_bootloader', params=params,
|
||||
@ -290,7 +291,7 @@ class TestAgentClient(base.TestCase):
|
||||
self._test_install_bootloader(root_uuid='fake-root-uuid',
|
||||
efi_system_part_uuid='fake-efi-uuid')
|
||||
|
||||
def test_install_bootloaderi_with_prep(self):
|
||||
def test_install_bootloader_with_prep(self):
|
||||
self._test_install_bootloader(root_uuid='fake-root-uuid',
|
||||
efi_system_part_uuid='fake-efi-uuid',
|
||||
prep_boot_part_uuid='fake-prep-uuid')
|
||||
|
@ -0,0 +1,4 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Adds support for bootable software RAID with UEFI boot mode.
|
Loading…
Reference in New Issue
Block a user