deploy: --apply-network with detached apply, connectivity gate and automatic rollback
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KqhjP7nud5gdBg25zCiRk9
This commit is contained in:
@@ -11,6 +11,8 @@
|
|||||||
# ./deploy.sh --classify-radio # reads `iw dev <if> info` text on stdin, prints beaconing|silent (no ssid line = silent; used by post_check; for tests)
|
# ./deploy.sh --classify-radio # reads `iw dev <if> info` text on stdin, prints beaconing|silent (no ssid line = silent; used by post_check; for tests)
|
||||||
# ./deploy.sh --render-wan-netplan # rendered /etc/netplan/50-van-wan.yaml (ethernet part + wifis stanza when WIFI_WAN_IFACE is set)
|
# ./deploy.sh --render-wan-netplan # rendered /etc/netplan/50-van-wan.yaml (ethernet part + wifis stanza when WIFI_WAN_IFACE is set)
|
||||||
# ./deploy.sh --wan-plan [conf] # what the NetworkManager WAN provisioning would do (read-only, no root)
|
# ./deploy.sh --wan-plan [conf] # what the NetworkManager WAN provisioning would do (read-only, no root)
|
||||||
|
# ./deploy.sh --apply-network # root: install the WAN netplan, apply it from a detached unit, roll back automatically if the uplink does not return
|
||||||
|
# ./deploy.sh --print-apply-helper [conf] # print the detached apply/rollback helper script (read-only, no root; for review and tests)
|
||||||
# ./deploy.sh render <file> # preview a templated file on stdout
|
# ./deploy.sh render <file> # preview a templated file on stdout
|
||||||
# ./deploy.sh --redact # filter stdin, masking secret values (used by --diff; for tests)
|
# ./deploy.sh --redact # filter stdin, masking secret values (used by --diff; for tests)
|
||||||
# VANLINK_NM_DIR=<dir> # test override: where existing NM *.nmconnection files are looked up (default /etc/NetworkManager/system-connections)
|
# VANLINK_NM_DIR=<dir> # test override: where existing NM *.nmconnection files are looked up (default /etc/NetworkManager/system-connections)
|
||||||
@@ -275,6 +277,70 @@ post_check() { # read-only live checks; every probe is guarded, warns instead o
|
|||||||
else warn "post-deploy: default route present but 1.1.1.1 does not answer ping"; fi
|
else warn "post-deploy: default route present but 1.1.1.1 does not answer ping"; fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apply_helper_script() { # apply_helper_script <backup-dir> — the script the detached unit runs
|
||||||
|
local bak=$1
|
||||||
|
# Unquoted heredoc on purpose: $bak and $STARLINK_IFACE expand now; \$... stay for run time.
|
||||||
|
cat <<HELPER
|
||||||
|
#!/bin/bash
|
||||||
|
# Generated by deploy.sh --apply-network: apply the WAN netplan, verify the uplink, roll back if it did not come back.
|
||||||
|
exec >>/var/log/vanlink-apply-network.log 2>&1
|
||||||
|
echo "== apply-network \$(date -Is) (backup: $bak)"
|
||||||
|
netplan generate && netplan apply || echo "netplan apply failed"
|
||||||
|
ok=0
|
||||||
|
for i in \$(seq 1 60); do
|
||||||
|
have_default=0; ip route show default | grep . >/dev/null && have_default=1
|
||||||
|
nm_ok=1
|
||||||
|
if [ -e /sys/class/net/$STARLINK_IFACE ]; then
|
||||||
|
nm_ok=0
|
||||||
|
nmcli -t -f DEVICE,STATE device 2>/dev/null | grep -Fx '$STARLINK_IFACE:connected' >/dev/null && nm_ok=1
|
||||||
|
fi
|
||||||
|
if [ \$have_default = 1 ] && [ \$nm_ok = 1 ] && ping -c1 -W2 1.1.1.1 >/dev/null 2>&1; then ok=1; break; fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
if [ \$ok = 1 ]; then
|
||||||
|
echo "apply-network OK"
|
||||||
|
else
|
||||||
|
echo "apply-network FAILED — restoring $bak"
|
||||||
|
rm -f /etc/netplan/*
|
||||||
|
cp -a $bak/. /etc/netplan/
|
||||||
|
netplan generate && netplan apply
|
||||||
|
echo "apply-network ROLLED BACK"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
HELPER
|
||||||
|
}
|
||||||
|
|
||||||
|
apply_network() { # ./deploy.sh --apply-network — explicit, root; see spec §4
|
||||||
|
[ "$(id -u)" = 0 ] || die "--apply-network needs root (sudo)"
|
||||||
|
[ "$ENABLE_NM_WAN" = 1 ] || die "ENABLE_NM_WAN is 0 in $VANLINK_CONF — nothing to apply"
|
||||||
|
dpkg -s network-manager >/dev/null 2>&1 || die "network-manager is not installed — run ./deploy.sh first"
|
||||||
|
local stamp bak tmp
|
||||||
|
stamp=$(date +%Y%m%d-%H%M%S)
|
||||||
|
bak=/var/backups/vanlink-netplan-$stamp
|
||||||
|
install -d -m0700 "$bak"
|
||||||
|
cp -a /etc/netplan/. "$bak/"
|
||||||
|
tmp=$(mktemp)
|
||||||
|
render_wan_netplan > "$tmp"
|
||||||
|
check_rendered ap/50-van-wan.yaml "$tmp" || { rm -f "$tmp"; exit 1; }
|
||||||
|
install -m0600 "$tmp" /etc/netplan/50-van-wan.yaml
|
||||||
|
rm -f "$tmp"
|
||||||
|
if [ -f /etc/netplan/10-dhcp-all-interfaces.yaml ]; then
|
||||||
|
mv /etc/netplan/10-dhcp-all-interfaces.yaml /etc/netplan/10-dhcp-all-interfaces.yaml.vanlink-disabled
|
||||||
|
fi
|
||||||
|
: > /var/log/vanlink-apply-network.log
|
||||||
|
apply_helper_script "$bak" > /run/vanlink-apply-network.sh
|
||||||
|
chmod 0700 /run/vanlink-apply-network.sh
|
||||||
|
echo "backup: $bak log: /var/log/vanlink-apply-network.log"
|
||||||
|
echo "applying from a detached unit (survives an SSH drop); waiting up to 90 s ..."
|
||||||
|
systemctl reset-failed vanlink-apply-network 2>/dev/null || true
|
||||||
|
systemd-run --unit=vanlink-apply-network --collect /bin/bash /run/vanlink-apply-network.sh >/dev/null
|
||||||
|
local t=0
|
||||||
|
while systemctl is-active --quiet vanlink-apply-network && [ "$t" -lt 90 ]; do sleep 1; t=$((t + 1)); done
|
||||||
|
tail -n 6 /var/log/vanlink-apply-network.log 2>/dev/null || true
|
||||||
|
grep -q 'apply-network OK' /var/log/vanlink-apply-network.log 2>/dev/null \
|
||||||
|
|| die "apply-network did not report OK — see /var/log/vanlink-apply-network.log (previous config: $bak)"
|
||||||
|
}
|
||||||
|
|
||||||
case "${1:-}" in
|
case "${1:-}" in
|
||||||
--templates)
|
--templates)
|
||||||
template_files
|
template_files
|
||||||
@@ -320,6 +386,14 @@ case "${1:-}" in
|
|||||||
--redact) # ./deploy.sh --redact — stdin through redact_secrets (no config, no root)
|
--redact) # ./deploy.sh --redact — stdin through redact_secrets (no config, no root)
|
||||||
redact_secrets
|
redact_secrets
|
||||||
exit 0 ;;
|
exit 0 ;;
|
||||||
|
--apply-network) # ./deploy.sh --apply-network — root; applies the WAN netplan with automatic rollback
|
||||||
|
load_conf "$VANLINK_CONF"
|
||||||
|
apply_network
|
||||||
|
exit 0 ;;
|
||||||
|
--print-apply-helper) # for review/tests: the helper script, with a placeholder backup dir; no root, no changes
|
||||||
|
load_conf "${2:-$VANLINK_CONF}"
|
||||||
|
apply_helper_script /var/backups/vanlink-netplan-EXAMPLE
|
||||||
|
exit 0 ;;
|
||||||
--render-wan-netplan) load_conf "$VANLINK_CONF"; render_wan_netplan; exit 0 ;;
|
--render-wan-netplan) load_conf "$VANLINK_CONF"; render_wan_netplan; exit 0 ;;
|
||||||
--wan-plan) # ./deploy.sh --wan-plan [conf] — what the NM WAN provisioning would do; changes nothing
|
--wan-plan) # ./deploy.sh --wan-plan [conf] — what the NM WAN provisioning would do; changes nothing
|
||||||
load_conf "${2:-$VANLINK_CONF}"
|
load_conf "${2:-$VANLINK_CONF}"
|
||||||
|
|||||||
@@ -257,4 +257,16 @@ rm -rf "$nmd" "$nme"
|
|||||||
# 17c. NM must not auto-create "Wired connection" profiles
|
# 17c. NM must not auto-create "Wired connection" profiles
|
||||||
[ "$(grep -v '^[[:space:]]*#' ap/nm-no-auto-default.conf 2>/dev/null | grep -v '^[[:space:]]*$')" = "$(printf '[main]\nno-auto-default=*')" ] && ok "nm-no-auto-default.conf is [main] + no-auto-default=*" || bad "ap/nm-no-auto-default.conf missing or wrong"
|
[ "$(grep -v '^[[:space:]]*#' ap/nm-no-auto-default.conf 2>/dev/null | grep -v '^[[:space:]]*$')" = "$(printf '[main]\nno-auto-default=*')" ] && ok "nm-no-auto-default.conf is [main] + no-auto-default=*" || bad "ap/nm-no-auto-default.conf missing or wrong"
|
||||||
|
|
||||||
|
# 18. the detached apply helper: syntax, ordering, rollback branch
|
||||||
|
h=$(VANLINK_CONF=hosts/van.conf ./deploy.sh --print-apply-helper 2>&1) || { bad "--print-apply-helper failed"; echo "$h" | sed 's/^/ /'; h=; }
|
||||||
|
if [ -n "$h" ]; then
|
||||||
|
echo "$h" | bash -n && ok "apply helper: bash -n" || bad "apply helper: bash -n"
|
||||||
|
echo "$h" | grep -q 'netplan generate' && echo "$h" | grep -q 'netplan apply' && ok "apply helper applies netplan" || bad "apply helper lacks netplan generate/apply"
|
||||||
|
echo "$h" | grep -q 'restoring' && ok "apply helper has a rollback branch" || bad "apply helper lacks rollback"
|
||||||
|
echo "$h" | grep -q 'enP2p33s0' && ok "apply helper waits on the Starlink port" || bad "apply helper does not reference STARLINK_IFACE"
|
||||||
|
# rollback must come after the wait loop, and the backup is restored wholesale
|
||||||
|
a=$(echo "$h" | grep -n 'netplan apply' | head -1 | cut -d: -f1); r=$(echo "$h" | grep -n 'restoring' | head -1 | cut -d: -f1)
|
||||||
|
[ "$a" -lt "$r" ] && ok "apply helper: apply precedes rollback" || bad "apply helper: rollback ordering"
|
||||||
|
fi
|
||||||
|
|
||||||
exit "$fail"
|
exit "$fail"
|
||||||
|
|||||||
Reference in New Issue
Block a user