build-golden.sh

3.5 KB · raw

1#!/usr/bin/env bash2# Bake the golden NixOS qcow2: boot the minimal ISO headless under qemu, drive a3# scripted nixos-install over the serial console, power off. Output is a golden4# disk image; Kiln (or boot-overlay.sh) boots throwaway overlays from it.5#6# Usage: build-golden.sh <nixos.iso> <nina-linux-binary> <out-golden.qcow2>7# Tunables via env: DISK_GB (20), MEM_MB (4096), SMP (2), INSTALL_TIMEOUT (2400)8set -euo pipefail910ISO="${1:?usage: build-golden.sh <iso> <nina-bin> <out.qcow2>}"11NINA="${2:?need nina linux binary}"12OUT="${3:?need output qcow2 path}"13HERE="$(cd "$(dirname "$0")" && pwd)"14DISK_GB="${DISK_GB:-20}"15MEM_MB="${MEM_MB:-4096}"16SMP="${SMP:-2}"17INSTALL_TIMEOUT="${INSTALL_TIMEOUT:-2400}"1819for f in "$ISO" "$NINA"; do [ -f "$f" ] || { echo "missing: $f" >&2; exit 1; }; done2021work="$(mktemp -d)"22trap 'rm -rf "$work"' EXIT2324# Seed media: our config + install script + nina, as an ISO the installer mounts.25seed="$work/seed"26mkdir -p "$seed"27cp "$HERE/configuration.nix" "$seed/configuration.nix"28cp "$HERE/install.sh" "$seed/install.sh"29cp "$NINA" "$seed/nina"30SEED_ISO="$work/seed.iso"31hdiutil makehybrid -quiet -iso -joliet -default-volume-name NINASEED -o "$SEED_ISO" "$seed"3233# Fresh blank disk for the install target.34qemu-img create -f qcow2 "$OUT" "${DISK_GB}G" >/dev/null3536# Direct kernel boot: the ISO's own cmdline omits console=ttyS0 (kernel + getty37# land on VGA, invisible under -nographic). Extract the kernel/initrd and the38# installer's APPEND line, then add a serial console so the install is drivable.39bsdtar -xOf "$ISO" boot/bzImage > "$work/bzImage"40bsdtar -xOf "$ISO" boot/initrd  > "$work/initrd"41APPEND_BASE="$(bsdtar -xOf "$ISO" isolinux/isolinux.cfg 2>/dev/null \42  | awk '/^[[:space:]]*APPEND/ {sub(/^[[:space:]]*APPEND[[:space:]]*/,""); print; exit}')"43[ -n "$APPEND_BASE" ] || { echo "could not read installer APPEND line" >&2; exit 1; }44APPEND="$APPEND_BASE console=ttyS0,115200"45echo "golden target: $OUT (${DISK_GB}G)  ·  seed: $SEED_ISO"46echo "kernel append: $APPEND"4748# Pass values to expect via the environment ($env(...)); `expect -c` does not49# populate $argv from trailing args.50export GI_ISO="$ISO" GI_SEED="$SEED_ISO" GI_OUT="$OUT" GI_MEM="$MEM_MB" \51       GI_SMP="$SMP" GI_TIMEOUT="$INSTALL_TIMEOUT" \52       GI_KERNEL="$work/bzImage" GI_INITRD="$work/initrd" GI_APPEND="$APPEND"5354expect -c '55  set timeout 60056  set iso       $env(GI_ISO)57  set seed_iso  $env(GI_SEED)58  set out       $env(GI_OUT)59  set mem       $env(GI_MEM)60  set smp       $env(GI_SMP)61  set install_timeout $env(GI_TIMEOUT)62  set kernel    $env(GI_KERNEL)63  set initrd    $env(GI_INITRD)64  set append    $env(GI_APPEND)6566  spawn qemu-system-x86_64 \67    -machine q35 -accel tcg -cpu max -smp $smp -m $mem \68    -kernel $kernel -initrd $initrd -append $append \69    -drive file=$out,if=virtio,format=qcow2 \70    -drive file=$iso,media=cdrom,readonly=on \71    -drive file=$seed_iso,media=cdrom,readonly=on \72    -netdev user,id=n0 -device virtio-net-pci,netdev=n0 \73    -nographic7475  expect {76    timeout { puts "\n!! installer never reached autologin"; exit 2 }77    "automatic login" {}78  }79  sleep 580  send "sudo -i\r"81  sleep 282  send "mkdir -p /mnt-seed && mount /dev/sr1 /mnt-seed && bash /mnt-seed/install.sh\r"8384  set timeout $install_timeout85  expect {86    timeout { puts "\n!! install never finished"; exit 4 }87    "NINA_INSTALL_FAIL" { puts "\n!! install.sh reported failure"; exit 5 }88    "NINA_INSTALL_DONE" {}89    "NINA_INSTALL_START" { exp_continue }90  }91  set timeout 12092  expect eof93'9495echo "=== golden image built: $OUT ==="96qemu-img info "$OUT" | sed 's/^/  /'