Local boot support for IPA
This patch adds support for local boot when using the IPA ramdisk, it also make sure it clear the PXE configurations and set the node to boot from disk permanently as part for the deployment if local boot is set. Implement blueprint local-boot-support-with-partition-images Depends-On: Ia588aafc240b55119c02f1254addc0cf796f88c5 Change-Id: I22c877100a19fe5147464bce589c8922f0bf3f1e
This commit is contained in:
parent
d87309e6f3
commit
efed216157
|
@ -105,3 +105,11 @@ class AgentClient(object):
|
|||
method='iscsi.start_iscsi_target',
|
||||
params=params,
|
||||
wait=True)
|
||||
|
||||
def install_bootloader(self, node, root_uuid):
|
||||
"""Install a boot loader on the image."""
|
||||
params = {'root_uuid': root_uuid}
|
||||
return self._command(node=node,
|
||||
method='image.install_bootloader',
|
||||
params=params,
|
||||
wait=True)
|
||||
|
|
|
@ -616,9 +616,32 @@ class VendorPassthru(agent_base_vendor.BaseAgentVendor):
|
|||
node.driver_internal_info = driver_internal_info
|
||||
node.save()
|
||||
|
||||
pxe_config_path = pxe_utils.get_pxe_config_file_path(node.uuid)
|
||||
deploy_utils.switch_pxe_config(pxe_config_path, root_uuid,
|
||||
driver_utils.get_node_capability(node, 'boot_mode'))
|
||||
if iscsi_deploy.get_boot_option(node) == "local":
|
||||
# Install the boot loader
|
||||
result = self._client.install_bootloader(node, root_uuid)
|
||||
if result['command_status'] == 'FAILED':
|
||||
msg = (_("Failed to install a bootloader when "
|
||||
"deploying node %(node)s. Error: %(error)s") %
|
||||
{'node': node.uuid,
|
||||
'error': result['command_error']})
|
||||
self._log_and_raise_deployment_error(task, msg)
|
||||
|
||||
try:
|
||||
try_set_boot_device(task, boot_devices.DISK)
|
||||
except Exception as e:
|
||||
msg = (_("Failed to change the boot device to %(boot_dev)s "
|
||||
"when deploying node %(node)s. Error: %(error)s") %
|
||||
{'boot_dev': boot_devices.DISK, 'node': node.uuid,
|
||||
'error': e})
|
||||
self._log_and_raise_deployment_error(task, msg)
|
||||
|
||||
# If it's going to boot from the local disk, get rid of
|
||||
# the PXE configuration files used for the deployment
|
||||
pxe_utils.clean_up_pxe_config(task)
|
||||
else:
|
||||
pxe_config_path = pxe_utils.get_pxe_config_file_path(node.uuid)
|
||||
deploy_utils.switch_pxe_config(pxe_config_path, root_uuid,
|
||||
driver_utils.get_node_capability(node, 'boot_mode'))
|
||||
|
||||
try:
|
||||
manager_utils.node_power_action(task, states.REBOOT)
|
||||
|
|
|
@ -134,3 +134,15 @@ class TestAgentClient(base.TestCase):
|
|||
method='iscsi.start_iscsi_target',
|
||||
params=params,
|
||||
wait=True)
|
||||
|
||||
@mock.patch('uuid.uuid4', mock.MagicMock(return_value='uuid'))
|
||||
def test_start_install_bootloader(self):
|
||||
self.client._command = mock.Mock()
|
||||
root_uuid = 'fake-root-uuid'
|
||||
params = {'root_uuid': root_uuid}
|
||||
|
||||
self.client.install_bootloader(self.node, root_uuid)
|
||||
self.client._command.assert_called_once_with(node=self.node,
|
||||
method='image.install_bootloader',
|
||||
params=params,
|
||||
wait=True)
|
||||
|
|
|
@ -979,14 +979,14 @@ class TestAgentVendorPassthru(db_base.DbTestCase):
|
|||
def test_continue_deploy_command_failed(self, mock_image_info,
|
||||
mock_pxe_opts, mock_start_iscsi,
|
||||
mock_cont_deploy):
|
||||
command_error = 'Gotham city is in danger!'
|
||||
mock_start_iscsi.return_value = {'command_error': command_error,
|
||||
'command_status': 'FAILED'}
|
||||
mock_pxe_opts.return_value = {'iscsi_target_iqn': 'fake-iqn',
|
||||
'deployment_key': 'fake-deploy-key'}
|
||||
mock_start_iscsi.return_value = {'command_error':
|
||||
'Gotham city is in danger!',
|
||||
'command_status': 'FAILED'}
|
||||
result = self.assertRaises(exception.InstanceDeployFailure,
|
||||
self.driver.vendor.continue_deploy, self.task)
|
||||
self.assertIn("Gotham city is in danger!", result.format_message())
|
||||
self.assertIn(command_error, result.format_message())
|
||||
mock_image_info.assert_called_once_with(self.node, self.context)
|
||||
mock_pxe_opts.assert_called_once_with(self.task.node, mock.ANY,
|
||||
self.task.context)
|
||||
|
@ -1038,3 +1038,96 @@ class TestAgentVendorPassthru(db_base.DbTestCase):
|
|||
mock_start_iscsi.assert_called_once_with(self.node, 'fake-iqn')
|
||||
self.assertNotIn('root_uuid', self.node.driver_internal_info)
|
||||
self.assertIsNotNone(self.node.last_error)
|
||||
|
||||
@mock.patch.object(pxe_utils, 'clean_up_pxe_config')
|
||||
@mock.patch.object(manager_utils, 'node_set_boot_device')
|
||||
@mock.patch.object(agent_client.AgentClient, 'install_bootloader')
|
||||
@mock.patch.object(deploy_utils, 'switch_pxe_config')
|
||||
@mock.patch.object(manager_utils, 'node_power_action')
|
||||
def test_continue_deploy_localboot(self, mock_node_power, mock_pxe_config,
|
||||
mock_install_bootloader, mock_boot_dev,
|
||||
mock_clean_pxe, mock_image_info, mock_pxe_opts,
|
||||
mock_start_iscsi, mock_cont_deploy):
|
||||
mock_pxe_opts.return_value = {'iscsi_target_iqn': 'fake-iqn',
|
||||
'deployment_key': 'fake-deploy-key'}
|
||||
mock_start_iscsi.return_value = {'command_error': None,
|
||||
'command_status': 'SUCCEEDED'}
|
||||
mock_cont_deploy.return_value = 'fake-root-uuid'
|
||||
i_info = self.node.instance_info
|
||||
i_info['capabilities'] = {'boot_option': 'local'}
|
||||
mock_install_bootloader.return_value = {'command_status': 'SUCCEEDED'}
|
||||
self.driver.vendor.continue_deploy(self.task)
|
||||
|
||||
mock_image_info.assert_called_once_with(self.node, self.context)
|
||||
mock_pxe_opts.assert_called_once_with(self.task.node, mock.ANY,
|
||||
self.task.context)
|
||||
mock_start_iscsi.assert_called_once_with(self.node, 'fake-iqn')
|
||||
self.assertIn('root_uuid', self.node.driver_internal_info)
|
||||
mock_node_power.assert_called_once_with(self.task, states.REBOOT)
|
||||
mock_install_bootloader.assert_called_once_with(self.node,
|
||||
'fake-root-uuid')
|
||||
self.assertIsNone(self.node.last_error)
|
||||
# Assert we clean up the PXE configuration and make set the boot
|
||||
# device to boot from disk
|
||||
mock_clean_pxe.assert_called_once_with(self.task)
|
||||
mock_boot_dev.assert_called_once_with(self.task, boot_devices.DISK,
|
||||
persistent=True)
|
||||
|
||||
# Assert we dont try to switch the PXE configuration
|
||||
self.assertFalse(mock_pxe_config.called)
|
||||
|
||||
@mock.patch.object(agent_client.AgentClient, 'install_bootloader')
|
||||
def test_continue_deploy_localboot_command_failed(self,
|
||||
mock_install_bootloader, mock_image_info,
|
||||
mock_pxe_opts, mock_start_iscsi,
|
||||
mock_cont_deploy):
|
||||
command_error = 'Gotham city is in danger!'
|
||||
mock_install_bootloader.return_value = {'command_error': command_error,
|
||||
'command_status': 'FAILED'}
|
||||
mock_pxe_opts.return_value = {'iscsi_target_iqn': 'fake-iqn',
|
||||
'deployment_key': 'fake-deploy-key'}
|
||||
mock_start_iscsi.return_value = {'command_error': None,
|
||||
'command_status': 'SUCCEEDED'}
|
||||
mock_cont_deploy.return_value = 'fake-root-uuid'
|
||||
i_info = self.node.instance_info
|
||||
i_info['capabilities'] = {'boot_option': 'local'}
|
||||
|
||||
result = self.assertRaises(exception.InstanceDeployFailure,
|
||||
self.driver.vendor.continue_deploy, self.task)
|
||||
self.assertIn(command_error, result.format_message())
|
||||
mock_image_info.assert_called_once_with(self.node, self.context)
|
||||
mock_pxe_opts.assert_called_once_with(self.task.node, mock.ANY,
|
||||
self.task.context)
|
||||
mock_start_iscsi.assert_called_once_with(self.node, 'fake-iqn')
|
||||
mock_install_bootloader.assert_called_once_with(self.node,
|
||||
'fake-root-uuid')
|
||||
self.assertIsNotNone(self.node.last_error)
|
||||
|
||||
@mock.patch.object(pxe, 'try_set_boot_device')
|
||||
@mock.patch.object(agent_client.AgentClient, 'install_bootloader')
|
||||
def test_continue_deploy_set_boot_device_failed(self,
|
||||
mock_install_bootloader, mock_set_boot_dev,
|
||||
mock_image_info, mock_pxe_opts, mock_start_iscsi,
|
||||
mock_cont_deploy):
|
||||
error_msg = "User error. Please replace the user."
|
||||
mock_set_boot_dev.side_effect = exception.IPMIFailure(error_msg)
|
||||
mock_install_bootloader.return_value = {'command_error': None,
|
||||
'command_status': 'SUCCEEDED'}
|
||||
mock_pxe_opts.return_value = {'iscsi_target_iqn': 'fake-iqn',
|
||||
'deployment_key': 'fake-deploy-key'}
|
||||
mock_start_iscsi.return_value = {'command_error': None,
|
||||
'command_status': 'SUCCEEDED'}
|
||||
mock_cont_deploy.return_value = 'fake-root-uuid'
|
||||
i_info = self.node.instance_info
|
||||
i_info['capabilities'] = {'boot_option': 'local'}
|
||||
|
||||
result = self.assertRaises(exception.InstanceDeployFailure,
|
||||
self.driver.vendor.continue_deploy, self.task)
|
||||
self.assertIn(error_msg, result.format_message())
|
||||
mock_image_info.assert_called_once_with(self.node, self.context)
|
||||
mock_pxe_opts.assert_called_once_with(self.task.node, mock.ANY,
|
||||
self.task.context)
|
||||
mock_start_iscsi.assert_called_once_with(self.node, 'fake-iqn')
|
||||
mock_install_bootloader.assert_called_once_with(self.node,
|
||||
'fake-root-uuid')
|
||||
self.assertIsNotNone(self.node.last_error)
|
||||
|
|
Loading…
Reference in New Issue