summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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.