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
This commit is contained in:
parent
45e8adc1df
commit
3f76724dfb
@ -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
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
Normal file
7
ironic/drivers/modules/initial_grub_cfg.template
Normal file
@ -0,0 +1,7 @@
|
||||
set default=initial
|
||||
set timeout=5
|
||||
set hidden_timeout_quiet=false
|
||||
|
||||
menuentry "initial" {
|
||||
configfile {{ tftp_root }}/$net_default_mac.conf
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
set default=master
|
||||
set timeout=5
|
||||
set hidden_timeout_quiet=false
|
||||
|
||||
menuentry "master" {
|
||||
configfile /tftpboot/$net_default_mac.conf
|
||||
}
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
Normal file
7
releasenotes/notes/initial_grub-566688b16f773fcf.yaml
Normal file
@ -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…
Reference in New Issue
Block a user