deploy: install missing packages, NetworkManager WAN section, --wan-plan
Pure-bash SHA-1 derived CELLULAR_UUID (no uuidgen); skip keyfile if empty. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KqhjP7nud5gdBg25zCiRk9
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
# ./deploy.sh --classify-unit <ActiveState> <Result> <ExecMainStatus> # prints ok|finished|wait|warn (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 --wan-plan [conf] # what the NetworkManager WAN provisioning would do (read-only, no root)
|
||||
# ./deploy.sh render <file> # preview a templated file on stdout
|
||||
# ./deploy.sh --redact # filter stdin, masking secret values (used by --diff; for tests)
|
||||
# Idempotent. Netplan (wlan0 + Starlink NIC = NM-managed WANs; eth0 is a LAN
|
||||
@@ -67,7 +68,10 @@ load_conf() { # load_conf <file> — source and validate a host config
|
||||
|| die "$f: ENABLE_NVME_WATCH=1 needs NVME_DEVICE and NVME_FS_DEVICE"
|
||||
fi
|
||||
ONBOARD_LAN_UNMANAGED=${ONBOARD_LAN_IFACE:+;interface-name:$ONBOARD_LAN_IFACE}
|
||||
CELLULAR_UUID=$(uuidgen -s -n @dns -N "vanlink-${CELLULAR_CONN_NAME:-}" 2>/dev/null || true)
|
||||
# Stable per connection name; pure bash + sha1sum (coreutils), no uuid-runtime dependency.
|
||||
local h
|
||||
h=$(printf 'vanlink-%s' "${CELLULAR_CONN_NAME:-}" | sha1sum | cut -c1-32)
|
||||
CELLULAR_UUID="${h:0:8}-${h:8:4}-5${h:13:3}-8${h:17:3}-${h:20:12}"
|
||||
}
|
||||
|
||||
render() { # render <file> -> stdout, with @TOKEN@ placeholders substituted
|
||||
@@ -88,6 +92,12 @@ render_wan_netplan() { # ap/50-van-wan.yaml, plus the wifis stanza when the hos
|
||||
fi
|
||||
}
|
||||
|
||||
nm_wan_state_netplan() { # missing | differs | matches (the installed WAN netplan vs the rendered one)
|
||||
if [ ! -f /etc/netplan/50-van-wan.yaml ]; then echo missing
|
||||
elif diff -q <(render_wan_netplan) /etc/netplan/50-van-wan.yaml >/dev/null 2>&1; then echo matches
|
||||
else echo differs; fi
|
||||
}
|
||||
|
||||
check_rendered() { # check_rendered <src> <rendered-file> — fail on a leftover @TOKEN@
|
||||
local left
|
||||
left=$(grep -oE "$TOKEN_RE" "$2" | sort -u | tr '\n' ' ') || true
|
||||
@@ -139,6 +149,9 @@ fi
|
||||
if [ "$ENABLE_LI3" = 1 ]; then
|
||||
ENABLE_UNITS+=(van-li3-battery)
|
||||
fi
|
||||
if [ "$ENABLE_NM_WAN" = 1 ]; then
|
||||
ENABLE_UNITS+=(NetworkManager ModemManager)
|
||||
fi
|
||||
if [ "$ENABLE_HA" = 1 ]; then
|
||||
EXTRA_CHECK_UNITS+=(homeassistant esphome)
|
||||
fi
|
||||
@@ -292,6 +305,23 @@ case "${1:-}" in
|
||||
redact_secrets
|
||||
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
|
||||
load_conf "${2:-$VANLINK_CONF}"
|
||||
echo "wan-plan: ENABLE_NM_WAN=$ENABLE_NM_WAN"
|
||||
if [ "$ENABLE_NM_WAN" = 1 ]; then
|
||||
if [ -n "${WIFI_WAN_IFACE:-}" ]; then echo " wifi WAN: $WIFI_WAN_IFACE"; else echo " wifi WAN: none (wifis stanza omitted)"; fi
|
||||
if dpkg -s network-manager >/dev/null 2>&1; then echo " packages: network-manager installed"; else echo " packages: network-manager would install"; fi
|
||||
echo " netplan: /etc/netplan/50-van-wan.yaml $(nm_wan_state_netplan)"
|
||||
if [ -f /etc/netplan/10-dhcp-all-interfaces.yaml ]; then echo " armbian: /etc/netplan/10-dhcp-all-interfaces.yaml present -> would move aside"; else echo " armbian: /etc/netplan/10-dhcp-all-interfaces.yaml absent"; fi
|
||||
if [ -z "${CELLULAR_APN:-}" ]; then
|
||||
echo " cellular profile: skipped (no CELLULAR_APN)"
|
||||
elif [ -e "/etc/NetworkManager/system-connections/${CELLULAR_CONN_NAME}.nmconnection" ]; then
|
||||
echo " cellular profile: ${CELLULAR_CONN_NAME} apn=${CELLULAR_APN} exists"
|
||||
else
|
||||
echo " cellular profile: ${CELLULAR_CONN_NAME} apn=${CELLULAR_APN} would create"
|
||||
fi
|
||||
fi
|
||||
exit 0 ;;
|
||||
--classify-unit) # ./deploy.sh --classify-unit <ActiveState> <Result> <ExecMainStatus>
|
||||
classify_unit "${2:-}" "${3:-}" "${4:-}"
|
||||
exit 0 ;;
|
||||
@@ -344,9 +374,16 @@ if [ "$ENABLE_HA" = 1 ]; then
|
||||
fi
|
||||
OPTIONAL_PACKAGES=(
|
||||
)
|
||||
missing_pkgs=()
|
||||
for pkg in "${REQUIRED_PACKAGES[@]}"; do
|
||||
dpkg -s "$pkg" >/dev/null 2>&1 || { echo "MISSING REQUIRED: $pkg (apt install $pkg)"; exit 1; }
|
||||
dpkg -s "$pkg" >/dev/null 2>&1 || missing_pkgs+=("$pkg")
|
||||
done
|
||||
if [ ${#missing_pkgs[@]} -gt 0 ]; then
|
||||
echo " installing missing required packages: ${missing_pkgs[*]}"
|
||||
apt-get update -qq || echo " -> apt-get update failed (continuing with the cached lists)"
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y "${missing_pkgs[@]}" \
|
||||
|| { echo "deploy: apt-get install failed for: ${missing_pkgs[*]}" >&2; exit 1; }
|
||||
fi
|
||||
|
||||
# Check optional packages
|
||||
for pkg in "${OPTIONAL_PACKAGES[@]}"; do
|
||||
@@ -375,15 +412,17 @@ if git -c safe.directory='*' -C "$(dirname "$conf_real")" status --porcelain --
|
||||
warn "$conf_real has uncommitted changes — commit it so the host config stays reviewable"
|
||||
fi
|
||||
|
||||
echo "== netplan drift check =="
|
||||
# Netplan is never installed by this script (applying it flaps the uplinks —
|
||||
# see note below), so it's easy to edit ap/50-van-wan.yaml and forget the
|
||||
# manual `netplan apply` step. Warn loudly rather than silently drifting.
|
||||
if [ ! -f /etc/netplan/50-van-wan.yaml ]; then
|
||||
warn "netplan: /etc/netplan/50-van-wan.yaml is missing — repo config was never deployed. Run: sudo ./deploy.sh --render-wan-netplan | sudo tee /etc/netplan/50-van-wan.yaml && sudo netplan generate && sudo netplan apply"
|
||||
elif ! diff -q <(render_wan_netplan) /etc/netplan/50-van-wan.yaml >/dev/null 2>&1; then
|
||||
warn "netplan: /etc/netplan/50-van-wan.yaml differs from ap/50-van-wan.yaml (rendered). Deploy manually: sudo ./deploy.sh --render-wan-netplan | sudo tee /etc/netplan/50-van-wan.yaml && sudo netplan generate && sudo netplan apply"
|
||||
diff -u /etc/netplan/50-van-wan.yaml <(render_wan_netplan) || true
|
||||
if [ "$ENABLE_NM_WAN" != 1 ]; then
|
||||
echo "== netplan drift check =="
|
||||
# Netplan is never installed by this script (applying it flaps the uplinks —
|
||||
# see note below), so it's easy to edit ap/50-van-wan.yaml and forget the
|
||||
# manual `netplan apply` step. Warn loudly rather than silently drifting.
|
||||
if [ ! -f /etc/netplan/50-van-wan.yaml ]; then
|
||||
warn "netplan: /etc/netplan/50-van-wan.yaml is missing — repo config was never deployed. Run: sudo ./deploy.sh --render-wan-netplan | sudo tee /etc/netplan/50-van-wan.yaml && sudo netplan generate && sudo netplan apply"
|
||||
elif ! diff -q <(render_wan_netplan) /etc/netplan/50-van-wan.yaml >/dev/null 2>&1; then
|
||||
warn "netplan: /etc/netplan/50-van-wan.yaml differs from ap/50-van-wan.yaml (rendered). Deploy manually: sudo ./deploy.sh --render-wan-netplan | sudo tee /etc/netplan/50-van-wan.yaml && sudo netplan generate && sudo netplan apply"
|
||||
diff -u /etc/netplan/50-van-wan.yaml <(render_wan_netplan) || true
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "== access point =="
|
||||
@@ -602,6 +641,40 @@ fi
|
||||
echo "== hardware watchdog =="
|
||||
install -D -m0644 power/10-vanlink-watchdog.conf /etc/systemd/system.conf.d/10-vanlink-watchdog.conf
|
||||
|
||||
if [ "$ENABLE_NM_WAN" = 1 ]; then
|
||||
echo "== networkmanager WANs =="
|
||||
if ! dpkg -s network-manager >/dev/null 2>&1; then
|
||||
# Installed only now: the package starts NM, which manages Wi-Fi/gsm devices by
|
||||
# default, so van-ap-unmanaged.conf (AP radios, LAN ports) must already be in place.
|
||||
apt-get update -qq || true
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y network-manager \
|
||||
|| { echo "deploy: apt-get install network-manager failed" >&2; exit 1; }
|
||||
fi
|
||||
systemctl enable --now NetworkManager ModemManager >/dev/null 2>&1 || true
|
||||
nmcli general reload conf 2>/dev/null || true
|
||||
for nm_if in "$WIFI_5G_IFACE" "$WIFI_2G_IFACE" "$LAN_IFACE" ${ONBOARD_LAN_IFACE:-}; do
|
||||
[ -e "/sys/class/net/$nm_if" ] || continue
|
||||
nm_state=$(nmcli -t -f DEVICE,STATE device 2>/dev/null | awk -F: -v d="$nm_if" '$1 == d { print $2 }') || true
|
||||
[ "$nm_state" = unmanaged ] \
|
||||
|| warn "NetworkManager manages $nm_if (state: ${nm_state:-unknown}) — AP/LAN ports must be unmanaged (see ap/van-ap-unmanaged.conf)"
|
||||
done
|
||||
if [ -n "${CELLULAR_APN:-}" ]; then
|
||||
nm_keyfile="/etc/NetworkManager/system-connections/${CELLULAR_CONN_NAME}.nmconnection"
|
||||
if [ -e "$nm_keyfile" ]; then
|
||||
echo " cellular connection ${CELLULAR_CONN_NAME} exists — left unchanged"
|
||||
elif [ -z "${CELLULAR_UUID:-}" ]; then
|
||||
warn "CELLULAR_UUID is empty — not creating the cellular keyfile $nm_keyfile"
|
||||
else
|
||||
install_rendered ap/cellular.nmconnection "$nm_keyfile" 0600
|
||||
nmcli connection reload 2>/dev/null || true
|
||||
echo " created cellular connection ${CELLULAR_CONN_NAME} (apn ${CELLULAR_APN}) — no modem needed"
|
||||
fi
|
||||
fi
|
||||
if [ "$(nm_wan_state_netplan)" != matches ]; then
|
||||
warn "WAN netplan is not provisioned/up to date: run ./deploy.sh --apply-network (backs up /etc/netplan and rolls back automatically if the uplink does not come back)"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "== apply =="
|
||||
sysctl --system >/dev/null
|
||||
systemctl daemon-reload
|
||||
|
||||
@@ -49,5 +49,5 @@ ENABLE_HA=0 # Home Assistant + ESPHome (podman quadlets)
|
||||
ENABLE_FRIGATE=0 # Frigate NVR (podman quadlet)
|
||||
ENABLE_NM_WAN=1 # NetworkManager owns the WANs (netplan, cellular profile) via --apply-network
|
||||
|
||||
CELLULAR_CONN_NAME=Koodo # optional: NM name of the cellular connection (also used by van-failover)
|
||||
CELLULAR_APN=sp.koodo.com # optional: cellular APN
|
||||
CELLULAR_CONN_NAME=Koodo # NM name of the cellular connection (also used by van-failover); needed with ENABLE_NM_WAN=1 when a cellular WAN is wanted
|
||||
CELLULAR_APN=sp.koodo.com # cellular APN; needed with ENABLE_NM_WAN=1 when a cellular WAN is wanted (no APN = no cellular profile)
|
||||
|
||||
@@ -228,4 +228,18 @@ for h in van wan; do
|
||||
done
|
||||
done
|
||||
|
||||
# 17. --wan-plan describes what would happen (config-derived lines only; no root, no changes)
|
||||
for h in van wan; do
|
||||
if ! p=$(VANLINK_CONF=hosts/$h.conf ./deploy.sh --wan-plan 2>&1); then bad "$h: --wan-plan failed"; echo "$p" | sed 's/^/ /'; continue; fi
|
||||
echo "$p" | grep -q '^wan-plan: ENABLE_NM_WAN=1$' && ok "$h: wan-plan header" || bad "$h: wan-plan header"
|
||||
echo "$p" | grep -q 'cellular profile: Koodo apn=sp.koodo.com' && ok "$h: wan-plan cellular" || bad "$h: wan-plan cellular"
|
||||
done
|
||||
p=$(VANLINK_CONF=hosts/van.conf ./deploy.sh --wan-plan); echo "$p" | grep -q 'wifi WAN: none' && ok "van: wan-plan says no Wi-Fi WAN" || bad "van: wan-plan Wi-Fi WAN"
|
||||
p=$(VANLINK_CONF=hosts/wan.conf ./deploy.sh --wan-plan); echo "$p" | grep -q 'wifi WAN: wlan0' && ok "wan: wan-plan Wi-Fi WAN wlan0" || bad "wan: wan-plan Wi-Fi WAN"
|
||||
# CELLULAR_UUID is derived in pure bash (no uuidgen dependency) and stable
|
||||
u1=$(VANLINK_CONF=hosts/van.conf ./deploy.sh render ap/cellular.nmconnection | grep '^uuid=')
|
||||
u2=$(VANLINK_CONF=hosts/wan.conf ./deploy.sh render ap/cellular.nmconnection | grep '^uuid=')
|
||||
[ -n "$u1" ] && [ "$u1" != "uuid=" ] && [ "$u1" = "$u2" ] && ok "cellular uuid non-empty and stable across hosts" || bad "cellular uuid: '$u1' vs '$u2'"
|
||||
[ "$(grep -v '^[[:space:]]*#' deploy.sh | grep -c uuidgen)" = 0 ] && ok "deploy.sh does not call uuidgen" || bad "deploy.sh calls uuidgen"
|
||||
|
||||
exit "$fail"
|
||||
|
||||
Reference in New Issue
Block a user