Merge pull request #1742 from anderbubble/wwinit-logging

Improved logging during iPXE, GRUB, and wwinit
This commit is contained in:
Christian Goll
2025-02-20 10:32:11 +01:00
committed by GitHub
18 changed files with 525 additions and 309 deletions

View File

@@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Added `WW_HISTFILE` to control shell history location during `wwctl image shell`. #1732 - Added `WW_HISTFILE` to control shell history location during `wwctl image shell`. #1732
- Added target help in Makefile. #1740 - Added target help in Makefile. #1740
- Added fstab mounts for `/home` and `/opt` to initial default profile. #1744 - Added fstab mounts for `/home` and `/opt` to initial default profile. #1744
- Add support for an `IPXEMenuEntry` tag to select the boot method during iPXE.
### Changed ### Changed
@@ -30,6 +31,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Update syncuser documentation. #1736 - Update syncuser documentation. #1736
- Update PS1 during `wwctl image shell` to include working directory by default, - Update PS1 during `wwctl image shell` to include working directory by default,
and to include `PS1` from the environment if present. #1245 and to include `PS1` from the environment if present. #1245
- DHCP template generates as much of the subnet and range definition as possible. #1469
- Updated overlay flags to `wwctl <node|profile> <add|set> [--runtime-overlays|--system-overlays]`. #1495
- Added logging and updated output during iPXE and GRUB. #1156
- Defined a menu for iPXE. #1156
- Added logging to wwinit scripts. #1156
- Renamed /warewulf/wwinit to /warewulf/prescripts. #1156
- Display auto-detected kernel version during iPXE and GRUB. #1742
### Fixed ### Fixed
@@ -49,6 +57,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Remove syncuser warning messages in `wwctl` that assume its use. #1321 - Remove syncuser warning messages in `wwctl` that assume its use. #1321
- Remove syncuser from the list of default runtime overlays. #1322 - Remove syncuser from the list of default runtime overlays. #1322
- Removed check for "discoverable" profiles during `wwctl upgrade nodes`. - Removed check for "discoverable" profiles during `wwctl upgrade nodes`.
- Removed `dracut.ipxe` template. (Use `default.ipxe` and set tag `IPXEMenuEntry=dracut`.)
## v4.6.0rc2, 2025-02-07 ## v4.6.0rc2, 2025-02-07

View File

@@ -216,7 +216,7 @@ install: build docs ## Install Warewulf from source
(cd overlays && find * -path '*/internal' -prune -o -type d -exec mkdir -pv $(DESTDIR)$(DATADIR)/warewulf/overlays/{} \;) (cd overlays && find * -path '*/internal' -prune -o -type d -exec mkdir -pv $(DESTDIR)$(DATADIR)/warewulf/overlays/{} \;)
(cd overlays && find * -path '*/internal' -prune -o -type l -exec cp -av {} $(DESTDIR)$(DATADIR)/warewulf/overlays/{} \;) (cd overlays && find * -path '*/internal' -prune -o -type l -exec cp -av {} $(DESTDIR)$(DATADIR)/warewulf/overlays/{} \;)
chmod 0755 $(DESTDIR)$(DATADIR)/warewulf/overlays/wwinit/rootfs/init chmod 0755 $(DESTDIR)$(DATADIR)/warewulf/overlays/wwinit/rootfs/init
chmod 0755 $(DESTDIR)$(DATADIR)/warewulf/overlays/wwinit/rootfs/$(WWCLIENTDIR)/wwinit chmod 0755 $(DESTDIR)$(DATADIR)/warewulf/overlays/wwinit/rootfs/$(WWCLIENTDIR)/wwprescripts
chmod 0600 $(DESTDIR)$(DATADIR)/warewulf/overlays/wwinit/rootfs/$(WWCLIENTDIR)/config.ww chmod 0600 $(DESTDIR)$(DATADIR)/warewulf/overlays/wwinit/rootfs/$(WWCLIENTDIR)/config.ww
chmod 0600 $(DESTDIR)$(DATADIR)/warewulf/overlays/ssh.host_keys/rootfs/etc/ssh/ssh* chmod 0600 $(DESTDIR)$(DATADIR)/warewulf/overlays/ssh.host_keys/rootfs/etc/ssh/ssh*
chmod 0644 $(DESTDIR)$(DATADIR)/warewulf/overlays/ssh.host_keys/rootfs/etc/ssh/ssh*.pub.ww chmod 0644 $(DESTDIR)$(DATADIR)/warewulf/overlays/ssh.host_keys/rootfs/etc/ssh/ssh*.pub.ww

View File

@@ -1,77 +1,170 @@
{{ if .ImageName }}
echo "================================================================================"
echo "Warewulf v4 now http booting grub: {{.Fqdn}} ({{.Hwaddr}})"
echo "================================================================================"
echo echo
echo "Warewulf Controller: {{.Ipaddr}}" echo "Warewulf v4 (GRUB)"
echo echo
sleep 1 echo "Warewulf Server:"
echo "* Ipaddr: {{.Ipaddr}}"
echo "* Port: {{.Port}}"
echo
echo "This node:"
echo "* Fqdn: {{.Fqdn}}"
echo "* Hwaddr: {{.Hwaddr}}"
echo "* ImageName: {{.ImageName}}"
{{- if .KernelVersion }}
echo "* KernelVersion: {{.KernelVersion}}"
{{- else }}
echo "* KernelVersion: (image default)"
{{- end }}
echo "* KernelArgs: {{.KernelArgs}}"
{{- if not .ImageName }}
echo "!!"
echo "!! No image defined for {{.Fqdn}}."
echo "!! Rebooting in 30s...
echo "!!"
sleep 30
reboot
{{- end }}
echo "Reading asset key..."
smbios --type 3 --get-string 8 --set assetkey smbios --type 3 --get-string 8 --set assetkey
uri="(http,{{.Ipaddr}}:{{.Port}})/provision/${net_default_mac}?assetkey=${assetkey}" uri="(http,{{.Ipaddr}}:{{.Port}})/provision/${net_default_mac}?assetkey=${assetkey}"
kernel="${uri}&stage=kernel" kernel="${uri}&stage=kernel"
image="${uri}&stage=image&compress=gz"
system="${uri}&stage=system&compress=gz"
runtime="${uri}&stage=runtime&compress=gz"
set default={{ or .Tags.GrubMenuEntry "ww4" }} set default={{ or .Tags.GrubMenuEntry "single-stage" }}
set timeout=5 set timeout=2
menuentry "Network boot node: {{.Id}}" --id ww4 { menuentry "Single-stage boot" --id single-stage {
{{if .KernelVersion }} echo "Warewulf Server:"
echo "Kernel: {{.KernelVersion}}" echo "* Ipaddr: {{.Ipaddr}}"
{{else}} echo "* Port: {{.Port}}"
echo "Kernel: {{.ImageName}} (image default)" echo
{{end}} echo "This node:"
echo "KernelArgs: {{.KernelArgs}}" echo "* Fqdn: {{.Fqdn}}"
echo "* Hwaddr: {{.Hwaddr}}"
echo "* ImageName: {{.ImageName}}"
{{- if .KernelVersion }}
echo "* KernelVersion: {{.KernelVersion}}"
{{- else }}
echo "* KernelVersion: (image default)"
{{- end }}
echo "* KernelArgs: {{.KernelArgs}}"
echo
echo "Downloading kernel image..."
linux $kernel wwid=${net_default_mac} {{.KernelArgs}} linux $kernel wwid=${net_default_mac} {{.KernelArgs}}
if [ x$? = x0 ] ; then if [ $? != 0 ]
echo "Loading Image: {{.ImageName}}" then
initrd $image $system $runtime echo "!!"
boot echo "!! Unable to load kernel."
else echo "!! Rebooting in 15s..."
echo "MESSAGE: This node seems to be unconfigured. Please have your system administrator add a" echo "!!"
echo " configuration for this node with HW address: ${net_default_mac}"
echo ""
echo "Rebooting in 1 minute..."
sleep 60
reboot
fi fi
echo "Downloading images..."
image="${uri}&stage=image&compress=gz"
system="${uri}&stage=system&compress=gz"
runtime="${uri}&stage=runtime&compress=gz"
initrd $image $system $runtime
if [ $? != 0 ]
then
echo "!!"
echo "!! Unable to load images."
echo "!! Rebooting in 15s..."
echo "!!"
fi
echo "Booting..."
boot
} }
menuentry "Network boot node with dracut: {{.Id}}" --id dracut { menuentry "Single-stage boot (no compression)" --id single-stage-nocompress {
echo "Warewulf Server:"
echo "* Ipaddr: {{.Ipaddr}}"
echo "* Port: {{.Port}}"
echo
echo "This node:"
echo "* Fqdn: {{.Fqdn}}"
echo "* Hwaddr: {{.Hwaddr}}"
echo "* ImageName: {{.ImageName}}"
{{- if .KernelVersion }}
echo "* KernelVersion: {{.KernelVersion}}"
{{- else }}
echo "* KernelVersion: (image default)"
{{- end }}
echo "* KernelArgs: {{.KernelArgs}}"
echo
echo "Downloading kernel image..."
linux $kernel wwid=${net_default_mac} {{.KernelArgs}}
if [ $? != 0 ]
then
echo "!!"
echo "!! Unable to load kernel."
echo "!! Rebooting in 15s..."
echo "!!"
fi
echo "Downloading images..."
image="${uri}&stage=image"
system="${uri}&stage=system"
runtime="${uri}&stage=runtime"
initrd $image $system $runtime
if [ $? != 0 ]
then
echo "!!"
echo "!! Unable to load images."
echo "!! Rebooting in 15s..."
echo "!!"
fi
echo "Booting..."
boot
}
menuentry "Two stage boot with dracut" --id dracut {
echo "Warewulf Server:"
echo "* Ipaddr: {{.Ipaddr}}"
echo "* Port: {{.Port}}"
echo
echo "This node:"
echo "* Fqdn: {{.Fqdn}}"
echo "* Hwaddr: {{.Hwaddr}}"
echo "* ImageName: {{.ImageName}}"
{{- if .KernelVersion }}
echo "* KernelVersion: {{.KernelVersion}}"
{{- else }}
echo "* KernelVersion: (image default)"
{{- end }}
echo "* KernelArgs: {{.KernelArgs}}"
initramfs="${uri}&stage=initramfs" initramfs="${uri}&stage=initramfs"
wwinit_uri="http://{{.Ipaddr}}:{{.Port}}/provision/${net_default_mac}" wwinit_uri="http://{{.Ipaddr}}:{{.Port}}/provision/${net_default_mac}"
{{if .KernelVersion }}
echo "Kernel: {{.KernelVersion}}"
{{else}}
echo "Kernel: {{.ImageName}} (image 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}}" 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.uri=${wwinit_uri} init=/init" wwinit_args="root=wwinit wwinit.uri=${wwinit_uri} init=/init"
echo
echo "Downloading kernel image..."
linux $kernel wwid=${net_default_mac} {{.KernelArgs}} $net_args $wwinit_args linux $kernel wwid=${net_default_mac} {{.KernelArgs}} $net_args $wwinit_args
if [ $? != 0 ]
if [ x$? = x0 ] ; then then
echo "Loading Image: {{.ImageName}}" echo "!!"
initrd $initramfs echo "!! Unable to load kernel."
boot echo "!! Rebooting in 15s..."
else echo "!!"
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 fi
}
menuentry "Chainload specific configfile" { echo "Downloading initramfs..."
conf="(http,{{.Ipaddr}}:{{.Port}})/efiboot/grub.cfg?assetkey=${assetkey}" initrd $initramfs
configfile $conf if [ $? != 0 ]
then
echo "!!"
echo "!! Unable to load initramfs."
echo "!! Rebooting in 15s..."
echo "!!"
fi
echo "Booting..."
boot
} }
menuentry "UEFI Firmware Settings" --id "uefi-firmware" { menuentry "UEFI Firmware Settings" --id "uefi-firmware" {
@@ -87,12 +180,3 @@ menuentry "System shutdown" {
echo "System shutting down..." echo "System shutting down..."
halt halt
} }
{{ else }}
echo "================================================================================"
echo " Warewulf v4:"
echo " No node image defined for this node ({{.Fqdn}})."
echo " Rebooting in 30s."
echo "================================================================================"
sleep 30
reboot
{{ end }}

View File

@@ -1,94 +1,129 @@
#!ipxe #!ipxe
{{ if .ImageName }} echo
echo echo Warewulf v4 (iPXE)
echo ================================================================================
echo Warewulf v4 now booting: {{.Fqdn}} ({{.Hwaddr}})
echo
echo Image: {{.ImageName}}
{{if .KernelVersion }}
echo Kernel: {{.KernelVersion}}
{{else}}
echo Kernel: {{.ImageName}} (image default)
{{end}}
echo KernelArgs: {{.KernelArgs}}
echo echo
set next start
goto metadata
set uri_base http://{{.Ipaddr}}:{{.Port}}/provision/{{.Hwaddr}}?assetkey=${asset}&uuid=${uuid} :start
echo Warewulf Controller: {{.Ipaddr}} {{- if not .ImageName }}
echo !!
echo Downloading Kernel Image: echo !! No image defined for {{.Fqdn}}.
kernel --name kernel ${uri_base}&stage=kernel || goto reboot echo !! Rebooting in 30s...
echo !!
# imgextract causes RAM space problems on non-EFI systems (because of the 3GB barrier
# in 32-Bit mode).
# -> Use the old initrd method with a compressed image to save as much RAM as possible
# in this early boot stage.
# See <https://github.com/warewulf/warewulf/issues/222> for more details.
iseq ${platform} efi && goto efi || goto noefi
:efi
# try extracting compressed images first
# NOTE: system overlay tends to be the smallest, so failure here is the cheapest
echo Downloading Image:
imgextract --name image ${uri_base}&stage=image&compress=gz || goto nocompress
echo Downloading System Overlay:
imgextract --name system ${uri_base}&stage=system&compress=gz || goto reboot
echo Downloading Runtime Overlay:
imgextract --name runtime ${uri_base}&stage=runtime&compress=gz && set runtime_initrd initrd=runtime || echo Failed downloading runtime overlay.
goto imoktogo
:nocompress
echo
echo Image extract not supported in this iPXE, using standard initrd mode
echo Downloading Image:
initrd --name image ${uri_base}&stage=image || goto reboot
echo Downloading System Overlay:
initrd --name system ${uri_base}&stage=system || goto reboot
echo Downloading Runtime Overlay:
initrd --name runtime ${uri_base}&stage=runtime && set runtime_initrd initrd=runtime || echo Failed downloading runtime overlay.
goto imoktogo
:noefi
echo
echo Use legacy initrd mode with compressed images
echo Downloading Image:
initrd --name image ${uri_base}&stage=image&compress=gz || goto reboot
echo Downloading System Overlay:
initrd --name system ${uri_base}&stage=system&compress=gz || goto reboot
echo Downloading Runtime Overlay:
initrd --name runtime ${uri_base}&stage=runtime&compress=gz && set runtime_initrd initrd=runtime || echo Failed downloading runtime overlay.
:imoktogo
echo boot kernel initrd=image initrd=system ${runtime_initrd} wwid={{.Hwaddr}} {{.KernelArgs}}
boot kernel initrd=image initrd=system ${runtime_initrd} wwid={{.Hwaddr}} {{.KernelArgs}} || goto reboot
:reboot
echo
echo There was an error, rebooting in 15s...
echo
sleep 15
reboot
{{ else }}
echo ================================================================================
echo Warewulf v4:
echo No image defined for this node ({{.Fqdn}}).
echo Rebooting in 30s.
echo ================================================================================
sleep 30 sleep 30
reboot reboot
{{ end }} {{- end }}
set baseuri http://{{.Ipaddr}}:{{.Port}}/provision/{{.Hwaddr}}
set uri ${baseuri}?assetkey=${asset}&uuid=${uuid}
echo Downloading kernel image...
kernel --name kernel ${uri}&stage=kernel || goto reboot
{{- if .Tags.IPXEMenuEntry }}
set method {{ .Tags.IPXEMenuEntry }}
{{- else }}
# https://github.com/warewulf/warewulf/issues/222
iseq ${platform} efi && set method imgextract || set method initrd
{{- end }}
:menu
menu Warewulf v4 image provisioning method
item imgextract Single-stage with imgextract
item initrd Single-stage with initrd
item initrd_nocompress Single stage with initrd (no compression)
item dracut Two stage with dracut
item shell iPXE shell
choose --default ${method} --timeout 2000 method && goto ${method} || goto menu
:imgextract
set next imgextract_continue
goto metadata
:imgextract_continue
echo
echo Downloading compressed image with imgextract...
imgextract --name image ${uri}&stage=image&compress=gz || goto error_use_initrd
echo Downloading compressed system overlay image with imgextract...
imgextract --name system ${uri}&stage=system&compress=gz || goto error_reboot
echo Downloading compressed runtime overlay image with imgextract...
imgextract --name runtime ${uri}&stage=runtime&compress=gz && set runtime_initrd initrd=runtime || echo Unable to download runtime overlay. (ignored)
goto boot_single_stage
:error_use_initrd
echo Encountered an error. Now using initrd.
goto initrd_continue
:initrd
set next initrd_continue
goto metadata
:initrd_continue
echo
echo Downloading compressed image with initrd...
initrd --name image ${uri}&stage=image&compress=gz || goto error_reboot
echo Downloading compressed system overlay with initrd...
initrd --name system ${uri}&stage=system&compress=gz || goto error_reboot
echo Downloading compressed runtime overlay with initrd...
initrd --name runtime ${uri}&stage=runtime&compress=gz && set runtime_initrd initrd=runtime || echo Unable to download runtime overlay. (ignored)
goto boot_single_stage
:initrd_nocompress
set next initrd_nocompress_continue
goto metadata
:initrd_nocompress_continue
echo
echo Downloading uncompressed image with initrd...
initrd --name image ${uri}&stage=image || goto error_reboot
echo Downloading uncompressed system overlay with initrd...
initrd --name system ${uri}&stage=system || goto error_reboot
echo Downloading uncompressed runtime overlay with initrd...
initrd --name runtime ${uri}&stage=runtime && set runtime_initrd initrd=runtime || echo Unable to download runtime overlay. (ignored)
goto boot_single_stage
:dracut
set next dracut_continue
goto metadata
:dracut_continue
echo
echo Downloading dracut initramfs...
initrd --name initramfs ${uri}&stage=initramfs || goto error_reboot
set dracut_net rd.neednet=1 {{range $devname, $netdev := .NetDevs}}{{if and $netdev.Hwaddr $netdev.Device}} ifname={{$netdev.Device}}:{{$netdev.Hwaddr}} ip={{$netdev.Device}}:dhcp {{end}}{{end}}
set dracut_wwinit root=wwinit wwinit.uri=${baseuri} init=/init
goto boot_two_stage_dracut
:boot_single_stage
echo Booting (single stage)...
boot kernel initrd=image initrd=system ${runtime_initrd} wwid={{.Hwaddr}} {{.KernelArgs}} || goto error_reboot
:boot_two_stage_dracut
echo Booting dracut (first stage)...
boot kernel initrd=initramfs ${dracut_net} ${dracut_wwinit} wwid={{.Hwaddr}} {{.KernelArgs}} || error_reboot
:error_reboot
echo !!
echo !! Encountered an error.
echo !! rebooting in 15s...
echo !!
sleep 15
reboot
:shell
shell
goto menu
:metadata
echo Warewulf Server:
echo * Ipaddr: {{.Ipaddr}}
echo * Port: {{.Port}}
echo
echo This node:
echo * Fqdn: {{.Fqdn}}
echo * Hwaddr: {{.Hwaddr}}
echo * ImageName: {{.ImageName}}
{{- if .KernelVersion }}
echo * KernelVersion: {{.KernelVersion}}
{{- else }}
echo * KernelVersion: (image default)
{{- end }}
echo * KernelArgs: {{.KernelArgs}}
goto ${next}

View File

@@ -1,47 +0,0 @@
#!ipxe
{{ if .ImageName }}
echo
echo ================================================================================
echo Warewulf v4 now booting via dracut: {{.Fqdn}} ({{.Hwaddr}})
echo
echo Image: {{.ImageName}}
{{if .KernelVersion }}
echo Kernel: {{.KernelVersion}}
{{else}}
echo Kernel: {{.ImageName}} (image default)
{{end}}
echo KernelArgs: {{.KernelArgs}}
echo
set baseuri http://{{.Ipaddr}}:{{.Port}}/provision/{{.Hwaddr}}
set uri ${baseuri}?assetkey=${asset}&uuid=${uuid}
echo Warewulf Controller: {{.Ipaddr}}
echo Downloading Kernel Image:
kernel --name kernel ${uri}&stage=kernel || goto reboot
echo Downloading initramfs
initrd --name initramfs ${uri}&stage=initramfs || goto reboot
set dracut_net rd.neednet=1 {{range $devname, $netdev := .NetDevs}}{{if and $netdev.Hwaddr $netdev.Device}} ifname={{$netdev.Device}}:{{$netdev.Hwaddr}} ip={{$netdev.Device}}:dhcp {{end}}{{end}}
set dracut_wwinit root=wwinit wwinit.uri=${baseuri} init=/init
echo Booting initramfs
boot kernel initrd=initramfs ${dracut_net} ${dracut_wwinit} wwid={{.Hwaddr}} {{.KernelArgs}}
:reboot
echo
echo There was an error, rebooting in 15s...
echo
sleep 15
reboot
{{ else }}
echo ================================================================================
echo Warewulf v4:
echo No image defined for this node ({{.Fqdn}}).
echo Rebooting in 30s.
echo ================================================================================
sleep 30
reboot
{{ end }}

48
init.bak Executable file
View File

@@ -0,0 +1,48 @@
#!/bin/sh
echo "Warewulf pre-init (/init)"
echo
echo "Mounting kernel file systems..."
mountpoint -q /proc || (mkdir -p /proc && mount -t proc proc /proc && echo "Mounted /proc")
mountpoint -q /dev || (mkdir -p /dev && mount -t devtmpfs devtmpfs /dev && echo "Mounted /dev")
mountpoint -q /sys || (mkdir -p /sys && mount -t sysfs sysfs /sys && echo "Mounted /sys")
echo
echo "Loading /warewulf/config..."
if [ -f "/warewulf/config" ]; then
. /warewulf/config
else
echo "ERROR: Warewulf configuration file not found."
echo "Rebooting in 1 minute..."
sleep 60
echo b > /proc/sysrq-trigger || /sbin/reboot -f
fi
echo
echo "Configuring root file system..."
WWPRESCRIPTS=/warewulf/wwprescripts
chmod +rx "${WWPRESCRIPTS}"
WWROOT="${WWROOT:-initramfs}"
if [ "${WWROOT}" = "initramfs" ]; then
echo "WWROOT=${WWROOT}: using initial rootfs and invoking ${WWPRESCRIPTS}..."
exec "${WWPRESCRIPTS}"
elif [ "${WWROOT}" = "ramfs" -o "${WWROOT}" = "tmpfs" ]; then
echo "WWROOT=${WWROOT}: setting up new ${WWROOT} rootfs (/newroot)..."
mkdir /newroot
mount wwroot /newroot -t ${WWROOT} -o mpol=interleave # mpol ignored for ramfs
tar -cf - --exclude ./proc --exclude ./sys --exclude ./dev --exclude --exclude ./newroot . | tar -xf - -C /newroot
mkdir /newroot/proc /newroot/dev /newroot/sys 2>/dev/null
echo "Switching to new rootfs (/newroot) and invoking ${WWPRESCRIPTS}..."
exec /sbin/switch_root /newroot "${WWPRESCRIPTS}"
else
echo "ERROR: Unrecognized rootfs type requested: ${WWROOT}"
echo "Rebooting in 1 minute..."
sleep 60
echo b > /proc/sysrq-trigger || /sbin/reboot -f
fi
echo
echo "ERROR: wwinit encountered a problem."
echo "Rebooting in 1 minute..."
sleep 60
echo b > /proc/sysrq-trigger || /sbin/reboot -f

View File

@@ -165,6 +165,7 @@ type Node struct {
func (legacy *Node) Upgrade(addDefaults bool, replaceOverlays bool) (upgraded *node.Node) { func (legacy *Node) Upgrade(addDefaults bool, replaceOverlays bool) (upgraded *node.Node) {
upgraded = new(node.Node) upgraded = new(node.Node)
upgraded.Tags = make(map[string]string) upgraded.Tags = make(map[string]string)
upgraded.Resources = make(map[string]node.Resource)
upgraded.Disks = make(map[string]*node.Disk) upgraded.Disks = make(map[string]*node.Disk)
upgraded.FileSystems = make(map[string]*node.FileSystem) upgraded.FileSystems = make(map[string]*node.FileSystem)
upgraded.Ipmi = new(node.IpmiConf) upgraded.Ipmi = new(node.IpmiConf)
@@ -226,7 +227,31 @@ func (legacy *Node) Upgrade(addDefaults bool, replaceOverlays bool) (upgraded *n
if upgraded.Ipmi.Write == "" && legacy.IpmiWrite != "" { if upgraded.Ipmi.Write == "" && legacy.IpmiWrite != "" {
warnError(upgraded.Ipmi.Write.Set(legacy.IpmiWrite)) warnError(upgraded.Ipmi.Write.Set(legacy.IpmiWrite))
} }
upgraded.Ipxe = legacy.Ipxe if legacy.Keys != nil {
for key, value := range legacy.Keys {
upgraded.Tags[key] = value
}
}
if legacy.Tags != nil {
for key, value := range legacy.Tags {
upgraded.Tags[key] = value
}
}
for _, tag := range legacy.TagsDel {
delete(upgraded.Tags, tag)
}
if legacy.Ipxe == "dracut" {
if _, ok := upgraded.Tags["IPXEMenuEntry"]; !ok {
wwlog.Info("Replacing ipxe template 'dracut' with 'default' and setting tag 'IPXEMenuEntry=dracut'")
upgraded.Ipxe = "default"
upgraded.Tags["IPXEMenuEntry"] = "dracut"
} else {
wwlog.Warn("Found ipxe template 'dracut' but tag 'IPXEMenuEntry' is already set; ignoring")
upgraded.Ipxe = legacy.Ipxe
}
} else {
upgraded.Ipxe = legacy.Ipxe
}
if legacy.Kernel != nil { if legacy.Kernel != nil {
upgraded.Kernel = legacy.Kernel.Upgrade(upgraded.ImageName) upgraded.Kernel = legacy.Kernel.Upgrade(upgraded.ImageName)
} else { } else {
@@ -237,11 +262,6 @@ func (legacy *Node) Upgrade(addDefaults bool, replaceOverlays bool) (upgraded *n
} }
upgraded.Kernel = inlineKernel.Upgrade(upgraded.ImageName) upgraded.Kernel = inlineKernel.Upgrade(upgraded.ImageName)
} }
if legacy.Keys != nil {
for key, value := range legacy.Keys {
upgraded.Tags[key] = value
}
}
if legacy.NetDevs != nil { if legacy.NetDevs != nil {
for name, netDev := range legacy.NetDevs { for name, netDev := range legacy.NetDevs {
upgraded.NetDevs[name] = netDev.Upgrade(false) upgraded.NetDevs[name] = netDev.Upgrade(false)
@@ -313,14 +333,11 @@ func (legacy *Node) Upgrade(addDefaults bool, replaceOverlays bool) (upgraded *n
genericSplitOverlays) genericSplitOverlays)
} }
} }
if legacy.Tags != nil { if legacy.Resources != nil {
for key, value := range legacy.Tags { for key, value := range legacy.Resources {
upgraded.Tags[key] = value upgraded.Resources[key] = value
} }
} }
for _, tag := range legacy.TagsDel {
delete(upgraded.Tags, tag)
}
return return
} }
@@ -427,7 +444,31 @@ func (legacy *Profile) Upgrade(addDefaults bool, replaceOverlays bool) (upgraded
if upgraded.Ipmi.Write == "" && legacy.IpmiWrite != "" { if upgraded.Ipmi.Write == "" && legacy.IpmiWrite != "" {
warnError(upgraded.Ipmi.Write.Set(legacy.IpmiWrite)) warnError(upgraded.Ipmi.Write.Set(legacy.IpmiWrite))
} }
upgraded.Ipxe = legacy.Ipxe if legacy.Keys != nil {
for key, value := range legacy.Keys {
upgraded.Tags[key] = value
}
}
if legacy.Tags != nil {
for key, value := range legacy.Tags {
upgraded.Tags[key] = value
}
}
for _, tag := range legacy.TagsDel {
delete(upgraded.Tags, tag)
}
if legacy.Ipxe == "dracut" {
if _, ok := upgraded.Tags["IPXEMenuEntry"]; !ok {
wwlog.Info("Replacing ipxe template 'dracut' with 'default' and setting tag 'IPXEMenuEntry=dracut'")
upgraded.Ipxe = "default"
upgraded.Tags["IPXEMenuEntry"] = "dracut"
} else {
wwlog.Warn("Found ipxe template 'dracut' but tag 'IPXEMenuEntry' is already set; ignoring")
upgraded.Ipxe = legacy.Ipxe
}
} else {
upgraded.Ipxe = legacy.Ipxe
}
if legacy.Kernel != nil { if legacy.Kernel != nil {
upgraded.Kernel = legacy.Kernel.Upgrade(upgraded.ImageName) upgraded.Kernel = legacy.Kernel.Upgrade(upgraded.ImageName)
} else { } else {
@@ -438,11 +479,6 @@ func (legacy *Profile) Upgrade(addDefaults bool, replaceOverlays bool) (upgraded
} }
upgraded.Kernel = inlineKernel.Upgrade(upgraded.ImageName) upgraded.Kernel = inlineKernel.Upgrade(upgraded.ImageName)
} }
if legacy.Keys != nil {
for key, value := range legacy.Keys {
upgraded.Tags[key] = value
}
}
if legacy.NetDevs != nil { if legacy.NetDevs != nil {
for name, netDev := range legacy.NetDevs { for name, netDev := range legacy.NetDevs {
upgraded.NetDevs[name] = netDev.Upgrade(addDefaults) upgraded.NetDevs[name] = netDev.Upgrade(addDefaults)
@@ -503,14 +539,6 @@ func (legacy *Profile) Upgrade(addDefaults bool, replaceOverlays bool) (upgraded
genericSplitOverlays) genericSplitOverlays)
} }
} }
if legacy.Tags != nil {
for key, value := range legacy.Tags {
upgraded.Tags[key] = value
}
}
for _, tag := range legacy.TagsDel {
delete(upgraded.Tags, tag)
}
if legacy.Resources != nil { if legacy.Resources != nil {
for key, value := range legacy.Resources { for key, value := range legacy.Resources {
upgraded.Resources[key] = value upgraded.Resources[key] = value

View File

@@ -254,7 +254,7 @@ nodes:
`, `,
}, },
{ {
name: "keys and tags", name: "keys, tags, and resources",
addDefaults: false, addDefaults: false,
replaceOverlays: false, replaceOverlays: false,
legacyYaml: ` legacyYaml: `
@@ -269,6 +269,13 @@ nodeprofiles:
key4: valD key4: valD
tagsdel: tagsdel:
- key4 - key4
resources:
res1:
- val1a
- val1b
res2:
- val2a
- val2b
network devices: network devices:
default: default:
tags: tags:
@@ -295,6 +302,13 @@ nodes:
key4: valD key4: valD
tagsdel: tagsdel:
- key4 - key4
resources:
resn1:
- valn1a
- valn1b
resn2:
- valn2a
- valn2b
network devices: network devices:
default: default:
tags: tags:
@@ -327,6 +341,13 @@ nodeprofiles:
key1: val1 key1: val1
key2: valB key2: valB
key3: valC key3: valC
resources:
res1:
- val1a
- val1b
res2:
- val2a
- val2b
nodes: nodes:
n1: n1:
ipmi: ipmi:
@@ -342,6 +363,13 @@ nodes:
key1: val1 key1: val1
key2: valB key2: valB
key3: valC key3: valC
resources:
resn1:
- valn1a
- valn1b
resn2:
- valn2a
- valn2b
`, `,
}, },
{ {
@@ -852,6 +880,29 @@ nfs:
mount: true mount: true
- path: /var - path: /var
mount: false mount: false
`,
},
{
name: "Replace dracut template with IPXEMenuEntry",
legacyYaml: `
nodeprofiles:
default:
ipxe template: dracut
nodes:
n1:
ipxe template: dracut
`,
upgradedYaml: `
nodeprofiles:
default:
ipxe template: default
tags:
IPXEMenuEntry: dracut
nodes:
n1:
ipxe template: default
tags:
IPXEMenuEntry: dracut
`, `,
}, },
} }

View File

@@ -104,6 +104,11 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) {
kernelArgs = strings.Join(remoteNode.Kernel.Args, " ") kernelArgs = strings.Join(remoteNode.Kernel.Args, " ")
kernelVersion = remoteNode.Kernel.Version kernelVersion = remoteNode.Kernel.Version
} }
if kernelVersion == "" {
if kernel_ := kernel.FromNode(&remoteNode); kernel_ != nil {
kernelVersion = kernel_.Version()
}
}
tmpl_data = &templateVars{ tmpl_data = &templateVars{
Id: remoteNode.Id(), Id: remoteNode.Id(),
Cluster: remoteNode.ClusterName, Cluster: remoteNode.ClusterName,
@@ -186,6 +191,11 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) {
kernelArgs = strings.Join(remoteNode.Kernel.Args, " ") kernelArgs = strings.Join(remoteNode.Kernel.Args, " ")
kernelVersion = remoteNode.Kernel.Version kernelVersion = remoteNode.Kernel.Version
} }
if kernelVersion == "" {
if kernel_ := kernel.FromNode(&remoteNode); kernel_ != nil {
kernelVersion = kernel_.Version()
}
}
tmpl_data = &templateVars{ tmpl_data = &templateVars{
Id: remoteNode.Id(), Id: remoteNode.Id(),
Cluster: remoteNode.ClusterName, Cluster: remoteNode.ClusterName,

View File

@@ -1,14 +1,13 @@
#!/bin/sh #!/bin/sh
#
# This is one of those types of files that you shouldn't edit unless you really
# know what you are doing and even then you should make a backup.
#
# Edit at your own risk! DANGER DANGER.
echo "Warewulf pre-init (/init)"
echo
echo "Mounting kernel file systems..."
mountpoint -q /proc || (mkdir -p /proc && mount -t proc proc /proc && echo "Mounted /proc") mountpoint -q /proc || (mkdir -p /proc && mount -t proc proc /proc && echo "Mounted /proc")
mountpoint -q /dev || (mkdir -p /dev && mount -t devtmpfs devtmpfs /dev && echo "Mounted /dev") mountpoint -q /dev || (mkdir -p /dev && mount -t devtmpfs devtmpfs /dev && echo "Mounted /dev")
mountpoint -q /sys || (mkdir -p /sys && mount -t sysfs sysfs /sys && echo "Mounted /sys") mountpoint -q /sys || (mkdir -p /sys && mount -t sysfs sysfs /sys && echo "Mounted /sys")
echo
echo "Loading /warewulf/config..."
if [ -f "/warewulf/config" ]; then if [ -f "/warewulf/config" ]; then
. /warewulf/config . /warewulf/config
else else
@@ -17,24 +16,24 @@ else
sleep 60 sleep 60
echo b > /proc/sysrq-trigger || /sbin/reboot -f echo b > /proc/sysrq-trigger || /sbin/reboot -f
fi fi
echo
echo "Warewulf v4 is now booting: ${WWHOSTNAME}"
echo echo
echo "Configuring root file system..."
chmod 755 /warewulf/wwinit WWPRESCRIPTS=/warewulf/wwprescripts
chmod +rx "${WWPRESCRIPTS}"
if [ -z "${WWROOT}" -o "${WWROOT}" = "initramfs" ]; then WWROOT="${WWROOT:-initramfs}"
echo "Retaining initramfs and invoking /warewulf/wwinit..." if [ "${WWROOT}" = "initramfs" ]; then
exec /warewulf/wwinit echo "WWROOT=${WWROOT}: using initial rootfs and invoking ${WWPRESCRIPTS}..."
exec "${WWPRESCRIPTS}"
elif [ "${WWROOT}" = "ramfs" -o "${WWROOT}" = "tmpfs" ]; then elif [ "${WWROOT}" = "ramfs" -o "${WWROOT}" = "tmpfs" ]; then
echo "Setting up new ${WWROOT} rootfs..." echo "WWROOT=${WWROOT}: setting up new ${WWROOT} rootfs (/newroot)..."
mkdir /newroot mkdir /newroot
mount wwroot /newroot -t ${WWROOT} -o mpol=interleave # mpol ignored for ramfs mount wwroot /newroot -t ${WWROOT} -o mpol=interleave # mpol ignored for ramfs
tar -cf - --exclude ./proc --exclude ./sys --exclude ./dev --exclude --exclude ./newroot . | tar -xf - -C /newroot tar -cf - --exclude ./proc --exclude ./sys --exclude ./dev --exclude --exclude ./newroot . | tar -xf - -C /newroot
mkdir /newroot/proc /newroot/dev /newroot/sys 2>/dev/null mkdir /newroot/proc /newroot/dev /newroot/sys 2>/dev/null
echo "Switching to new rootfs and invoking /warewulf/wwinit..." echo "Switching to new rootfs (/newroot) and invoking ${WWPRESCRIPTS}..."
exec /sbin/switch_root /newroot /warewulf/wwinit exec /sbin/switch_root /newroot "${WWPRESCRIPTS}"
else else
echo "ERROR: Unrecognized rootfs type requested: ${WWROOT}" echo "ERROR: Unrecognized rootfs type requested: ${WWROOT}"
echo "Rebooting in 1 minute..." echo "Rebooting in 1 minute..."
@@ -43,7 +42,7 @@ else
fi fi
echo echo
echo "ERROR: There was a problem with the initial provisioning process." echo "ERROR: wwinit encountered a problem."
echo "Rebooting in 1 minute..." echo "Rebooting in 1 minute..."
sleep 60 sleep 60
echo b > /proc/sysrq-trigger || /sbin/reboot -f echo b > /proc/sysrq-trigger || /sbin/reboot -f

View File

@@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
. /warewulf/config echo "Warewulf prescript: localhost"
echo
echo "Bringing up lo:127.0.0.1" echo "Bringing up lo..."
/sbin/ip link set dev lo up /sbin/ip link set dev lo up

View File

@@ -4,17 +4,22 @@
export PATH=/usr/bin:/bin:/usr/sbin:/sbin export PATH=/usr/bin:/bin:/usr/sbin:/sbin
echo "Warewulf prescript: IPMI"
echo
if [ "$WWIPMI_WRITE" != "true" ]; then if [ "$WWIPMI_WRITE" != "true" ]; then
echo "IPMI write not configured: skipping" echo "IPMI write not configured: skipping"
exit exit
fi fi
echo "Loading IPMI kernel modules..."
modprobe ipmi_si ipmi_ssif ipmi_devintf ipmi_msghandler || ( modprobe ipmi_si ipmi_ssif ipmi_devintf ipmi_msghandler || (
echo "unable to load IPMI kernel modules: skipping IPMI configuration" echo "Unable to load IPMI kernel modules: skipping IPMI configuration"
exit exit
) )
if [ ! -e /dev/ipmi0 ]; then if [ ! -e /dev/ipmi0 ]; then
echo "/dev/ipmi0 does not exist; creating..."
sleep 1 sleep 1
ipmi_dev=$(grep ipmidev /proc/devices | awk '{ print $1 }') ipmi_dev=$(grep ipmidev /proc/devices | awk '{ print $1 }')
mknod -m 0666 /dev/ipmi0 c "$ipmi_dev" 0 mknod -m 0666 /dev/ipmi0 c "$ipmi_dev" 0
@@ -83,7 +88,7 @@ if [ -n "$WWIPMI_PASSWORD" ]; then
fi fi
fi fi
# Serial Over LAN echo "Configuring Serial over LAN..."
ipmitool channel setaccess 1 2 link=on ipmi=on callin=on privilege=4 ipmitool channel setaccess 1 2 link=on ipmi=on callin=on privilege=4
ipmitool sol set force-encryption true 1 ipmitool sol set force-encryption true 1
ipmitool sol set force-authentication true 1 ipmitool sol set force-authentication true 1

View File

@@ -2,23 +2,19 @@
. /warewulf/config . /warewulf/config
# This will eventually be optional echo "Warewulf prescript: VNFS fixes"
if true; then echo
if [ -f "/etc/pam.d/system-auth" ]; then
echo "FIXING: system-auth" add_broken_shadow() {
sed -i -e '/^account.*pam_unix\.so\s*$/s/\s*$/\ broken_shadow/' /etc/pam.d/system-auth if [ -f "${1}" ]; then
echo "Adding broken_shadow to ${1}..."
sed -i -e '/^account.*pam_unix\.so\s*$/s/\s*$/\ broken_shadow/' "${1}"
fi fi
}
if [ -f "/etc/pam.d/password-auth" ]; then add_broken_shadow /etc/pam.d/system-auth
echo "FIXING: password-auth" add_broken_shadow /etc/pam.d/password-auth
sed -i -e '/^account.*pam_unix\.so\s*$/s/\s*$/\ broken_shadow/' /etc/pam.d/password-auth add_broken_shadow /etc/pam.d/common-account
fi
if [ -f "/etc/pam.d/common-account" ]; then
echo "FIXING: common-account"
sed -i -e '/^account.*pam_unix\.so\s*$/s/\s*$/\ broken_shadow/' /etc/pam.d/common-account
fi
fi
echo "Adjusting root directory permissions..."
chmod 755 / chmod 755 /

View File

@@ -2,32 +2,42 @@
. /warewulf/config . /warewulf/config
echo "Warewulf prescript: SELinux"
if test -f "/etc/sysconfig/selinux"; then if test -f "/etc/sysconfig/selinux"; then
. /etc/sysconfig/selinux . /etc/sysconfig/selinux
else else
echo "Skipping SELinux configuration: Host config not found: /etc/sysconfig/selinux" echo "File not found: /etc/sysconfig/selinux"
echo "Skipping SELinux configuration."
exit exit
fi fi
if test "$SELINUX" == "disabled"; then if [ "$SELINUX" = "disabled" ]; then
echo "Skipping SELinux setup per /etc/sysconfig/selinux" echo "/etc/sysconfig/selinux:SELINUX=${SELINUX}: skipping SELinux configuration."
exit exit
fi fi
if grep -q "selinux=0" /proc/cmdline; then if grep -q "selinux=0" /proc/cmdline; then
echo "Skipping SELinux setup per kernel command line" echo "/proc/cmdline:selinux=0: skipping SELinux configuration."
exit exit
fi fi
if [ $(findmnt / --noheadings --output SOURCE) == 'rootfs' ]; then if [ $(findmnt / --noheadings --output SOURCE) = 'rootfs' ]; then
echo "Skipping SELinux configuration: rootfs does not support SELinux contexts" echo "/ is a 'rootfs' file system, which does not support SELinux contexts."
echo "Skipping SELinux configuration."
echo echo
echo "WARNING: SELinux prep is being skipped, but SELinux is enabled on host! This may" echo "WARNING: SELinux configuration is being skipped, but SELinux is"
echo "WARNING: cause the system to not work properly. Try setting 'Root=tmpfs'" echo "WARNING: enabled in the image! The node will probably not boot"
sleep 5 echo "WARNING: properly."
echo "WARNING:"
echo "WARNING: Try setting 'Root=tmpfs'"
echo
echo "Continuing in 60s..."
sleep 60
exit exit
fi fi
echo "Setting up SELinux" echo "Loading SELinux policy..."
/sbin/load_policy -i /sbin/load_policy -i
echo "Restoring filesystem labels..."
/sbin/restorecon -e /sys -r / /sbin/restorecon -e /sys -r /

View File

@@ -1,17 +0,0 @@
#!/bin/sh
echo "Hello from WWINIT"
. /warewulf/config
myPATH=/warewulf/init.d
ls -1 $myPATH/ | while read -r NAME; do
echo "Launching: $NAME"
sh "$myPATH/$NAME"
done
echo "Calling $WWINIT..."
echo
sleep 2
exec $WWINIT

View File

@@ -0,0 +1,14 @@
#!/usr/bin/sh
. /warewulf/config
echo "Warewulf prescript runner (/warewulf/wwprescripts)"
scriptdir=/warewulf/init.d
echo "Looking for prescripts in /warewulf/init.d/..."
ls -1 "${scriptdir}/" | while read -r name; do
echo "Running prescript: ${name}..."
sh "${scriptdir}/${name}"
done
echo
echo "Running ${WWINIT}..."
exec $WWINIT

View File

@@ -332,24 +332,22 @@ initramfs inside the image.
necessary to remove ``/etc/machine-id`` for dracut to properly generate necessary to remove ``/etc/machine-id`` for dracut to properly generate
the initramfs in the location that Warewulf is expecting. the initramfs in the location that Warewulf is expecting.
Set the node's iPXE template to ``dracut`` to direct iPXE to fetch the To direct iPXE to fetch the node's initramfs image and boot with dracut
node's initramfs image and boot with dracut semantics, rather than semantics, set an ``IPXEMenuEntry`` tag for the node.
booting the node image directly.
.. note:: .. note::
Warewulf iPXE templates are located at ``/etc/warewulf/ipxe/`` when Warewulf configures iPXE with a template located at
Warewulf is installed via official packages. You can learn more ``/etc/warewulf/ipxe/default.ipxe``. Inspect the template to learn more about
about how dracut booting works by inspecting its iPXE template at the dracut booting process.
``/etc/warewulf/ipxe/dracut.ipxe``.
.. code-block:: shell .. code-block:: shell
wwctl node set wwnode1 --ipxe dracut wwctl node set wwnode1 --tagadd IPXEMenuEntry=dracut
.. note:: .. note::
The iPXE template may be set at the node or profile level. The IPXEMenuEntry variable may be set at the node or profile level.
Alternatively, to direct GRUB to fetch the node's initramfs image and boot with Alternatively, to direct GRUB to fetch the node's initramfs image and boot with
dracut semantics, set a ``GrubMenuEntry`` tag for the node. dracut semantics, set a ``GrubMenuEntry`` tag for the node.
@@ -379,8 +377,3 @@ to use up to 50% of physical memory. This size limit may be adjustd
using the kernel argument `wwinit.tmpfs.size`. (This parameter is using the kernel argument `wwinit.tmpfs.size`. (This parameter is
passed to the `size` option during tmpfs mount. See ``tmpfs(5)`` for passed to the `size` option during tmpfs mount. See ``tmpfs(5)`` for
more details.) more details.)
.. warning::
Kernel overrides are not currently fully supported during dracut initramfs boot.

View File

@@ -23,12 +23,10 @@ iPXE
If you're using iPXE to boot (the default), you can get a command prompt by pressing with C-b during boot. If you're using iPXE to boot (the default), you can get a command prompt by pressing with C-b during boot.
From the iPXE command prompt, you can run the same commands from `default.ipxe`_ (or `dracut.ipxe`_) to troubleshoot potential boot problems. From the iPXE command prompt, you can run the same commands from `default.ipxe`_ to troubleshoot potential boot problems.
.. _default.ipxe: https://github.com/warewulf/warewulf/blob/main/etc/ipxe/default.ipxe .. _default.ipxe: https://github.com/warewulf/warewulf/blob/main/etc/ipxe/default.ipxe
.. _dracut.ipxe: https://github.com/warewulf/warewulf/blob/main/etc/ipxe/dracut.ipxe
For example, the following commands perform a (relatively) normal Warewulf boot. For example, the following commands perform a (relatively) normal Warewulf boot.
(Substitute your Warewulf server's IP address in place of 10.0.0.1, (Substitute your Warewulf server's IP address in place of 10.0.0.1,
update the port number if you have changed it from the default of 9873, update the port number if you have changed it from the default of 9873,