Files
guix-router/deploy-mt6000.sh
ssmithxandClaude Opus 5.5 dcd8a8fb53 MT6000: deploy-mt6000.sh -- guix copy, FIT to p6, rollback
As deploy-rpi.sh, with GL U-Boot's single FIT in place of extlinux.conf:
switching to a generation writes its FIT (scripts/mt6000-fit.sh, built
on the workstation) to the `kernel' partition and checks it.  Deployed
generation 2 (drops the bring-up self-reboot), rolled back to 1 and
forward again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 11:11:51 -04:00

100 lines
3.9 KiB
Bash
Executable File

#!/usr/bin/env bash
# Update the running GL-MT6000 over SSH without reflashing.
#
# ./deploy-mt6000.sh build mt6000.scm, copy, switch, reboot
# ./deploy-mt6000.sh --no-reboot ... activate only (the new kernel and
# services start on the next boot)
# ./deploy-mt6000.sh switch N make existing generation N the default
# (roll back), activate, reboot
# ./deploy-mt6000.sh list show the router's system generations
#
# As deploy-rpi.sh: the system is cross-built here and sent with `guix copy'.
# GL's U-Boot boots one FIT from the `kernel' partition (p6), with no menu,
# so switching to a generation means writing its FIT (scripts/mt6000-fit.sh,
# built here) to p6. If a new generation doesn't come up, roll back from
# ssh if it gets that far, else through U-Boot's TFTP recovery
# (docs/PITFALLS.md #51) -- an interrupted p6 write needs that too.
#
# Needs: ~/.ssh/config entry for $ROUTER, /etc/guix/signing-key.* on this
# host, and that key in the router's guix-service-type authorized-keys
# (mt6000.scm).
set -euo pipefail
cd "$(dirname "$0")"
export PATH=$HOME/.local/bin:$PATH
export GUIX_PACKAGE_PATH="$PWD/packages:$HOME/channels/nonguix"
ROUTER=${ROUTER:-mt6000}
PROFILES=/var/guix/profiles
KERNEL_PART=/dev/mmcblk0p6
# -n: never read stdin (it would swallow `while read` loop input).
router() { ssh -n -o BatchMode=yes "$ROUTER" "$@"; }
# "N /gnu/store/…-system" for each generation, ascending.
generations() {
router "cd $PROFILES && for l in system-*-link; do n=\${l#system-}; echo \"\${n%-link} \$(readlink \$l)\"; done" |
sort -n
}
current() { router "readlink -f $PROFILES/system"; }
# Write the FIT for system $1 to p6 and check it. The system's kernel and
# initrd must be in this host's store (they are: it built them).
install_fit() {
local sys=$1 tmp sum
[ -d "$sys" ] || guix build "$sys" >/dev/null
tmp=$(mktemp -d)
scripts/mt6000-fit.sh "$sys" "$tmp/boot.itb"
ssh -o BatchMode=yes "$ROUTER" "dd of=$KERNEL_PART bs=64k conv=fsync 2>/dev/null" < "$tmp/boot.itb"
sum=$(router "head -c $(stat -c %s "$tmp/boot.itb") $KERNEL_PART | sha256sum" | cut -c1-64)
if [ "$sum" != "$(sha256sum < "$tmp/boot.itb" | cut -c1-64)" ]; then
rm -rf "$tmp"
echo "FIT on $KERNEL_PART does not match: rewrite it before rebooting" >&2
exit 1
fi
rm -rf "$tmp"
echo "FIT written to $KERNEL_PART"
}
# Point the system profile at generation $1, write its FIT, activate it.
switch_to() {
local n=$1 path
path=$(router "readlink $PROFILES/system-$n-link")
install_fit "$path"
router "ln -sfn system-$n-link $PROFILES/system.new && mv -T $PROFILES/system.new $PROFILES/system"
echo "activating generation $n ($path)"
# activate.scm picks the system from GUIX_NEW_SYSTEM (set by reconfigure
# and at boot); without it, it re-activates /run/current-system.
router "GUIX_NEW_SYSTEM=$path $path/activate" ||
echo "warning: activation reported errors" >&2
}
reboot_router() {
echo "rebooting $ROUTER"
router "sync; (sleep 1; reboot) >/dev/null 2>&1 &" || true
}
case "${1:-deploy}" in
list)
cur=$(current)
generations | while read -r n path; do
echo "$n $path$( [ "$path" = "$cur" ] && echo ' (current)')"
done ;;
switch)
n=${2:?usage: deploy-mt6000.sh switch N}
switch_to "$n"
[ "${3:-}" = --no-reboot ] || reboot_router ;;
deploy|--no-reboot)
sys=$(guix system build --target=aarch64-linux-gnu mt6000.scm | tail -1)
echo "built $sys"
if [ "$sys" = "$(current)" ]; then echo "already running $sys"; exit 0; fi
guix copy --to="$ROUTER" "$sys"
last=$(generations | tail -1 | cut -d' ' -f1)
n=$((last + 1))
router "ln -sfn $sys $PROFILES/system-$n-link"
echo "registered generation $n"
switch_to "$n"
[ "${1:-deploy}" = --no-reboot ] || reboot_router ;;
*)
sed -n '2,10p' "$0"; exit 1 ;;
esac