85 lines
3.9 KiB
Bash
85 lines
3.9 KiB
Bash
#!/bin/sh
|
|
# dnsmasq entrypoint: assemble the TFTP root, then exec dnsmasq with the compose
|
|
# args ("$@").
|
|
#
|
|
# iPXE + Secure Boot OFF cmdline problem:
|
|
# When iPXE executes the UKI it sets the EFI LoadOptions to the image's command
|
|
# line, or — if that's empty — to the image NAME. With Secure Boot OFF,
|
|
# systemd-stub uses LoadOptions AS THE KERNEL CMDLINE, replacing the UKI's
|
|
# EMBEDDED cmdline (root/roothash/rd.nvmf.discover/rd.dot1x=0/volatile). So
|
|
# booting the UKI URL directly (or clearing the args) makes the kernel come up
|
|
# with just "fleet-<ver>.efi" as its cmdline -> dracut emergency shell.
|
|
# Fix: feed iPXE the REAL cmdline via `imgargs`. That cmdline lives only inside
|
|
# the UKI on the serving host (not in the OCI image, not as a file), so we read
|
|
# it out of the UKI's .cmdline PE section and bake it into boot.ipxe.
|
|
# (Secure Boot ON ignores any loader cmdline and uses the embedded one, so this
|
|
# whole dance is a lab/SB-OFF concern; harmless when SB is on.)
|
|
#
|
|
# Extraction: objdump -h gives the .cmdline section's size + file offset; we dd
|
|
# those bytes out of the (read-only) UKI. We deliberately avoid `objcopy`:
|
|
# --dump-section rewrites the input in place (fails on the read-only /artifacts
|
|
# mount), and `-O binary --only-section` lays the section out at its huge VMA
|
|
# (multi-GB sparse file).
|
|
set -eu
|
|
|
|
mkdir -p /srv/tftp
|
|
# User-supplied iPXE binary (snponly.efi) from the read-only source mount.
|
|
cp -f /tftp-src/*.efi /srv/tftp/ 2>/dev/null || true
|
|
# autoexec.ipxe was an STP-era workaround (ifopen+retry before autoboot); it's no
|
|
# longer rendered — PortFast on the switch port is the real fix. Remove any stale
|
|
# copy left in a long-lived container's writable layer.
|
|
rm -f /srv/tftp/autoexec.ipxe
|
|
|
|
extract_cmdline() { # $1 = UKI path; echoes the cleaned cmdline (empty on failure)
|
|
uki="$1"
|
|
command -v objdump >/dev/null 2>&1 || return 0
|
|
# objdump -h columns: Idx Name Size VMA LMA File-off Algn
|
|
line=$(objdump -h "$uki" 2>/dev/null | awk '$2==".cmdline"{print $3" "$6; exit}')
|
|
[ -n "$line" ] || return 0
|
|
sz=$((0x${line% *})); off=$((0x${line#* }))
|
|
[ "$sz" -gt 0 ] || return 0
|
|
dd if="$uki" bs=1 skip="$off" count="$sz" 2>/dev/null \
|
|
| tr -d '\000' | tr '\n\t' ' ' | sed 's/ */ /g; s/^ //; s/ $//'
|
|
}
|
|
|
|
render_boot_ipxe() {
|
|
uki="fleet-${IMAGE_VERSION}.efi"
|
|
cmdline=""
|
|
[ -f "/artifacts/${uki}" ] && cmdline=$(extract_cmdline "/artifacts/${uki}")
|
|
if [ -z "$cmdline" ]; then
|
|
echo "WARN: could not extract .cmdline from /artifacts/${uki} — iPXE boot will" >&2
|
|
echo " hit a dracut shell under Secure Boot OFF (no embedded cmdline)." >&2
|
|
echo " Check the /artifacts mount + binutils, or enable Secure Boot." >&2
|
|
fi
|
|
# boot.ipxe is fetched as the DHCP bootfile (dnsmasq tag:ipxe) AFTER iPXE's
|
|
# normal autoboot DHCP has already configured the link, so it just fetches and
|
|
# boots the UKI. `imgargs` feeds the UKI's REAL cmdline (Secure Boot OFF — see
|
|
# top); without it iPXE would pass the image name as the cmdline and dracut
|
|
# would drop to an emergency shell. (every fallible step is '||'-guarded — a
|
|
# bare failure aborts the iPXE script.)
|
|
#
|
|
# REQUIRES PortFast/edge on the switch port: iPXE's autoboot opens the NIC,
|
|
# which bounces the PHY; without PortFast the switch's STP forwarding delay
|
|
# (~30s) drops the DHCP and the boot fails. (We removed the old ifopen+retry
|
|
# workaround now that PortFast is the documented requirement — serving/tftp/README.)
|
|
cat > /srv/tftp/boot.ipxe <<EOF
|
|
#!ipxe
|
|
dhcp net0 || goto err
|
|
imgfetch http://${SERVER_IP}/${uki} || goto err
|
|
imgargs ${uki} ${cmdline}
|
|
boot ${uki} || goto err
|
|
:err
|
|
echo Fleet iPXE chain failed (\${errno}) - dropping to iPXE shell
|
|
shell
|
|
EOF
|
|
echo "rendered /srv/tftp/boot.ipxe -> ${uki} (cmdline: ${cmdline:-<MISSING>})"
|
|
}
|
|
|
|
if [ -n "${SERVER_IP:-}" ] && [ -n "${IMAGE_VERSION:-}" ]; then
|
|
render_boot_ipxe
|
|
else
|
|
echo "WARN: SERVER_IP/IMAGE_VERSION unset; /srv/tftp/boot.ipxe NOT rendered" >&2
|
|
fi
|
|
|
|
exec dnsmasq "$@"
|