deploy: host config from /etc/vanlink.conf (hosts/<hostname>.conf)
deploy.conf is replaced by one versioned file per host plus an example. deploy.sh validates the config, renders every template with a generic token loop, refuses to install output with leftover @TOKENs and gains --check/--templates. LAN_USB_IFACE is renamed LAN_IFACE. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,49 +2,119 @@
|
||||
# Deploy vanlink configs/scripts (Pi 4 "wan" port) to their system locations.
|
||||
# Usage: cd ~/vanlink && sudo ./deploy.sh
|
||||
# sudo ./deploy.sh render <file> # preview a templated file on stdout
|
||||
# ./deploy.sh --check [conf] # validate conf + render all templates (no root)
|
||||
# ./deploy.sh --templates # list templated files
|
||||
# Idempotent. Netplan (wlan0 + Starlink NIC = NM-managed WANs; eth0 is a LAN
|
||||
# port on br0) is NOT deployed here — reference copy in ap/50-van-wan.yaml,
|
||||
# applied once manually (apply flaps uplinks). We do check it for drift below.
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$(readlink -f "$0")")"
|
||||
|
||||
# deploy.conf holds hardware-instance identifiers (interface names, USB vendor
|
||||
# IDs) that change when a dongle/adapter gets physically swapped. Config files
|
||||
# below carry @TOKEN@ placeholders substituted from these variables via
|
||||
# render()/install_rendered() — edit deploy.conf, not the individual configs.
|
||||
set -a
|
||||
source ./deploy.conf
|
||||
set +a
|
||||
# Host-specific values (interface names, addressing, feature flags) live in
|
||||
# /etc/vanlink.conf — a symlink to hosts/<hostname>.conf in this repo. Config
|
||||
# files below carry @TOKEN@ placeholders substituted from those variables via
|
||||
# render()/install_rendered() — edit hosts/<hostname>.conf, not the configs.
|
||||
VANLINK_CONF=${VANLINK_CONF:-/etc/vanlink.conf}
|
||||
|
||||
# Must be defined (non-empty) in the host file; deploy aborts naming any missing.
|
||||
REQUIRED_VARS=(
|
||||
WIFI_5G_IFACE WIFI_2G_IFACE LAN_IFACE STARLINK_IFACE WIFI_WAN_IFACE
|
||||
GATEWAY_IP GATEWAY_PREFIX GATEWAY_NETWORK DHCP_RANGE_START DHCP_RANGE_END
|
||||
DNS_RESOLVERS MODEM_USB_VENDOR
|
||||
ENABLE_COCKPIT ENABLE_LI3 ENABLE_NVME_WATCH ENABLE_HA ENABLE_FRIGATE
|
||||
)
|
||||
# May be empty or absent; NVME_* are required only when ENABLE_NVME_WATCH=1.
|
||||
OPTIONAL_VARS=(
|
||||
ONBOARD_LAN_IFACE NVME_DEVICE NVME_FS_DEVICE
|
||||
USB_BACKUP_ROOT_PART USB_BACKUP_MOUNT SD_BACKUP_UUID
|
||||
)
|
||||
# Computed in load_conf; usable as @TOKEN@ like the rest.
|
||||
DERIVED_VARS=(ONBOARD_LAN_UNMANAGED)
|
||||
TOKEN_VARS=("${REQUIRED_VARS[@]}" "${OPTIONAL_VARS[@]}" "${DERIVED_VARS[@]}")
|
||||
TOKEN_RE='@[A-Z][A-Z0-9_]*@'
|
||||
|
||||
die() { echo "deploy: $*" >&2; exit 1; }
|
||||
|
||||
load_conf() { # load_conf <file> — source and validate a host config
|
||||
local f=$1 v flag missing=()
|
||||
[ -e "$f" ] || die "$f not found (missing or dangling symlink). Create it for this host with:
|
||||
sudo ln -sfn \"$PWD/hosts/$(hostname -s).conf\" /etc/vanlink.conf"
|
||||
for v in "${TOKEN_VARS[@]}"; do unset "$v"; done
|
||||
# shellcheck disable=SC1090
|
||||
. "$f"
|
||||
for v in "${REQUIRED_VARS[@]}"; do
|
||||
[ -n "${!v:-}" ] || missing+=("$v")
|
||||
done
|
||||
[ ${#missing[@]} -eq 0 ] || die "$f is missing required variable(s): ${missing[*]}"
|
||||
for flag in ENABLE_COCKPIT ENABLE_LI3 ENABLE_NVME_WATCH ENABLE_HA ENABLE_FRIGATE; do
|
||||
case ${!flag} in
|
||||
0|1) ;;
|
||||
*) die "$f: $flag must be 0 or 1 (got '${!flag}')" ;;
|
||||
esac
|
||||
done
|
||||
if [ "$ENABLE_NVME_WATCH" = 1 ]; then
|
||||
{ [ -n "${NVME_DEVICE:-}" ] && [ -n "${NVME_FS_DEVICE:-}" ]; } \
|
||||
|| 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}
|
||||
}
|
||||
|
||||
render() { # render <file> -> stdout, with @TOKEN@ placeholders substituted
|
||||
sed -e "s|@WIFI_5G_IFACE@|$WIFI_5G_IFACE|g" \
|
||||
-e "s|@WIFI_2G_IFACE@|$WIFI_2G_IFACE|g" \
|
||||
-e "s|@LAN_USB_IFACE@|$LAN_USB_IFACE|g" \
|
||||
-e "s|@STARLINK_IFACE@|$STARLINK_IFACE|g" \
|
||||
-e "s|@MODEM_USB_VENDOR@|$MODEM_USB_VENDOR|g" \
|
||||
-e "s|@DNS_RESOLVERS@|$DNS_RESOLVERS|g" \
|
||||
-e "s|@GATEWAY_IP@|$GATEWAY_IP|g" \
|
||||
-e "s|@GATEWAY_PREFIX@|$GATEWAY_PREFIX|g" \
|
||||
-e "s|@GATEWAY_NETWORK@|$GATEWAY_NETWORK|g" \
|
||||
-e "s|@DHCP_RANGE_START@|$DHCP_RANGE_START|g" \
|
||||
-e "s|@DHCP_RANGE_END@|$DHCP_RANGE_END|g" \
|
||||
"$1"
|
||||
local args=() v
|
||||
for v in "${TOKEN_VARS[@]}"; do
|
||||
args+=(-e "s|@${v}@|${!v-}|g")
|
||||
done
|
||||
sed "${args[@]}" "$1"
|
||||
}
|
||||
|
||||
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
|
||||
[ -z "$left" ] && return 0
|
||||
echo "deploy: $1: unrendered token(s) after render: $left" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
install_rendered() { # install_rendered <src> <dst> [mode]
|
||||
local tmp
|
||||
tmp=$(mktemp)
|
||||
render "$1" > "$tmp"
|
||||
check_rendered "$1" "$tmp" || { rm -f "$tmp"; exit 1; }
|
||||
install -D -m"${3:-0644}" "$tmp" "$2"
|
||||
rm -f "$tmp"
|
||||
}
|
||||
|
||||
if [ "${1:-}" = "render" ]; then
|
||||
[ -n "${2:-}" ] || { echo "Usage: $0 render <file>"; exit 1; }
|
||||
render "$2"
|
||||
exit 0
|
||||
fi
|
||||
template_files() { # every repo file that carries an @TOKEN@ placeholder
|
||||
grep -rlE "$TOKEN_RE" --exclude-dir=.git --exclude-dir=__pycache__ --exclude-dir=.superpowers \
|
||||
--exclude-dir=docs --exclude-dir=tests --exclude-dir=hosts \
|
||||
--exclude='*.bak' --exclude='*.md' --exclude=deploy.sh . | sed 's|^\./||' | sort
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
--templates)
|
||||
template_files
|
||||
exit 0 ;;
|
||||
--check) # ./deploy.sh --check [conf] — validate conf, render every template, install nothing
|
||||
load_conf "${2:-$VANLINK_CONF}"
|
||||
rc=0
|
||||
tmp=$(mktemp)
|
||||
for f in $(template_files); do
|
||||
render "$f" > "$tmp"
|
||||
check_rendered "$f" "$tmp" || rc=1
|
||||
done
|
||||
rm -f "$tmp"
|
||||
[ "$rc" -eq 0 ] && echo "check OK: $(template_files | wc -l) templates render cleanly"
|
||||
exit "$rc" ;;
|
||||
render)
|
||||
[ -n "${2:-}" ] || { echo "Usage: $0 render <file>"; exit 1; }
|
||||
load_conf "$VANLINK_CONF"
|
||||
render "$2"
|
||||
exit 0 ;;
|
||||
esac
|
||||
|
||||
[ "$(id -u)" = 0 ] || { echo "Run with sudo (writes to /etc, /usr)."; exit 1; }
|
||||
load_conf "$VANLINK_CONF"
|
||||
echo "== host config: $(readlink -f "$VANLINK_CONF") =="
|
||||
|
||||
# Check for essential package dependencies
|
||||
echo "== dependency check =="
|
||||
|
||||
Reference in New Issue
Block a user