diff options
author | Dmitry Tantsur <dtantsur@protonmail.com> | 2021-11-15 19:40:03 +0100 |
---|---|---|
committer | Dmitry Tantsur <dtantsur@protonmail.com> | 2021-11-15 20:09:20 +0100 |
commit | dbc24610d907cb51d8b711edd1b6bd5413c85e69 (patch) | |
tree | a7a236dec81253091aadc257807dabbe9b3f8884 | |
parent | 2ef65aa368842472946c7aa33749121f845ac336 (diff) | |
download | ironic-dbc24610d907cb51d8b711edd1b6bd5413c85e69.tar.gz |
Add an option to create inspector-compatible boot.ipxe
Currently the default boot.ipxe is not suitable for ironic-inspector
in a standalone configuration. This change adds a new option
[pxe]ipxe_fallback_script that makes boot.ipxe fall back to the provided
script.
Story: #2009294
Task: #43982
Change-Id: Id5547885e75beafb4423e9e2056c79c54b286275
-rw-r--r-- | ironic/common/pxe_utils.py | 3 | ||||
-rw-r--r-- | ironic/conf/pxe.py | 4 | ||||
-rw-r--r-- | ironic/drivers/modules/boot.ipxe | 10 | ||||
-rw-r--r-- | ironic/tests/unit/common/test_pxe_utils.py | 36 | ||||
-rw-r--r-- | ironic/tests/unit/drivers/boot-fallback.ipxe | 31 | ||||
-rw-r--r-- | ironic/tests/unit/drivers/modules/test_ipxe.py | 6 | ||||
-rw-r--r-- | releasenotes/notes/ipxe-fallback-a10c8ce422caa429.yaml | 5 |
7 files changed, 90 insertions, 5 deletions
diff --git a/ironic/common/pxe_utils.py b/ironic/common/pxe_utils.py index 08d6d3f98..c0e2ca6e0 100644 --- a/ironic/common/pxe_utils.py +++ b/ironic/common/pxe_utils.py @@ -379,7 +379,8 @@ def create_ipxe_boot_script(): """Render the iPXE boot script into the HTTP root directory""" boot_script = utils.render_template( CONF.pxe.ipxe_boot_script, - {'ipxe_for_mac_uri': PXE_CFG_DIR_NAME + '/'}) + {'ipxe_for_mac_uri': PXE_CFG_DIR_NAME + '/', + 'ipxe_fallback_script': CONF.pxe.ipxe_fallback_script}) bootfile_path = os.path.join( CONF.deploy.http_root, os.path.basename(CONF.pxe.ipxe_boot_script)) diff --git a/ironic/conf/pxe.py b/ironic/conf/pxe.py index 81aef8e74..08c554f87 100644 --- a/ironic/conf/pxe.py +++ b/ironic/conf/pxe.py @@ -144,6 +144,10 @@ opts = [ '$pybasedir', 'drivers/modules/boot.ipxe'), help=_('On ironic-conductor node, the path to the main iPXE ' 'script file.')), + cfg.StrOpt('ipxe_fallback_script', + help=_('File name (e.g. inspector.ipxe) of an iPXE script to ' + 'fall back to when booting to a MAC-specific script ' + 'fails. When not set, booting will fail in this case.')), cfg.IntOpt('ipxe_timeout', default=0, help=_('Timeout value (in seconds) for downloading an image ' diff --git a/ironic/drivers/modules/boot.ipxe b/ironic/drivers/modules/boot.ipxe index 4739695ba..4ed58497c 100644 --- a/ironic/drivers/modules/boot.ipxe +++ b/ironic/drivers/modules/boot.ipxe @@ -11,12 +11,22 @@ echo Attempting to boot from MAC ${net${netid}/mac:hexhyp} chain {{ ipxe_for_mac_uri }}${net${netid}/mac:hexhyp} || goto loop :loop_done +{% if ipxe_fallback_script -%} +chain {{ ipxe_fallback_script }} | goto boot_failed + +:boot_failed +{% endif -%} echo PXE boot failed! No configuration found for any of the present NICs. echo Press any key to reboot... prompt --timeout 180 reboot :old_rom +{% if ipxe_fallback_script -%} +chain {{ ipxe_fallback_script }} | goto boot_failed_old_rom + +:boot_failed_old_rom +{% endif -%} echo PXE boot failed! No configuration found for NIC ${mac:hexhyp}. echo Please update your iPXE ROM and retry. echo Press any key to reboot... diff --git a/ironic/tests/unit/common/test_pxe_utils.py b/ironic/tests/unit/common/test_pxe_utils.py index 2c16e7eb7..4768b914a 100644 --- a/ironic/tests/unit/common/test_pxe_utils.py +++ b/ironic/tests/unit/common/test_pxe_utils.py @@ -154,6 +154,17 @@ class TestPXEUtils(db_base.DbTestCase): self.assertEqual(str(expected_template), rendered_template) + def test_fallback_ipxe_boot_script(self): + rendered_template = utils.render_template( + CONF.pxe.ipxe_boot_script, + {'ipxe_for_mac_uri': 'pxelinux.cfg/', + 'ipxe_fallback_script': 'inspector.ipxe'}) + + with open('ironic/tests/unit/drivers/boot-fallback.ipxe') as f: + expected_template = f.read().rstrip() + + self.assertEqual(str(expected_template), rendered_template) + def test_default_ipxe_config(self): # NOTE(lucasagomes): iPXE is just an extension of the PXE driver, # it doesn't have it's own configuration option for template. @@ -714,7 +725,8 @@ class TestPXEUtils(db_base.DbTestCase): 'foo') render_mock.assert_called_once_with( CONF.pxe.ipxe_boot_script, - {'ipxe_for_mac_uri': 'pxelinux.cfg/'}) + {'ipxe_for_mac_uri': 'pxelinux.cfg/', + 'ipxe_fallback_script': None}) @mock.patch.object(os.path, 'isfile', lambda path: True) @mock.patch('ironic.common.utils.file_has_content', autospec=True) @@ -735,7 +747,27 @@ class TestPXEUtils(db_base.DbTestCase): 'foo') render_mock.assert_called_once_with( CONF.pxe.ipxe_boot_script, - {'ipxe_for_mac_uri': 'pxelinux.cfg/'}) + {'ipxe_for_mac_uri': 'pxelinux.cfg/', + 'ipxe_fallback_script': None}) + + @mock.patch.object(os.path, 'isfile', lambda path: False) + @mock.patch('ironic.common.utils.file_has_content', autospec=True) + @mock.patch('ironic.common.utils.write_to_file', autospec=True) + @mock.patch('ironic.common.utils.render_template', autospec=True) + def test_create_ipxe_boot_script_fallback(self, render_mock, write_mock, + file_has_content_mock): + self.config(ipxe_fallback_script='inspector.ipxe', group='pxe') + render_mock.return_value = 'foo' + pxe_utils.create_ipxe_boot_script() + self.assertFalse(file_has_content_mock.called) + write_mock.assert_called_once_with( + os.path.join(CONF.deploy.http_root, + os.path.basename(CONF.pxe.ipxe_boot_script)), + 'foo') + render_mock.assert_called_once_with( + CONF.pxe.ipxe_boot_script, + {'ipxe_for_mac_uri': 'pxelinux.cfg/', + 'ipxe_fallback_script': 'inspector.ipxe'}) @mock.patch.object(os.path, 'isfile', lambda path: True) @mock.patch('ironic.common.utils.file_has_content', autospec=True) diff --git a/ironic/tests/unit/drivers/boot-fallback.ipxe b/ironic/tests/unit/drivers/boot-fallback.ipxe new file mode 100644 index 000000000..bf8ab414c --- /dev/null +++ b/ironic/tests/unit/drivers/boot-fallback.ipxe @@ -0,0 +1,31 @@ +#!ipxe + +# NOTE(lucasagomes): Loop over all network devices and boot from +# the first one capable of booting. For more information see: +# https://bugs.launchpad.net/ironic/+bug/1504482 +set netid:int32 -1 +:loop +inc netid || chain pxelinux.cfg/${mac:hexhyp} || goto old_rom +isset ${net${netid}/mac} || goto loop_done +echo Attempting to boot from MAC ${net${netid}/mac:hexhyp} +chain pxelinux.cfg/${net${netid}/mac:hexhyp} || goto loop + +:loop_done +chain inspector.ipxe | goto boot_failed + +:boot_failed +echo PXE boot failed! No configuration found for any of the present NICs. +echo Press any key to reboot... +prompt --timeout 180 +reboot + +:old_rom +chain inspector.ipxe | goto boot_failed_old_rom + +:boot_failed_old_rom +echo PXE boot failed! No configuration found for NIC ${mac:hexhyp}. +echo Please update your iPXE ROM and retry. +echo Press any key to reboot... +prompt --timeout 180 +reboot + diff --git a/ironic/tests/unit/drivers/modules/test_ipxe.py b/ironic/tests/unit/drivers/modules/test_ipxe.py index 45a68eeb3..2254a2c72 100644 --- a/ironic/tests/unit/drivers/modules/test_ipxe.py +++ b/ironic/tests/unit/drivers/modules/test_ipxe.py @@ -395,7 +395,8 @@ class iPXEBootTestCase(db_base.DbTestCase): 'foo') render_mock.assert_called_once_with( CONF.pxe.ipxe_boot_script, - {'ipxe_for_mac_uri': 'pxelinux.cfg/'}) + {'ipxe_for_mac_uri': 'pxelinux.cfg/', + 'ipxe_fallback_script': None}) @mock.patch.object(os.path, 'isfile', lambda path: False) @mock.patch('ironic.common.utils.file_has_content', autospec=True) @@ -415,7 +416,8 @@ class iPXEBootTestCase(db_base.DbTestCase): 'foo') render_mock.assert_called_once_with( CONF.pxe.ipxe_boot_script, - {'ipxe_for_mac_uri': 'pxelinux.cfg/'}) + {'ipxe_for_mac_uri': 'pxelinux.cfg/', + 'ipxe_fallback_script': None}) @mock.patch.object(os.path, 'isfile', lambda path: True) @mock.patch.object(common_utils, 'file_has_content', lambda *args: True) diff --git a/releasenotes/notes/ipxe-fallback-a10c8ce422caa429.yaml b/releasenotes/notes/ipxe-fallback-a10c8ce422caa429.yaml new file mode 100644 index 000000000..0f0d60236 --- /dev/null +++ b/releasenotes/notes/ipxe-fallback-a10c8ce422caa429.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + Adds a new configuration option ``[pxe]ipxe_fallback_script`` which allows + iPXE boot to fall back to e.g. ironic-inspector iPXE script. |