summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulia Kreger <juliaashleykreger@gmail.com>2020-05-14 17:43:08 -0700
committerJulia Kreger <juliaashleykreger@gmail.com>2021-07-22 08:14:09 -0700
commitef365f89b97a0fcec240a4855defcfa61e062e9a (patch)
treeb7e5ad78225af82a67400596badccd702bd197e6
parent0c17549c2c81fcb2e3ce256d93f80befe36c2d0d (diff)
downloadironic-ef365f89b97a0fcec240a4855defcfa61e062e9a.tar.gz
Provide a path to set explicit ipxe bootloaders
I did something stupid when started driving forth the split of ipxe from the pxe interface: I didn't think about the need to actually separate bootloaders. In part, because the use case was a mixed Power8/Power9 and x86 cluster. Mainly because the Power hardware does not honor or care about the bootfile name provided over DHCP. The firmware knows how to read the PXELINUX boot file format and the machines are able to boot from there. Where this all goes sideways is when: * Enabled boot interfaces are set to ipxe,pxe * No default boot interface is set * Node is created without a default for x86 hardware. * Node uses ipxe boot_interface, and creates files under /httpboot * bootfile transmitted via DHCP is pxelinux.0. Fun right? The simple workaround for the power user is to just define the iPXE loader, or maybe use UEFI. But that is neither here nor there, this is still a bug and a possible use case is GRUB2 via PXE and iPXE. Not that would really work via ipxe, but hopefully people get the idea. The solution kind of seems clear, duplicate configuration and fallback if not defined. Story: #2007003 Task: #40282 Change-Id: I4419254c23095929e52a0fda11789f2f5167dc6b (cherry picked from commit 5f7d84f483be165fde04954453e156ceefc43d28)
-rw-r--r--devstack/lib/ironic6
-rw-r--r--doc/source/install/configure-pxe.rst59
-rw-r--r--ironic/common/pxe_utils.py29
-rw-r--r--ironic/conf/pxe.py23
-rw-r--r--ironic/drivers/modules/deploy_utils.py48
-rw-r--r--ironic/drivers/modules/pxe_base.py5
-rw-r--r--ironic/tests/unit/common/test_pxe_utils.py26
-rw-r--r--ironic/tests/unit/drivers/modules/test_deploy_utils.py50
-rw-r--r--ironic/tests/unit/drivers/modules/test_ipxe.py15
-rw-r--r--releasenotes/notes/explicit_ipxe_config_options-d7bf9a743a13f523.yaml17
10 files changed, 226 insertions, 52 deletions
diff --git a/devstack/lib/ironic b/devstack/lib/ironic
index 9a1a5feb9..ae8983772 100644
--- a/devstack/lib/ironic
+++ b/devstack/lib/ironic
@@ -1727,10 +1727,8 @@ function configure_ironic_conductor {
local pxebin
pxebin=`basename $IRONIC_PXE_BOOT_IMAGE`
uefipxebin=`basename $(get_uefi_ipxe_boot_file)`
- iniset $IRONIC_CONF_FILE pxe pxe_config_template '$pybasedir/drivers/modules/ipxe_config.template'
- iniset $IRONIC_CONF_FILE pxe pxe_bootfile_name $pxebin
- iniset $IRONIC_CONF_FILE pxe uefi_pxe_config_template '$pybasedir/drivers/modules/ipxe_config.template'
- iniset $IRONIC_CONF_FILE pxe uefi_pxe_bootfile_name $uefipxebin
+ iniset $IRONIC_CONF_FILE pxe ipxe_bootfile_name $pxebin
+ iniset $IRONIC_CONF_FILE pxe uefi_ipxe_bootfile_name $uefipxebin
iniset $IRONIC_CONF_FILE deploy http_root $IRONIC_HTTP_DIR
iniset $IRONIC_CONF_FILE deploy http_url "http://$([[ $IRONIC_HTTP_SERVER =~ : ]] && echo "[$IRONIC_HTTP_SERVER]" || echo $IRONIC_HTTP_SERVER):$IRONIC_HTTP_PORT"
if [[ "$IRONIC_IPXE_USE_SWIFT" == "True" ]]; then
diff --git a/doc/source/install/configure-pxe.rst b/doc/source/install/configure-pxe.rst
index 8769375f4..d06c1f419 100644
--- a/doc/source/install/configure-pxe.rst
+++ b/doc/source/install/configure-pxe.rst
@@ -341,41 +341,59 @@ on the Bare Metal service node(s) where ``ironic-conductor`` is running.
Ubuntu::
- cp /usr/lib/ipxe/{undionly.kpxe,ipxe.efi} /tftpboot
+ cp /usr/lib/ipxe/{undionly.kpxe,ipxe.efi,snponly.efi} /tftpboot
Fedora/RHEL8/CentOS8::
- cp /usr/share/ipxe/{undionly.kpxe,ipxe.efi} /tftpboot
+ cp /usr/share/ipxe/{undionly.kpxe,ipxe.efi,snponly.efi} /tftpboot
-#. Enable/Configure iPXE in the Bare Metal Service's configuration file
- (/etc/ironic/ironic.conf):
+#. Enable/Configure iPXE overrides in the Bare Metal Service's configuration
+ file **if required** (/etc/ironic/ironic.conf):
.. code-block:: ini
[pxe]
- # Enable iPXE boot. (boolean value)
- ipxe_enabled=True
-
# Neutron bootfile DHCP parameter. (string value)
- pxe_bootfile_name=undionly.kpxe
+ ipxe_bootfile_name=undionly.kpxe
# Bootfile DHCP parameter for UEFI boot mode. (string value)
- uefi_pxe_bootfile_name=ipxe.efi
+ uefi_ipxe_bootfile_name=ipxe.efi
# Template file for PXE configuration. (string value)
- pxe_config_template=$pybasedir/drivers/modules/ipxe_config.template
+ ipxe_config_template=$pybasedir/drivers/modules/ipxe_config.template
+
+ .. note::
+ Most UEFI systems have integrated networking which means the
+ ``[pxe]uefi_ipxe_bootfile_name`` setting should be set to
+ ``snponly.efi``.
+
+ .. note::
+ Setting the iPXE parameters noted in the code block above to no value,
+ in other words setting a line to something like ``ipxe_bootfile_name=``
+ will result in ironic falling back to the default values of the non-iPXE
+ PXE settings. This is for backwards compatability.
+
+#. Ensure iPXE is the default PXE, if applicable.
- # Template file for PXE configuration for UEFI boot loader.
- # (string value)
- uefi_pxe_config_template=$pybasedir/drivers/modules/ipxe_config.template
+ In earlier versions of ironic, a ``[pxe]ipxe_enabled`` setting allowing
+ operators to declare the behavior of the conductor to exclusively operate
+ as if only iPXE was to be used. As time moved on, iPXE functionality was
+ moved to it's own ``ipxe`` boot interface.
+
+ If you want to emulate that same hehavior, set the following in the
+ configuration file (/etc/ironic/ironic.conf):
+
+ .. code-block:: ini
+
+ [DEFAULT]
+ default_boot_interface=ipxe
+ enabled_boot_interfaces=ipxe,pxe
.. note::
- The ``[pxe]ipxe_enabled`` option has been deprecated and will be removed
- in the T* development cycle. Users should instead consider use of the
- ``ipxe`` boot interface. The same default use of iPXE functionality can
- be achieved by setting the ``[DEFAULT]default_boot_interface`` option
- to ``ipxe``.
+ The ``[DEFAULT]enabled_boot_interfaces`` setting may be exclusively set
+ to ``ipxe``, however ironic has multiple interfaces available depending
+ on the hardware types available for use.
#. It is possible to configure the Bare Metal service in such a way
that nodes will boot into the deploy image directly from Object Storage.
@@ -426,7 +444,6 @@ on the Bare Metal service node(s) where ``ironic-conductor`` is running.
sudo service ironic-conductor restart
-
PXE multi-architecture setup
----------------------------
@@ -482,6 +499,10 @@ nodes will be deployed by 'grubaa64.efi', and ppc64 nodes by 'bootppc64'::
commands, you'll need to switch to use ``linux`` and ``initrd`` command
instead.
+.. note::
+ A ``[pxe]ipxe_bootfile_name_by_arch`` setting is available for multi-arch
+ iPXE based deployment, and defaults to the same behavior as the comperable
+ ``[pxe]pxe_bootfile_by_arch`` setting for standard PXE.
PXE timeouts tuning
-------------------
diff --git a/ironic/common/pxe_utils.py b/ironic/common/pxe_utils.py
index 6f7a666c7..dccf2f038 100644
--- a/ironic/common/pxe_utils.py
+++ b/ironic/common/pxe_utils.py
@@ -268,7 +268,10 @@ def create_pxe_config(task, pxe_options, template=None, ipxe_enabled=False):
"""
LOG.debug("Building PXE config for node %s", task.node.uuid)
if template is None:
- template = deploy_utils.get_pxe_config_template(task.node)
+ if ipxe_enabled:
+ template = deploy_utils.get_ipxe_config_template(task.node)
+ else:
+ template = deploy_utils.get_pxe_config_template(task.node)
_ensure_config_dirs_exist(task, ipxe_enabled)
@@ -386,7 +389,16 @@ def _dhcp_option_file_or_url(task, urlboot=False, ip_version=None):
to return options for DHCP. Possible options
are 4, and 6.
"""
- boot_file = deploy_utils.get_pxe_boot_file(task.node)
+ try:
+ if task.driver.boot.ipxe_enabled:
+ boot_file = deploy_utils.get_ipxe_boot_file(task.node)
+ else:
+ boot_file = deploy_utils.get_pxe_boot_file(task.node)
+ except AttributeError:
+ # Support boot interfaces that lack an explicit ipxe_enabled
+ # attribute flag.
+ boot_file = deploy_utils.get_pxe_boot_file(task.node)
+
# NOTE(TheJulia): There are additional cases as we add new
# features, so the logic below is in the form of if/elif/elif
if not urlboot:
@@ -801,7 +813,10 @@ def build_service_pxe_config(task, instance_image_info,
pxe_options = build_pxe_config_options(task, instance_image_info,
service=True,
ipxe_enabled=ipxe_enabled)
- pxe_config_template = deploy_utils.get_pxe_config_template(node)
+ if ipxe_enabled:
+ pxe_config_template = deploy_utils.get_ipxe_config_template(node)
+ else:
+ pxe_config_template = deploy_utils.get_pxe_config_template(node)
create_pxe_config(task, pxe_options, pxe_config_template,
ipxe_enabled=ipxe_enabled)
iwdi = node.driver_internal_info.get('is_whole_disk_image')
@@ -939,8 +954,12 @@ def prepare_instance_pxe_config(task, image_info,
pxe_options = build_pxe_config_options(
task, image_info, service=ramdisk_boot,
ipxe_enabled=ipxe_enabled)
- pxe_config_template = (
- deploy_utils.get_pxe_config_template(node))
+ if ipxe_enabled:
+ pxe_config_template = (
+ deploy_utils.get_ipxe_config_template(node))
+ else:
+ pxe_config_template = (
+ deploy_utils.get_pxe_config_template(node))
create_pxe_config(
task, pxe_options, pxe_config_template,
ipxe_enabled=ipxe_enabled)
diff --git a/ironic/conf/pxe.py b/ironic/conf/pxe.py
index a54beefa6..16315c88c 100644
--- a/ironic/conf/pxe.py
+++ b/ironic/conf/pxe.py
@@ -51,13 +51,20 @@ opts = [
default=os.path.join(
'$pybasedir', 'drivers/modules/pxe_config.template'),
help=_('On ironic-conductor node, template file for PXE '
- 'configuration.')),
+ 'loader configuration.')),
+ cfg.StrOpt('ipxe_config_template',
+ default=os.path.join(
+ '$pybasedir', 'drivers/modules/ipxe_config.template'),
+ mutable=True,
+ help=_('On ironic-conductor node, template file for iPXE '
+ 'operations.')),
cfg.StrOpt('uefi_pxe_config_template',
default=os.path.join(
'$pybasedir',
'drivers/modules/pxe_grub_config.template'),
help=_('On ironic-conductor node, template file for PXE '
- 'configuration for UEFI boot loader.')),
+ 'configuration for UEFI boot loader. Generally this '
+ 'is used for GRUB specific templates.')),
cfg.DictOpt('pxe_config_template_by_arch',
default={},
help=_('On ironic-conductor node, template file for PXE '
@@ -102,10 +109,22 @@ opts = [
cfg.StrOpt('uefi_pxe_bootfile_name',
default='bootx64.efi',
help=_('Bootfile DHCP parameter for UEFI boot mode.')),
+ cfg.StrOpt('ipxe_bootfile_name',
+ default='undionly.kpxe',
+ help=_('Bootfile DHCP parameter.')),
+ cfg.StrOpt('uefi_ipxe_bootfile_name',
+ default='ipxe.efi',
+ help=_('Bootfile DHCP parameter for UEFI boot mode. If you '
+ 'experience problems with booting using it, try '
+ 'snponly.efi.')),
cfg.DictOpt('pxe_bootfile_name_by_arch',
default={},
help=_('Bootfile DHCP parameter per node architecture. '
'For example: aarch64:grubaa64.efi')),
+ cfg.DictOpt('ipxe_bootfile_name_by_arch',
+ default={},
+ help=_('Bootfile DHCP parameter per node architecture. '
+ 'For example: aarch64:ipxe_aa64.efi')),
cfg.StrOpt('ipxe_boot_script',
default=os.path.join(
'$pybasedir', 'drivers/modules/boot.ipxe'),
diff --git a/ironic/drivers/modules/deploy_utils.py b/ironic/drivers/modules/deploy_utils.py
index 028032cbc..8a1c741ea 100644
--- a/ironic/drivers/modules/deploy_utils.py
+++ b/ironic/drivers/modules/deploy_utils.py
@@ -383,6 +383,54 @@ def get_pxe_boot_file(node):
return boot_file
+def get_ipxe_boot_file(node):
+ """Return the iPXE boot file name requested for deploy.
+
+ This method returns iPXE boot file name to be used for deploy.
+ Architecture specific boot file is searched first. BIOS/UEFI
+ boot file is used if no valid architecture specific file found.
+
+ If no valid value is found, the default reverts to the
+ ``get_pxe_boot_file`` method and thus the
+ ``[pxe]pxe_bootfile_name`` and ``[pxe]uefi_ipxe_bootfile_name``
+ settings.
+
+ :param node: A single Node.
+ :returns: The iPXE boot file name.
+ """
+ cpu_arch = node.properties.get('cpu_arch')
+ boot_file = CONF.pxe.ipxe_bootfile_name_by_arch.get(cpu_arch)
+ if boot_file is None:
+ if boot_mode_utils.get_boot_mode(node) == 'uefi':
+ boot_file = CONF.pxe.uefi_ipxe_bootfile_name
+ else:
+ boot_file = CONF.pxe.ipxe_bootfile_name
+
+ if boot_file is None:
+ boot_file = get_pxe_boot_file(node)
+
+ return boot_file
+
+
+def get_ipxe_config_template(node):
+ """Return the iPXE config template file name requested of deploy.
+
+ This method returns the iPXE configuration template file.
+
+ :param node: A single Node.
+ :returns: The iPXE config template file name.
+ """
+ # NOTE(TheJulia): iPXE configuration files don't change based upon the
+ # architecture and we're not trying to support multiple different boot
+ # loaders by architecture as they are all consistent. Where as PXE
+ # could need to be grub for one arch, PXELINUX for another.
+ configured_template = CONF.pxe.ipxe_config_template
+ override_template = node.driver_info.get('pxe_template')
+ if override_template:
+ configured_template = override_template
+ return configured_template or get_pxe_config_template(node)
+
+
def get_pxe_config_template(node):
"""Return the PXE config template file name requested for deploy.
diff --git a/ironic/drivers/modules/pxe_base.py b/ironic/drivers/modules/pxe_base.py
index a30d69233..a26c9eaf5 100644
--- a/ironic/drivers/modules/pxe_base.py
+++ b/ironic/drivers/modules/pxe_base.py
@@ -201,7 +201,10 @@ class PXEBaseMixin(object):
if ramdisk_params.get("ipa-api-url"):
pxe_options["ipa-api-url"] = ramdisk_params["ipa-api-url"]
- pxe_config_template = deploy_utils.get_pxe_config_template(node)
+ if self.ipxe_enabled:
+ pxe_config_template = deploy_utils.get_ipxe_config_template(node)
+ else:
+ pxe_config_template = deploy_utils.get_pxe_config_template(node)
pxe_utils.create_pxe_config(task, pxe_options,
pxe_config_template,
diff --git a/ironic/tests/unit/common/test_pxe_utils.py b/ironic/tests/unit/common/test_pxe_utils.py
index 25847a325..3c1f745dc 100644
--- a/ironic/tests/unit/common/test_pxe_utils.py
+++ b/ironic/tests/unit/common/test_pxe_utils.py
@@ -664,7 +664,7 @@ class TestPXEUtils(db_base.DbTestCase):
'config'),
pxe_utils.get_pxe_config_file_path(self.node.uuid))
- def _dhcp_options_for_instance(self, ip_version=4):
+ def _dhcp_options_for_instance(self, ip_version=4, ipxe=False):
self.config(ip_version=ip_version, group='pxe')
if ip_version == 4:
self.config(tftp_server='192.0.2.1', group='pxe')
@@ -672,6 +672,10 @@ class TestPXEUtils(db_base.DbTestCase):
self.config(tftp_server='ff80::1', group='pxe')
self.config(pxe_bootfile_name='fake-bootfile', group='pxe')
self.config(tftp_root='/tftp-path/', group='pxe')
+ if ipxe:
+ bootfile = 'fake-bootfile-ipxe'
+ else:
+ bootfile = 'fake-bootfile'
if ip_version == 6:
# NOTE(TheJulia): DHCPv6 RFCs seem to indicate that the prior
@@ -679,11 +683,11 @@ class TestPXEUtils(db_base.DbTestCase):
# by vendors. The apparent proper option is to return a
# URL in the field https://tools.ietf.org/html/rfc5970#section-3
expected_info = [{'opt_name': '59',
- 'opt_value': 'tftp://[ff80::1]/fake-bootfile',
+ 'opt_value': 'tftp://[ff80::1]/%s' % bootfile,
'ip_version': ip_version}]
elif ip_version == 4:
expected_info = [{'opt_name': '67',
- 'opt_value': 'fake-bootfile',
+ 'opt_value': bootfile,
'ip_version': ip_version},
{'opt_name': '210',
'opt_value': '/tftp-path/',
@@ -1380,7 +1384,7 @@ class iPXEBuildConfigOptionsTestCase(db_base.DbTestCase):
# URL in the field https://tools.ietf.org/html/rfc5970#section-3
expected_boot_script_url = 'http://[ff80::1]:1234/boot.ipxe'
expected_info = [{'opt_name': '!175,59',
- 'opt_value': 'tftp://[ff80::1]/fake-bootfile',
+ 'opt_value': 'tftp://[ff80::1]/%s' % boot_file,
'ip_version': ip_version},
{'opt_name': '59',
'opt_value': expected_boot_script_url,
@@ -1412,7 +1416,7 @@ class iPXEBuildConfigOptionsTestCase(db_base.DbTestCase):
if ip_version == 6:
# Boot URL variable set from prior test of isc parameters.
expected_info = [{'opt_name': 'tag:!ipxe6,59',
- 'opt_value': 'tftp://[ff80::1]/fake-bootfile',
+ 'opt_value': 'tftp://[ff80::1]/%s' % boot_file,
'ip_version': ip_version},
{'opt_name': 'tag:ipxe6,59',
'opt_value': expected_boot_script_url,
@@ -1441,23 +1445,23 @@ class iPXEBuildConfigOptionsTestCase(db_base.DbTestCase):
def test_dhcp_options_for_instance_ipxe_bios(self):
self.config(ip_version=4, group='pxe')
- boot_file = 'fake-bootfile-bios'
- self.config(pxe_bootfile_name=boot_file, group='pxe')
+ boot_file = 'fake-bootfile-bios-ipxe'
+ self.config(ipxe_bootfile_name=boot_file, group='pxe')
with task_manager.acquire(self.context, self.node.uuid) as task:
self._dhcp_options_for_instance_ipxe(task, boot_file)
def test_dhcp_options_for_instance_ipxe_uefi(self):
self.config(ip_version=4, group='pxe')
- boot_file = 'fake-bootfile-uefi'
- self.config(uefi_pxe_bootfile_name=boot_file, group='pxe')
+ boot_file = 'fake-bootfile-uefi-ipxe'
+ self.config(uefi_ipxe_bootfile_name=boot_file, group='pxe')
with task_manager.acquire(self.context, self.node.uuid) as task:
task.node.properties['capabilities'] = 'boot_mode:uefi'
self._dhcp_options_for_instance_ipxe(task, boot_file)
def test_dhcp_options_for_ipxe_ipv6(self):
self.config(ip_version=6, group='pxe')
- boot_file = 'fake-bootfile'
- self.config(pxe_bootfile_name=boot_file, group='pxe')
+ boot_file = 'fake-bootfile-ipxe'
+ self.config(ipxe_bootfile_name=boot_file, group='pxe')
with task_manager.acquire(self.context, self.node.uuid) as task:
self._dhcp_options_for_instance_ipxe(task, boot_file, ip_version=6)
diff --git a/ironic/tests/unit/drivers/modules/test_deploy_utils.py b/ironic/tests/unit/drivers/modules/test_deploy_utils.py
index 5344d3ed4..1e6c3b42b 100644
--- a/ironic/tests/unit/drivers/modules/test_deploy_utils.py
+++ b/ironic/tests/unit/drivers/modules/test_deploy_utils.py
@@ -582,6 +582,34 @@ class GetPxeBootConfigTestCase(db_base.DbTestCase):
result = utils.get_pxe_boot_file(self.node)
self.assertEqual('bios-bootfile', result)
+ def test_get_ipxe_boot_file(self):
+ self.config(ipxe_bootfile_name='meow', group='pxe')
+ result = utils.get_ipxe_boot_file(self.node)
+ self.assertEqual('meow', result)
+
+ def test_get_ipxe_boot_file_uefi(self):
+ self.config(uefi_ipxe_bootfile_name='ipxe-uefi-bootfile', group='pxe')
+ properties = {'capabilities': 'boot_mode:uefi'}
+ self.node.properties = properties
+ result = utils.get_ipxe_boot_file(self.node)
+ self.assertEqual('ipxe-uefi-bootfile', result)
+
+ def test_get_ipxe_boot_file_other_arch(self):
+ arch_names = {'aarch64': 'ipxe-aa64.efi',
+ 'x86_64': 'ipxe.kpxe'}
+ self.config(ipxe_bootfile_name_by_arch=arch_names, group='pxe')
+ properties = {'cpu_arch': 'aarch64', 'capabilities': 'boot_mode:uefi'}
+ self.node.properties = properties
+ result = utils.get_ipxe_boot_file(self.node)
+ self.assertEqual('ipxe-aa64.efi', result)
+
+ def test_get_ipxe_boot_file_fallback(self):
+ self.config(ipxe_bootfile_name=None, group='pxe')
+ self.config(uefi_ipxe_bootfile_name=None, group='pxe')
+ self.config(pxe_bootfile_name='lolcat', group='pxe')
+ result = utils.get_ipxe_boot_file(self.node)
+ self.assertEqual('lolcat', result)
+
def test_get_pxe_config_template_emtpy_property(self):
self.node.properties = {}
self.config(pxe_config_template_by_arch=self.template_by_arch,
@@ -597,6 +625,28 @@ class GetPxeBootConfigTestCase(db_base.DbTestCase):
result = utils.get_pxe_config_template(node)
self.assertEqual('fake-template', result)
+ def test_get_ipxe_config_template(self):
+ node = obj_utils.create_test_node(
+ self.context, driver='fake-hardware')
+ self.assertIn('ipxe_config.template',
+ utils.get_ipxe_config_template(node))
+
+ def test_get_ipxe_config_template_none(self):
+ self.config(ipxe_config_template=None, group='pxe')
+ self.config(pxe_config_template='magical_bootloader',
+ group='pxe')
+ node = obj_utils.create_test_node(
+ self.context, driver='fake-hardware')
+ self.assertEqual('magical_bootloader',
+ utils.get_ipxe_config_template(node))
+
+ def test_get_ipxe_config_template_override_pxe_fallback(self):
+ node = obj_utils.create_test_node(
+ self.context, driver='fake-hardware',
+ driver_info={'pxe_template': 'magical'})
+ self.assertEqual('magical',
+ utils.get_ipxe_config_template(node))
+
@mock.patch('time.sleep', lambda sec: None)
class OtherFunctionTestCase(db_base.DbTestCase):
diff --git a/ironic/tests/unit/drivers/modules/test_ipxe.py b/ironic/tests/unit/drivers/modules/test_ipxe.py
index cbec1bb0d..c53facf22 100644
--- a/ironic/tests/unit/drivers/modules/test_ipxe.py
+++ b/ironic/tests/unit/drivers/modules/test_ipxe.py
@@ -310,14 +310,9 @@ class iPXEBootTestCase(db_base.DbTestCase):
mock_cache_r_k.assert_called_once_with(
task, {'rescue_kernel': 'a', 'rescue_ramdisk': 'r'},
ipxe_enabled=True)
- if uefi:
- mock_pxe_config.assert_called_once_with(
- task, {}, CONF.pxe.uefi_pxe_config_template,
- ipxe_enabled=True)
- else:
- mock_pxe_config.assert_called_once_with(
- task, {}, CONF.pxe.pxe_config_template,
- ipxe_enabled=True)
+ mock_pxe_config.assert_called_once_with(
+ task, {}, CONF.pxe.ipxe_config_template,
+ ipxe_enabled=True)
def test_prepare_ramdisk(self):
self.node.provision_state = states.DEPLOYING
@@ -700,7 +695,7 @@ class iPXEBootTestCase(db_base.DbTestCase):
ipxe_enabled=True)
provider_mock.update_dhcp.assert_called_once_with(task, dhcp_opts)
create_pxe_config_mock.assert_called_once_with(
- task, mock.ANY, CONF.pxe.pxe_config_template,
+ task, mock.ANY, CONF.pxe.ipxe_config_template,
ipxe_enabled=True)
switch_pxe_config_mock.assert_called_once_with(
pxe_config_path, "30212642-09d3-467f-8e09-21685826ab50",
@@ -817,7 +812,7 @@ class iPXEBootTestCase(db_base.DbTestCase):
self.assertFalse(cache_mock.called)
provider_mock.update_dhcp.assert_called_once_with(task, dhcp_opts)
create_pxe_config_mock.assert_called_once_with(
- task, mock.ANY, CONF.pxe.pxe_config_template,
+ task, mock.ANY, CONF.pxe.ipxe_config_template,
ipxe_enabled=True)
switch_pxe_config_mock.assert_called_once_with(
pxe_config_path, None, boot_modes.LEGACY_BIOS, False,
diff --git a/releasenotes/notes/explicit_ipxe_config_options-d7bf9a743a13f523.yaml b/releasenotes/notes/explicit_ipxe_config_options-d7bf9a743a13f523.yaml
new file mode 100644
index 000000000..acf5daccf
--- /dev/null
+++ b/releasenotes/notes/explicit_ipxe_config_options-d7bf9a743a13f523.yaml
@@ -0,0 +1,17 @@
+---
+upgrade:
+ - |
+ Operators upgrading from earlier versions using PXE should explicitly set
+ ``[pxe]ipxe_bootfile_name``, ``[pxe]uefi_ipxe_bootfile_name``, and
+ possibly ``[pxe]ipxe_bootfile_name_by_arch`` settings, as well as a
+ iPXE specific ``[pxe]ipxe_config_template`` override, if required.
+
+ Setting the ``[pxe]ipxe_config_template`` to no value will result in the
+ ``[pxe]pxe_config_template`` being used. The default value points to the
+ supplied standard iPXE template, so only highly customized operators may
+ have to tune this setting.
+fixes:
+ - |
+ Addresses the lack of an ability to explicitly set different bootloaders
+ for ``iPXE`` and ``PXE`` based boot operations via their respective
+ ``ipxe`` and ``pxe`` boot interfaces.