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.
|
on encountering error while setting the boot device on the node.
|
||||||
"""
|
"""
|
||||||
node = task.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)
|
LOG.debug('Configuring local boot for node %s', node.uuid)
|
||||||
|
|
||||||
# If the target RAID configuration is set to 'software' for the
|
# If the target RAID configuration is set to 'software' for the
|
||||||
@ -1091,7 +1094,9 @@ class AgentDeployMixin(HeartbeatMixin):
|
|||||||
result = self._client.install_bootloader(
|
result = self._client.install_bootloader(
|
||||||
node, root_uuid=root_uuid,
|
node, root_uuid=root_uuid,
|
||||||
efi_system_part_uuid=efi_system_part_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 result['command_status'] == 'FAILED':
|
||||||
if not whole_disk_image:
|
if not whole_disk_image:
|
||||||
msg = (_("Failed to install a bootloader when "
|
msg = (_("Failed to install a bootloader when "
|
||||||
|
@ -259,12 +259,14 @@ class AgentClient(object):
|
|||||||
wait=True)
|
wait=True)
|
||||||
|
|
||||||
@METRICS.timer('AgentClient.install_bootloader')
|
@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):
|
prep_boot_part_uuid=None):
|
||||||
"""Install a boot loader on the image.
|
"""Install a boot loader on the image.
|
||||||
|
|
||||||
:param node: A node object.
|
:param node: A node object.
|
||||||
:param root_uuid: The UUID of the root partition.
|
: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
|
:param efi_system_part_uuid: The UUID of the efi system partition
|
||||||
where the bootloader will be installed to, only used for uefi
|
where the bootloader will be installed to, only used for uefi
|
||||||
boot mode.
|
boot mode.
|
||||||
@ -279,7 +281,9 @@ class AgentClient(object):
|
|||||||
"""
|
"""
|
||||||
params = {'root_uuid': root_uuid,
|
params = {'root_uuid': root_uuid,
|
||||||
'efi_system_part_uuid': efi_system_part_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
|
# NOTE(TheJulia): This command explicitly sends a larger timeout
|
||||||
# factor to the _command call such that the agent ramdisk has enough
|
# factor to the _command call such that the agent ramdisk has enough
|
||||||
@ -289,6 +293,29 @@ class AgentClient(object):
|
|||||||
# compatible. We could at least begin to delineate the commands apart
|
# 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
|
# over the next cycle or two so we don't need a command timeout
|
||||||
# extension factor.
|
# extension factor.
|
||||||
|
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,
|
return self._command(node=node,
|
||||||
method='image.install_bootloader',
|
method='image.install_bootloader',
|
||||||
params=params,
|
params=params,
|
||||||
|
@ -1084,7 +1084,10 @@ class AgentDeployMixinTest(AgentDeployMixinBaseTest):
|
|||||||
@mock.patch.object(agent_client.AgentClient, 'install_bootloader',
|
@mock.patch.object(agent_client.AgentClient, 'install_bootloader',
|
||||||
autospec=True)
|
autospec=True)
|
||||||
@mock.patch.object(deploy_utils, 'try_set_boot_device', 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):
|
||||||
install_bootloader_mock.return_value = {
|
install_bootloader_mock.return_value = {
|
||||||
'command_status': 'SUCCESS', 'command_error': None}
|
'command_status': 'SUCCESS', 'command_error': None}
|
||||||
@ -1094,17 +1097,24 @@ class AgentDeployMixinTest(AgentDeployMixinBaseTest):
|
|||||||
self.deploy.configure_local_boot(task, root_uuid='some-root-uuid')
|
self.deploy.configure_local_boot(task, root_uuid='some-root-uuid')
|
||||||
try_set_boot_device_mock.assert_called_once_with(
|
try_set_boot_device_mock.assert_called_once_with(
|
||||||
task, boot_devices.DISK, persistent=True)
|
task, boot_devices.DISK, persistent=True)
|
||||||
|
boot_mode_mock.assert_called_once_with(task.node)
|
||||||
install_bootloader_mock.assert_called_once_with(
|
install_bootloader_mock.assert_called_once_with(
|
||||||
mock.ANY, task.node, root_uuid='some-root-uuid',
|
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',
|
@mock.patch.object(agent_client.AgentClient, 'install_bootloader',
|
||||||
autospec=True)
|
autospec=True)
|
||||||
@mock.patch.object(deploy_utils, 'try_set_boot_device', 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):
|
||||||
install_bootloader_mock.return_value = {
|
install_bootloader_mock.return_value = {
|
||||||
'command_status': 'SUCCESS', 'command_error': None}
|
'command_status': 'SUCCESS', 'command_error': None}
|
||||||
|
|
||||||
with task_manager.acquire(self.context, self.node['uuid'],
|
with task_manager.acquire(self.context, self.node['uuid'],
|
||||||
shared=False) as task:
|
shared=False) as task:
|
||||||
task.node.driver_internal_info['is_whole_disk_image'] = False
|
task.node.driver_internal_info['is_whole_disk_image'] = False
|
||||||
@ -1112,14 +1122,20 @@ class AgentDeployMixinTest(AgentDeployMixinBaseTest):
|
|||||||
prep_boot_part_uuid='fake-prep')
|
prep_boot_part_uuid='fake-prep')
|
||||||
try_set_boot_device_mock.assert_called_once_with(
|
try_set_boot_device_mock.assert_called_once_with(
|
||||||
task, boot_devices.DISK, persistent=True)
|
task, boot_devices.DISK, persistent=True)
|
||||||
|
boot_mode_mock.assert_called_once_with(task.node)
|
||||||
install_bootloader_mock.assert_called_once_with(
|
install_bootloader_mock.assert_called_once_with(
|
||||||
mock.ANY, task.node, root_uuid='some-root-uuid',
|
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',
|
@mock.patch.object(agent_client.AgentClient, 'install_bootloader',
|
||||||
autospec=True)
|
autospec=True)
|
||||||
@mock.patch.object(deploy_utils, 'try_set_boot_device', 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):
|
||||||
install_bootloader_mock.return_value = {
|
install_bootloader_mock.return_value = {
|
||||||
'command_status': 'SUCCESS', 'command_error': None}
|
'command_status': 'SUCCESS', 'command_error': None}
|
||||||
@ -1131,10 +1147,13 @@ class AgentDeployMixinTest(AgentDeployMixinBaseTest):
|
|||||||
efi_system_part_uuid='efi-system-part-uuid')
|
efi_system_part_uuid='efi-system-part-uuid')
|
||||||
try_set_boot_device_mock.assert_called_once_with(
|
try_set_boot_device_mock.assert_called_once_with(
|
||||||
task, boot_devices.DISK, persistent=True)
|
task, boot_devices.DISK, persistent=True)
|
||||||
|
boot_mode_mock.assert_called_once_with(task.node)
|
||||||
install_bootloader_mock.assert_called_once_with(
|
install_bootloader_mock.assert_called_once_with(
|
||||||
mock.ANY, task.node, root_uuid='some-root-uuid',
|
mock.ANY, task.node, root_uuid='some-root-uuid',
|
||||||
efi_system_part_uuid='efi-system-part-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(deploy_utils, 'try_set_boot_device', autospec=True)
|
||||||
@mock.patch.object(agent_client.AgentClient, 'install_bootloader',
|
@mock.patch.object(agent_client.AgentClient, 'install_bootloader',
|
||||||
@ -1180,7 +1199,7 @@ class AgentDeployMixinTest(AgentDeployMixinBaseTest):
|
|||||||
install_bootloader_mock.assert_called_once_with(
|
install_bootloader_mock.assert_called_once_with(
|
||||||
mock.ANY, task.node, root_uuid=None,
|
mock.ANY, task.node, root_uuid=None,
|
||||||
efi_system_part_uuid='efi-system-part-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(image_service, 'GlanceImageService', autospec=True)
|
@mock.patch.object(image_service, 'GlanceImageService', autospec=True)
|
||||||
@mock.patch.object(deploy_utils, 'try_set_boot_device', 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
|
# check if the root_uuid comes from the driver_internal_info
|
||||||
install_bootloader_mock.assert_called_once_with(
|
install_bootloader_mock.assert_called_once_with(
|
||||||
mock.ANY, task.node, root_uuid=root_uuid,
|
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(
|
try_set_boot_device_mock.assert_called_once_with(
|
||||||
task, boot_devices.DISK, persistent=True)
|
task, boot_devices.DISK, persistent=True)
|
||||||
|
|
||||||
@ -1326,8 +1346,11 @@ class AgentDeployMixinTest(AgentDeployMixinBaseTest):
|
|||||||
autospec=True)
|
autospec=True)
|
||||||
@mock.patch.object(agent_client.AgentClient, 'install_bootloader',
|
@mock.patch.object(agent_client.AgentClient, 'install_bootloader',
|
||||||
autospec=True)
|
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(
|
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 = {
|
install_bootloader_mock.return_value = {
|
||||||
'command_status': 'FAILED', 'command_error': 'boom'}
|
'command_status': 'FAILED', 'command_error': 'boom'}
|
||||||
self.node.provision_state = states.DEPLOYING
|
self.node.provision_state = states.DEPLOYING
|
||||||
@ -1339,9 +1362,12 @@ class AgentDeployMixinTest(AgentDeployMixinBaseTest):
|
|||||||
self.assertRaises(exception.InstanceDeployFailure,
|
self.assertRaises(exception.InstanceDeployFailure,
|
||||||
self.deploy.configure_local_boot,
|
self.deploy.configure_local_boot,
|
||||||
task, root_uuid='some-root-uuid')
|
task, root_uuid='some-root-uuid')
|
||||||
|
boot_mode_mock.assert_called_once_with(task.node)
|
||||||
install_bootloader_mock.assert_called_once_with(
|
install_bootloader_mock.assert_called_once_with(
|
||||||
mock.ANY, task.node, root_uuid='some-root-uuid',
|
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)
|
collect_logs_mock.assert_called_once_with(mock.ANY, task.node)
|
||||||
self.assertEqual(states.DEPLOYFAIL, task.node.provision_state)
|
self.assertEqual(states.DEPLOYFAIL, task.node.provision_state)
|
||||||
self.assertEqual(states.ACTIVE, task.node.target_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(deploy_utils, 'try_set_boot_device', autospec=True)
|
||||||
@mock.patch.object(agent_client.AgentClient, 'install_bootloader',
|
@mock.patch.object(agent_client.AgentClient, 'install_bootloader',
|
||||||
autospec=True)
|
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(
|
def test_configure_local_boot_set_boot_device_fail(
|
||||||
self, install_bootloader_mock, try_set_boot_device_mock,
|
self, boot_mode_mock, install_bootloader_mock,
|
||||||
collect_logs_mock):
|
try_set_boot_device_mock, collect_logs_mock):
|
||||||
install_bootloader_mock.return_value = {
|
install_bootloader_mock.return_value = {
|
||||||
'command_status': 'SUCCESS', 'command_error': None}
|
'command_status': 'SUCCESS', 'command_error': None}
|
||||||
try_set_boot_device_mock.side_effect = RuntimeError('error')
|
try_set_boot_device_mock.side_effect = RuntimeError('error')
|
||||||
@ -1367,9 +1395,11 @@ class AgentDeployMixinTest(AgentDeployMixinBaseTest):
|
|||||||
self.deploy.configure_local_boot,
|
self.deploy.configure_local_boot,
|
||||||
task, root_uuid='some-root-uuid',
|
task, root_uuid='some-root-uuid',
|
||||||
prep_boot_part_uuid=None)
|
prep_boot_part_uuid=None)
|
||||||
|
boot_mode_mock.assert_called_once_with(task.node)
|
||||||
install_bootloader_mock.assert_called_once_with(
|
install_bootloader_mock.assert_called_once_with(
|
||||||
mock.ANY, task.node, root_uuid='some-root-uuid',
|
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(
|
try_set_boot_device_mock.assert_called_once_with(
|
||||||
task, boot_devices.DISK, persistent=True)
|
task, boot_devices.DISK, persistent=True)
|
||||||
collect_logs_mock.assert_called_once_with(mock.ANY, task.node)
|
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=[])
|
self.client._command = mock.MagicMock(spec_set=[])
|
||||||
params = {'root_uuid': root_uuid,
|
params = {'root_uuid': root_uuid,
|
||||||
'efi_system_part_uuid': efi_system_part_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.client.install_bootloader(
|
||||||
self.node, root_uuid, efi_system_part_uuid=efi_system_part_uuid,
|
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(
|
self.client._command.assert_called_once_with(
|
||||||
command_timeout_factor=2, node=self.node,
|
command_timeout_factor=2, node=self.node,
|
||||||
method='image.install_bootloader', params=params,
|
method='image.install_bootloader', params=params,
|
||||||
@ -290,7 +291,7 @@ class TestAgentClient(base.TestCase):
|
|||||||
self._test_install_bootloader(root_uuid='fake-root-uuid',
|
self._test_install_bootloader(root_uuid='fake-root-uuid',
|
||||||
efi_system_part_uuid='fake-efi-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',
|
self._test_install_bootloader(root_uuid='fake-root-uuid',
|
||||||
efi_system_part_uuid='fake-efi-uuid',
|
efi_system_part_uuid='fake-efi-uuid',
|
||||||
prep_boot_part_uuid='fake-prep-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