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
|
||||||
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
|
else
|
||||||
echo "r ^([^/]) $IRONIC_TFTPBOOT_DIR/\1" >$IRONIC_TFTPBOOT_DIR/map-file
|
echo "r ^([^/]) $IRONIC_TFTPBOOT_DIR/\1" >$IRONIC_TFTPBOOT_DIR/map-file
|
||||||
echo "r ^(/tftpboot/) $IRONIC_TFTPBOOT_DIR/\2" >>$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/lib64/efi/shim.efi /tftpboot/bootx64.efi
|
||||||
sudo cp /usr/lib/grub2/x86_64-efi/grub.efi /tftpboot/grubx64.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
|
#. Update the bare metal node with ``boot_mode:uefi`` capability in
|
||||||
node's properties field. See :ref:`boot_mode_support` for details.
|
node's properties field. See :ref:`boot_mode_support` for details.
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ import jinja2
|
|||||||
from oslo_concurrency import processutils
|
from oslo_concurrency import processutils
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from oslo_utils import excutils
|
from oslo_utils import excutils
|
||||||
|
from oslo_utils import fileutils
|
||||||
|
|
||||||
from ironic.common import dhcp_factory
|
from ironic.common import dhcp_factory
|
||||||
from ironic.common import exception
|
from ironic.common import exception
|
||||||
@ -1286,3 +1287,25 @@ def place_loaders_for_boot(base_path):
|
|||||||
'the requested destination. %s' % e)
|
'the requested destination. %s' % e)
|
||||||
LOG.error(msg)
|
LOG.error(msg)
|
||||||
raise exception.IncorrectConfiguration(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: '
|
'for bootloaders. Use example: '
|
||||||
'ipxe.efi:/usr/share/ipxe/ipxe-snponly-x86_64.efi,'
|
'ipxe.efi:/usr/share/ipxe/ipxe-snponly-x86_64.efi,'
|
||||||
'undionly.kpxe:/usr/share/ipxe/undionly.kpxe')),
|
'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']
|
capabilities = ['ramdisk_boot', 'pxe_boot']
|
||||||
|
|
||||||
def __init__(self):
|
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.deploy.http_root)
|
||||||
pxe_utils.place_loaders_for_boot(CONF.pxe.tftp_root)
|
pxe_utils.place_loaders_for_boot(CONF.pxe.tftp_root)
|
||||||
|
|
||||||
|
@ -152,6 +152,7 @@ class TestCase(oslo_test_base.BaseTestCase):
|
|||||||
group='neutron')
|
group='neutron')
|
||||||
self.config(enabled_hardware_types=['fake-hardware',
|
self.config(enabled_hardware_types=['fake-hardware',
|
||||||
'manual-management'])
|
'manual-management'])
|
||||||
|
self.config(initial_grub_template=None, group='pxe')
|
||||||
for iface in drivers_base.ALL_INTERFACES:
|
for iface in drivers_base.ALL_INTERFACES:
|
||||||
default = None
|
default = None
|
||||||
|
|
||||||
|
@ -1035,6 +1035,53 @@ class TestPXEUtils(db_base.DbTestCase):
|
|||||||
next(actual))
|
next(actual))
|
||||||
self.assertEqual('/tftpboot-path/' + address + '.conf', 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(ipxe.iPXEBoot, '__init__', lambda self: None)
|
||||||
@mock.patch.object(pxe.PXEBoot, '__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 oslo_utils import uuidutils
|
||||||
|
|
||||||
from ironic.common import exception
|
from ironic.common import exception
|
||||||
|
from ironic.common import pxe_utils
|
||||||
from ironic.common import states
|
from ironic.common import states
|
||||||
from ironic.conductor import manager
|
from ironic.conductor import manager
|
||||||
from ironic import objects
|
from ironic import objects
|
||||||
@ -143,8 +144,10 @@ class ServiceSetUpMixin(object):
|
|||||||
self.service.init_host()
|
self.service.init_host()
|
||||||
else:
|
else:
|
||||||
with mock.patch.object(periodics, 'PeriodicWorker', autospec=True):
|
with mock.patch.object(periodics, 'PeriodicWorker', autospec=True):
|
||||||
self.service.prepare_host()
|
with mock.patch.object(pxe_utils, 'place_common_config',
|
||||||
self.service.init_host()
|
autospec=True):
|
||||||
|
self.service.prepare_host()
|
||||||
|
self.service.init_host()
|
||||||
self.addCleanup(self._stop_service)
|
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