diff --git a/ironic/common/pxe_utils.py b/ironic/common/pxe_utils.py index 8c61e235dd..a6efb026b7 100644 --- a/ironic/common/pxe_utils.py +++ b/ironic/common/pxe_utils.py @@ -967,7 +967,7 @@ def build_service_pxe_config(task, instance_image_info, # fail if the agent was booted outside the direct actions of the # boot interface. if (node.provision_state in [states.ACTIVE, states.UNRESCUING, - states.DEPLOYING] + states.DEPLOYING, states.ADOPTING] and not os.path.isfile(pxe_config_path)): pxe_options = build_pxe_config_options(task, instance_image_info, service=True, diff --git a/ironic/drivers/modules/agent.py b/ironic/drivers/modules/agent.py index a9b3544b1a..1cb3bb5ff6 100644 --- a/ironic/drivers/modules/agent.py +++ b/ironic/drivers/modules/agent.py @@ -364,10 +364,11 @@ class CustomAgentDeploy(agent_base.AgentBaseMixin, agent_base.AgentDeployMixin, # Alternatively, we could be in a fast track deployment # and again, we should have nothing to do here. return - if node.provision_state in (states.ACTIVE, states.UNRESCUING): + if node.provision_state in (states.ACTIVE, states.UNRESCUING, + states.ADOPTING): # Call is due to conductor takeover task.driver.boot.prepare_instance(task) - elif node.provision_state != states.ADOPTING: + else: if node.provision_state not in (states.RESCUING, states.RESCUEWAIT, states.RESCUE, states.RESCUEFAIL): self._update_instance_info(task) diff --git a/ironic/drivers/modules/pxe_base.py b/ironic/drivers/modules/pxe_base.py index f3ac498902..5053ce0f6a 100644 --- a/ironic/drivers/modules/pxe_base.py +++ b/ironic/drivers/modules/pxe_base.py @@ -283,7 +283,8 @@ class PXEBaseMixin(object): # NOTE(pas-ha) do not re-set boot device on ACTIVE nodes # during takeover - if boot_device and task.node.provision_state != states.ACTIVE: + if boot_device and (task.node.provision_state not in + (states.ACTIVE, states.ADOPTING)): manager_utils.node_set_boot_device(task, boot_device, persistent=True) diff --git a/ironic/tests/unit/common/test_pxe_utils.py b/ironic/tests/unit/common/test_pxe_utils.py index a57441f588..f1295cb2cf 100644 --- a/ironic/tests/unit/common/test_pxe_utils.py +++ b/ironic/tests/unit/common/test_pxe_utils.py @@ -2387,6 +2387,41 @@ class iPXEBuildConfigOptionsTestCase(db_base.DbTestCase): os.path.join(CONF.deploy.http_root, self.node.uuid)) +@mock.patch.object(ipxe.iPXEBoot, '__init__', lambda self: None) +class iPXEBuildServicePXEConfigTestCase(db_base.DbTestCase): + def setUp(self): + super(iPXEBuildServicePXEConfigTestCase, self).setUp() + n = { + 'driver': 'fake-hardware', + 'boot_interface': 'ipxe', + 'instance_info': INST_INFO_DICT, + 'driver_info': DRV_INFO_DICT, + 'driver_internal_info': DRV_INTERNAL_INFO_DICT, + } + self.config(enabled_boot_interfaces=['ipxe']) + self.node = object_utils.create_test_node(self.context, **n) + + @mock.patch.object(pxe_utils, 'create_pxe_config', autospec=True) + @mock.patch.object(deploy_utils, 'switch_pxe_config', autospec=True) + def test_build_service_pxe_config_adopt(self, mock_switch, mock_pxe_utils): + self.node.provision_state = states.ADOPTING + + driver_internal_info = self.node.driver_internal_info + driver_internal_info['is_whole_disk_image'] = True + self.node.driver_internal_info = driver_internal_info + self.node.save() + + image_info = {} + + with task_manager.acquire(self.context, self.node.uuid, + shared=True) as task: + pxe_utils.build_service_pxe_config(task, image_info, 'id', + is_whole_disk_image=True) + + mock_pxe_utils.assert_called() + mock_switch.assert_called() + + @mock.patch.object(ironic_utils, 'unlink_without_raise', autospec=True) @mock.patch.object(pxe_utils, 'clean_up_pxe_config', autospec=True) @mock.patch.object(pxe_utils, 'TFTPImageCache', autospec=True) diff --git a/ironic/tests/unit/drivers/modules/test_agent.py b/ironic/tests/unit/drivers/modules/test_agent.py index 0ada1e2b47..4e92ad2f44 100644 --- a/ironic/tests/unit/drivers/modules/test_agent.py +++ b/ironic/tests/unit/drivers/modules/test_agent.py @@ -984,6 +984,7 @@ class TestAgentDeploy(CommonTestsMixin, db_base.DbTestCase): self.assertTrue(storage_attach_volumes_mock.called) self.assertEqual(2, should_write_image_mock.call_count) + @mock.patch.object(pxe.PXEBoot, 'prepare_instance', autospec=True) @mock.patch.object(flat_network.FlatNetwork, 'add_provisioning_network', spec_set=True, autospec=True) @mock.patch.object(pxe.PXEBoot, 'prepare_ramdisk', autospec=True) @@ -992,7 +993,8 @@ class TestAgentDeploy(CommonTestsMixin, db_base.DbTestCase): autospec=True) def test_prepare_adopting( self, build_instance_info_mock, build_options_mock, - pxe_prepare_ramdisk_mock, add_provisioning_net_mock): + pxe_prepare_ramdisk_mock, add_provisioning_net_mock, + prepare_instance_mock): with task_manager.acquire( self.context, self.node['uuid'], shared=False) as task: task.node.provision_state = states.ADOPTING @@ -1003,6 +1005,7 @@ class TestAgentDeploy(CommonTestsMixin, db_base.DbTestCase): self.assertFalse(build_options_mock.called) self.assertFalse(pxe_prepare_ramdisk_mock.called) self.assertFalse(add_provisioning_net_mock.called) + self.assertTrue(prepare_instance_mock.called) @mock.patch.object(flat_network.FlatNetwork, 'add_provisioning_network', spec_set=True, autospec=True) diff --git a/releasenotes/notes/pxe-onadopt-7214eba4f5822e1a.yaml b/releasenotes/notes/pxe-onadopt-7214eba4f5822e1a.yaml new file mode 100644 index 0000000000..b08f6cba1a --- /dev/null +++ b/releasenotes/notes/pxe-onadopt-7214eba4f5822e1a.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + Fixes ``enable_netboot_fallback`` to write out pxe config + on adopt.