Browse Source

Write initial grub config on startup

This change removes the documentation to copy master_grub_cfg.txt to
/tftpboot/grub/grub.cfg and instead writes it on conductor startup.
This grub config is a simple redirect config requested by grub network
boot. "master" has been renamed to "initial" as a more accurate label
of its function.

New configuration option [pxe]initial_grub_template allows the deployer
to specify a different initial grub template.

Change-Id: I71191dd399a6c49607f91d69b5b1673799a38624
changes/80/815580/13
Steve Baker 6 months ago
parent
commit
3f76724dfb
  1. 14
      devstack/lib/ironic
  2. 32
      doc/source/install/configure-pxe.rst
  3. 23
      ironic/common/pxe_utils.py
  4. 5
      ironic/conf/pxe.py
  5. 7
      ironic/drivers/modules/initial_grub_cfg.template
  6. 7
      ironic/drivers/modules/master_grub_cfg.txt
  7. 1
      ironic/drivers/modules/pxe.py
  8. 1
      ironic/tests/base.py
  9. 47
      ironic/tests/unit/common/test_pxe_utils.py
  10. 7
      ironic/tests/unit/conductor/mgr_utils.py
  11. 7
      releasenotes/notes/initial_grub-566688b16f773fcf.yaml

14
devstack/lib/ironic

@ -2745,20 +2745,6 @@ function configure_tftpd {
echo "re ^(^/) $IRONIC_TFTPBOOT_DIR/\1" >>$IRONIC_TFTPBOOT_DIR/map-file
echo "re ^([^/]) $IRONIC_TFTPBOOT_DIR/\1" >>$IRONIC_TFTPBOOT_DIR/map-file
# Write a grub.cfg redirect for the ubuntu grub. The fedora grub
# will fetch the generated grub.cfg-01-<mac> directly
grub_dir=$IRONIC_TFTPBOOT_DIR/grub
mkdir -p $grub_dir
cat << EOF > $grub_dir/grub.cfg
set default=master
set timeout=1
set hidden_timeout_quiet=false
menuentry "master" {
configfile $IRONIC_TFTPBOOT_DIR/\$net_default_mac.conf
}
EOF
chmod 644 $grub_dir/grub.cfg
else
echo "r ^([^/]) $IRONIC_TFTPBOOT_DIR/\1" >$IRONIC_TFTPBOOT_DIR/map-file
echo "r ^(/tftpboot/) $IRONIC_TFTPBOOT_DIR/\2" >>$IRONIC_TFTPBOOT_DIR/map-file

32
doc/source/install/configure-pxe.rst

@ -157,38 +157,6 @@ the PXE UEFI environment.
sudo cp /usr/lib64/efi/shim.efi /tftpboot/bootx64.efi
sudo cp /usr/lib/grub2/x86_64-efi/grub.efi /tftpboot/grubx64.efi
#. Create master grub.cfg:
Ubuntu: Create grub.cfg under ``/tftpboot/grub`` directory::
GRUB_DIR=/tftpboot/grub
Fedora: Create grub.cfg under ``/tftpboot/EFI/fedora`` directory::
GRUB_DIR=/tftpboot/EFI/fedora
RHEL8/CentOS8: Create grub.cfg under ``/tftpboot/EFI/centos`` directory::
GRUB_DIR=/tftpboot/EFI/centos
SUSE: Create grub.cfg under ``/tftpboot/boot/grub`` directory::
GRUB_DIR=/tftpboot/boot/grub
Create directory ``GRUB_DIR``::
sudo mkdir -p $GRUB_DIR
This file is used to redirect grub to baremetal node specific config file.
It redirects it to specific grub config file based on DHCP IP assigned to
baremetal node.
.. literalinclude:: ../../../ironic/drivers/modules/master_grub_cfg.txt
Change the permission of grub.cfg::
sudo chmod 644 $GRUB_DIR/grub.cfg
#. Update the bare metal node with ``boot_mode:uefi`` capability in
node's properties field. See :ref:`boot_mode_support` for details.

23
ironic/common/pxe_utils.py

@ -24,6 +24,7 @@ import jinja2
from oslo_concurrency import processutils
from oslo_log import log as logging
from oslo_utils import excutils
from oslo_utils import fileutils
from ironic.common import dhcp_factory
from ironic.common import exception
@ -1286,3 +1287,25 @@ def place_loaders_for_boot(base_path):
'the requested destination. %s' % e)
LOG.error(msg)
raise exception.IncorrectConfiguration(error=msg)
def place_common_config():
"""Place template generated config which is not node specific.
Currently places the initial grub config for grub network boot.
"""
if not CONF.pxe.initial_grub_template:
return
grub_dir_path = os.path.join(_get_root_dir(False), 'grub')
if not os.path.isdir(grub_dir_path):
fileutils.ensure_tree(grub_dir_path)
if CONF.pxe.dir_permission:
os.chmod(grub_dir_path, CONF.pxe.dir_permission)
initial_grub = utils.render_template(
CONF.pxe.initial_grub_template,
{'tftp_root': _get_root_dir(False)})
initial_grub_path = os.path.join(grub_dir_path, 'grub.cfg')
utils.write_to_file(initial_grub_path, initial_grub)

5
ironic/conf/pxe.py

@ -204,6 +204,11 @@ opts = [
'for bootloaders. Use example: '
'ipxe.efi:/usr/share/ipxe/ipxe-snponly-x86_64.efi,'
'undionly.kpxe:/usr/share/ipxe/undionly.kpxe')),
cfg.StrOpt('initial_grub_template',
default=os.path.join(
'$pybasedir', 'drivers/modules/initial_grub_cfg.template'),
help=_('On ironic-conductor node, the path to the initial grub'
'configuration template for grub network boot.')),
]

7
ironic/drivers/modules/initial_grub_cfg.template

@ -0,0 +1,7 @@
set default=initial
set timeout=5
set hidden_timeout_quiet=false
menuentry "initial" {
configfile {{ tftp_root }}/$net_default_mac.conf
}

7
ironic/drivers/modules/master_grub_cfg.txt

@ -1,7 +0,0 @@
set default=master
set timeout=5
set hidden_timeout_quiet=false
menuentry "master" {
configfile /tftpboot/$net_default_mac.conf
}

1
ironic/drivers/modules/pxe.py

@ -39,6 +39,7 @@ class PXEBoot(pxe_base.PXEBaseMixin, base.BootInterface):
capabilities = ['ramdisk_boot', 'pxe_boot']
def __init__(self):
pxe_utils.place_common_config()
pxe_utils.place_loaders_for_boot(CONF.deploy.http_root)
pxe_utils.place_loaders_for_boot(CONF.pxe.tftp_root)

1
ironic/tests/base.py

@ -152,6 +152,7 @@ class TestCase(oslo_test_base.BaseTestCase):
group='neutron')
self.config(enabled_hardware_types=['fake-hardware',
'manual-management'])
self.config(initial_grub_template=None, group='pxe')
for iface in drivers_base.ALL_INTERFACES:
default = None

47
ironic/tests/unit/common/test_pxe_utils.py

@ -1035,6 +1035,53 @@ class TestPXEUtils(db_base.DbTestCase):
next(actual))
self.assertEqual('/tftpboot-path/' + address + '.conf', next(actual))
@mock.patch.object(os, 'makedirs', autospec=True)
@mock.patch.object(os.path, 'isdir', autospec=True)
@mock.patch.object(os, 'chmod', autospec=True)
def test_place_common_config(self, mock_chmod, mock_isdir,
mock_makedirs):
self.config(initial_grub_template=os.path.join(
'$pybasedir',
'drivers/modules/initial_grub_cfg.template'),
group='pxe')
mock_isdir.return_value = False
self.config(group='pxe', dir_permission=0o777)
def write_to_file(path, contents):
self.assertEqual('/tftpboot/grub/grub.cfg', path)
self.assertIn(
'configfile /tftpboot/$net_default_mac.conf',
contents
)
with mock.patch('ironic.common.utils.write_to_file',
wraps=write_to_file):
pxe_utils.place_common_config()
mock_isdir.assert_called_once_with('/tftpboot/grub')
mock_makedirs.assert_called_once_with('/tftpboot/grub', 511)
mock_chmod.assert_called_once_with('/tftpboot/grub', 0o777)
@mock.patch.object(os, 'makedirs', autospec=True)
@mock.patch.object(os.path, 'isdir', autospec=True)
@mock.patch.object(os, 'chmod', autospec=True)
def test_place_common_config_existing_dirs(self, mock_chmod, mock_isdir,
mock_makedirs):
self.config(initial_grub_template=os.path.join(
'$pybasedir',
'drivers/modules/initial_grub_cfg.template'),
group='pxe')
mock_isdir.return_value = True
with mock.patch('ironic.common.utils.write_to_file',
autospec=True) as mock_write:
pxe_utils.place_common_config()
mock_write.assert_called_once()
mock_isdir.assert_called_once_with('/tftpboot/grub')
mock_makedirs.assert_not_called()
mock_chmod.assert_not_called()
@mock.patch.object(ipxe.iPXEBoot, '__init__', lambda self: None)
@mock.patch.object(pxe.PXEBoot, '__init__', lambda self: None)

7
ironic/tests/unit/conductor/mgr_utils.py

@ -24,6 +24,7 @@ from oslo_utils import strutils
from oslo_utils import uuidutils
from ironic.common import exception
from ironic.common import pxe_utils
from ironic.common import states
from ironic.conductor import manager
from ironic import objects
@ -143,8 +144,10 @@ class ServiceSetUpMixin(object):
self.service.init_host()
else:
with mock.patch.object(periodics, 'PeriodicWorker', autospec=True):
self.service.prepare_host()
self.service.init_host()
with mock.patch.object(pxe_utils, 'place_common_config',
autospec=True):
self.service.prepare_host()
self.service.init_host()
self.addCleanup(self._stop_service)

7
releasenotes/notes/initial_grub-566688b16f773fcf.yaml

@ -0,0 +1,7 @@
---
features:
- |
Manually copying the initial grub config for grub network boot is no longer
necessary, as this file is now written to the TFTP root directory on
conductor startup. A custom template can be used to generate this file with
config option ``[pxe]initial_grub_template``.
Loading…
Cancel
Save