Fix provisioning failure with `ramdisk` deploy interface

Provisioning fails if ironic node is configured with ``ramdisk``
deploy interface and PXE boot config file is not present for the
node.

Change-Id: Ic3a41b252751195a60e4757fee21cb2f62c3c7c2
Story: #2003532
Task: #24817
(cherry picked from commit 9911293e68)
This commit is contained in:
Shivanand Tendulker 2018-08-23 08:46:00 -04:00 committed by Dmitry Tantsur
parent 9ceb015a0a
commit 65ab326b44
3 changed files with 100 additions and 31 deletions

View File

@ -589,6 +589,37 @@ class PXEBoot(base.BootInterface):
else:
_clean_up_pxe_env(task, images_info)
def _prepare_instance_pxe_config(self, task, image_info,
iscsi_boot=False,
ramdisk_boot=False):
"""Prepares the config file for PXE boot
:param task: a task from TaskManager.
:param image_info: a dict of values of instance image
metadata to set on the configuration file.
:param iscsi_boot: if boot is from an iSCSI volume or not.
:param ramdisk_boot: if the boot is to a ramdisk configuration.
:returns: None
"""
node = task.node
dhcp_opts = pxe_utils.dhcp_options_for_instance(task)
provider = dhcp_factory.DHCPFactory()
provider.update_dhcp(task, dhcp_opts)
pxe_config_path = pxe_utils.get_pxe_config_file_path(
node.uuid)
if not os.path.isfile(pxe_config_path):
pxe_options = _build_pxe_config_options(
task, image_info, service=ramdisk_boot)
pxe_config_template = (
deploy_utils.get_pxe_config_template(node))
pxe_utils.create_pxe_config(
task, pxe_options, pxe_config_template)
deploy_utils.switch_pxe_config(
pxe_config_path, None,
boot_mode_utils.get_boot_mode_for_deploy(node), False,
iscsi_boot=iscsi_boot, ramdisk_boot=ramdisk_boot)
@METRICS.timer('PXEBoot.prepare_instance')
def prepare_instance(self, task):
"""Prepares the boot of instance.
@ -606,40 +637,18 @@ class PXEBoot(base.BootInterface):
node = task.node
boot_option = deploy_utils.get_boot_option(node)
boot_device = None
if deploy_utils.is_iscsi_boot(task):
dhcp_opts = pxe_utils.dhcp_options_for_instance(task)
provider = dhcp_factory.DHCPFactory()
provider.update_dhcp(task, dhcp_opts)
# configure iPXE for iscsi boot
pxe_config_path = pxe_utils.get_pxe_config_file_path(
task.node.uuid)
if not os.path.isfile(pxe_config_path):
pxe_options = _build_pxe_config_options(task, {})
pxe_config_template = (
deploy_utils.get_pxe_config_template(node))
pxe_utils.create_pxe_config(
task, pxe_options, pxe_config_template)
deploy_utils.switch_pxe_config(
pxe_config_path, None,
boot_mode_utils.get_boot_mode_for_deploy(node), False,
iscsi_boot=True)
boot_device = boot_devices.PXE
elif boot_option == "ramdisk":
instance_image_info = {}
if boot_option == "ramdisk":
instance_image_info = _get_instance_image_info(
task.node, task.context)
_cache_ramdisk_kernel(task.context, task.node,
instance_image_info)
dhcp_opts = pxe_utils.dhcp_options_for_instance(task)
provider = dhcp_factory.DHCPFactory()
provider.update_dhcp(task, dhcp_opts)
pxe_config_path = pxe_utils.get_pxe_config_file_path(
task.node.uuid)
deploy_utils.switch_pxe_config(
pxe_config_path, None,
boot_mode_utils.get_boot_mode_for_deploy(node), False,
iscsi_boot=False, ramdisk_boot=True)
if deploy_utils.is_iscsi_boot(task) or boot_option == "ramdisk":
self._prepare_instance_pxe_config(
task, instance_image_info,
iscsi_boot=deploy_utils.is_iscsi_boot(task),
ramdisk_boot=(boot_option == "ramdisk"))
boot_device = boot_devices.PXE
elif boot_option != "local":

View File

@ -1400,7 +1400,7 @@ class PXEBootTestCase(db_base.DbTestCase):
task, mock.ANY, CONF.pxe.pxe_config_template)
switch_pxe_config_mock.assert_called_once_with(
pxe_config_path, None, boot_modes.LEGACY_BIOS, False,
iscsi_boot=True)
iscsi_boot=True, ramdisk_boot=False)
set_boot_device_mock.assert_called_once_with(task,
boot_devices.PXE,
persistent=True)
@ -1453,6 +1453,59 @@ class PXEBootTestCase(db_base.DbTestCase):
clean_up_pxe_config_mock.assert_called_once_with(task)
self.assertFalse(set_boot_device_mock.called)
@mock.patch.object(manager_utils, 'node_set_boot_device', autospec=True)
@mock.patch.object(deploy_utils, 'switch_pxe_config', autospec=True)
@mock.patch.object(pxe_utils, 'create_pxe_config', autospec=True)
@mock.patch.object(dhcp_factory, 'DHCPFactory', autospec=True)
@mock.patch.object(pxe, '_cache_ramdisk_kernel', autospec=True)
@mock.patch.object(pxe, '_get_instance_image_info', autospec=True)
def _test_prepare_instance_ramdisk(
self, get_image_info_mock, cache_mock,
dhcp_factory_mock, create_pxe_config_mock,
switch_pxe_config_mock,
set_boot_device_mock, config_file_exits=False):
image_info = {'kernel': ['', '/path/to/kernel'],
'ramdisk': ['', '/path/to/ramdisk']}
get_image_info_mock.return_value = image_info
provider_mock = mock.MagicMock()
dhcp_factory_mock.return_value = provider_mock
self.node.provision_state = states.DEPLOYING
get_image_info_mock.return_value = image_info
with task_manager.acquire(self.context, self.node.uuid) as task:
instance_info = task.node.instance_info
instance_info['capabilities'] = {'boot_option': 'ramdisk'}
task.node.instance_info = instance_info
task.node.save()
dhcp_opts = pxe_utils.dhcp_options_for_instance(task)
pxe_config_path = pxe_utils.get_pxe_config_file_path(
task.node.uuid)
task.driver.boot.prepare_instance(task)
get_image_info_mock.assert_called_once_with(
task.node, task.context)
cache_mock.assert_called_once_with(
task.context, task.node, image_info)
provider_mock.update_dhcp.assert_called_once_with(task, dhcp_opts)
if config_file_exits:
self.assertFalse(create_pxe_config_mock.called)
else:
create_pxe_config_mock.assert_called_once_with(
task, mock.ANY, CONF.pxe.pxe_config_template)
switch_pxe_config_mock.assert_called_once_with(
pxe_config_path, None,
'bios', False, iscsi_boot=False, ramdisk_boot=True)
set_boot_device_mock.assert_called_once_with(task,
boot_devices.PXE,
persistent=True)
@mock.patch.object(os.path, 'isfile', lambda path: True)
def test_prepare_instance_ramdisk_pxe_conf_missing(self):
self._test_prepare_instance_ramdisk(config_file_exits=True)
@mock.patch.object(os.path, 'isfile', lambda path: False)
def test_prepare_instance_ramdisk_pxe_conf_exists(self):
self._test_prepare_instance_ramdisk(config_file_exits=False)
@mock.patch.object(pxe, '_clean_up_pxe_env', autospec=True)
@mock.patch.object(pxe, '_get_instance_image_info', autospec=True)
def test_clean_up_instance(self, get_image_info_mock,

View File

@ -0,0 +1,7 @@
---
fixes:
- |
Fixes an issue wherein provisioning fails if ironic node is configured
with ``ramdisk`` deploy interface.
See `bug 2003532 <https://storyboard.openstack.org/#!/story/2003532>`_ for
more details.