From 05b951d78da284b20035f69381a4bde03e6af9ed Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Thu, 6 Jun 2024 03:08:43 -0400 Subject: [PATCH] Support dracut booting with GRUB Signed-off-by: Jonathon Anderson --- CHANGELOG.md | 4 ++- etc/grub/grub.cfg.ww | 42 ++++++++++++++++++++++++++- internal/pkg/warewulfd/provision.go | 9 ++++-- userdocs/contents/boot-management.rst | 21 ++++++++++++-- 4 files changed, 70 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eaed83f5..b44547f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,7 +41,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Add `stage=initramfs` to warewulfd provision to serve initramfs from container image. #1115 - Add `warewulf-dracut` package to support building Warewulf-compatible initramfs images with dracut. #1115 - Add iPXE template `dracut.ipxe` to boot a dracut initramfs. #1115 -- Add `.NetDevs` variable to iPXE templates, similar to overlay templates. #1115 +- Add dracut menuentry to `grub.cfg.ww` to boot a dracut initramfs. #1115 +- Add `.NetDevs` variable to iPXE and GRUB templates, similar to overlay templates. #1115 +- Add `.Tags` variable to iPXE and GRUB templates, similar to overlay templates. #1115 ### Changed diff --git a/etc/grub/grub.cfg.ww b/etc/grub/grub.cfg.ww index dcb806a0..f7ecac23 100644 --- a/etc/grub/grub.cfg.ww +++ b/etc/grub/grub.cfg.ww @@ -6,13 +6,16 @@ echo "Warewulf Controller: {{.Ipaddr}}" echo sleep 1 smbios --type1 --get-string 8 --set assetkey + uri="(http,{{.Ipaddr}}:{{.Port}})/provision/${net_default_mac}?assetkey=${assetkey}" kernel="${uri}&stage=kernel" container="${uri}&stage=container&compress=gz" system="${uri}&stage=system&compress=gz" runtime="${uri}&stage=runtime&compress=gz" -set default=ww4 + +set default={{ or .Tags.GrubMenuEntry "ww4" }} set timeout=5 + menuentry "Network boot node: {{.Id}}" --id ww4 { {{if .KernelOverride }} echo "Kernel: {{.KernelOverride}}" @@ -34,17 +37,54 @@ menuentry "Network boot node: {{.Id}}" --id ww4 { reboot fi } + +menuentry "Network boot node with dracut: {{.Id}}" --id dracut { + initramfs="${uri}&stage=initramfs" + + uri="http://{{.Ipaddr}}:{{.Port}}/provision/${net_default_mac}?assetkey=${assetkey}" + container="${uri}&stage=container&compress=gz" + system="${uri}&stage=system&compress=gz" + runtime="${uri}&stage=runtime&compress=gz" + + {{if .KernelOverride }} + echo "Kernel: {{.KernelOverride}}" + {{else}} + echo "Kernel: {{.ContainerName}} (container default)" + {{end}} + echo "KernelArgs: {{.KernelArgs}}" + + net_args="rd.neednet=1 {{range $devname, $netdev := .NetDevs}}{{if and $netdev.Hwaddr $netdev.Device}} ifname={{$netdev.Device}}:{{$netdev.Hwaddr}} {{end}}{{end}}" + wwinit_args="root=wwinit wwinit.container=${container} wwinit.system=${system} wwinit.runtime=${runtime} init=/init" + linux $kernel wwid=${net_default_mac} {{.KernelArgs}} $net_args $wwinit_args + + if [ x$? = x0 ] ; then + echo "Loading Container: {{.ContainerName}}" + initrd $initramfs + boot + else + echo "MESSAGE: This node seems to be unconfigured. Please have your system administrator add a" + echo " configuration for this node with HW address: ${net_default_mac}" + echo "" + echo "Rebooting in 1 minute..." + sleep 60 + reboot + fi +} + menuentry "Chainload specific configfile" { conf="(http,{{.Ipaddr}}:{{.Port}})/efiboot/grub.cfg" configfile $conf } + menuentry "UEFI Firmware Settings" --id "uefi-firmware" { fwsetup } + menuentry "System restart" { echo "System rebooting..." reboot } + menuentry "System shutdown" { echo "System shutting down..." halt diff --git a/internal/pkg/warewulfd/provision.go b/internal/pkg/warewulfd/provision.go index 9ef089ba..51b8d60e 100644 --- a/internal/pkg/warewulfd/provision.go +++ b/internal/pkg/warewulfd/provision.go @@ -34,6 +34,7 @@ type templateVars struct { Port string KernelArgs string KernelOverride string + Tags map[string]string NetDevs map[string]*node.NetDevs } @@ -108,7 +109,8 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) { ContainerName: node.ContainerName.Get(), KernelArgs: node.Kernel.Args.Get(), KernelOverride: node.Kernel.Override.Get(), - NetDevs: tstruct.NetDevs} + NetDevs: tstruct.NetDevs, + Tags: tstruct.Tags} } else if rinfo.stage == "kernel" { if node.Kernel.Override.Defined() { stage_file = kernel.KernelImage(node.Kernel.Override.Get()) @@ -180,6 +182,7 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) { } case "grub.cfg": stage_file = path.Join(conf.Paths.Sysconfdir, "warewulf/grub/grub.cfg.ww") + tstruct := overlay.InitStruct(&node) tmpl_data = templateVars{ Id: node.Id.Get(), Cluster: node.ClusterName.Get(), @@ -190,7 +193,9 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) { Hwaddr: rinfo.hwaddr, ContainerName: node.ContainerName.Get(), KernelArgs: node.Kernel.Args.Get(), - KernelOverride: node.Kernel.Override.Get()} + KernelOverride: node.Kernel.Override.Get(), + NetDevs: tstruct.NetDevs, + Tags: tstruct.Tags} if stage_file == "" { wwlog.ErrorExc(fmt.Errorf("could't find grub.cfg template"), containerName) w.WriteHeader(http.StatusNotFound) diff --git a/userdocs/contents/boot-management.rst b/userdocs/contents/boot-management.rst index d7bcec23..586a98f6 100644 --- a/userdocs/contents/boot-management.rst +++ b/userdocs/contents/boot-management.rst @@ -74,10 +74,27 @@ booting the node image directly. The iPXE template may be set at the node or profile level. +Alternatively, to direct GRUB to fetch the node's initramfs image and boot with +dracut semantics, set a ``GrubMenuEntry`` tag for the node. + +.. note:: + + Warewulf configures GRUB with a template located at + ``/etc/warewulf/grub/grub.cfg.ww``. Inspect the template to learn more about + the dracut booting process. + +.. code-block:: shell + + wwctl node set wwnode1 --tagadd GrubMenuEntry=dracut + +.. note:: + + The ``GrubMenuEntry`` variable may be set at the node or profile level. + During boot, ``warewulfd`` will detect and dynamically serve an initramfs from a node's container image in much the same way that it can serve a kernel from a container image. This image is loaded by -iPXE, and iPXE directs dracut to fetch the node's container image +iPXE (or GRUB) which directs dracut to fetch the node's container image during boot. The wwinit module provisions to tmpfs. By default, tmpfs is permitted @@ -88,7 +105,7 @@ more details.) .. warning:: - Kernel overrides are not currently supported during dracut initramfs boot. + Kernel overrides are not currently fully supported during dracut initramfs boot. Booting with GRUB =================