deploy: feature flags, --diff, tolerate failed restarts
Li3, NVMe watchdog, Home Assistant/ESPHome, Frigate and Cockpit are installed, enabled and restarted only when their ENABLE_* flag is 1. --diff shows what would change in /etc. A unit that fails to restart is recorded as a warning instead of aborting the deploy. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -105,6 +105,17 @@ case "${1:-}" in
|
|||||||
rm -f "$tmp"
|
rm -f "$tmp"
|
||||||
[ "$rc" -eq 0 ] && echo "check OK: $(template_files | wc -l) templates render cleanly"
|
[ "$rc" -eq 0 ] && echo "check OK: $(template_files | wc -l) templates render cleanly"
|
||||||
exit "$rc" ;;
|
exit "$rc" ;;
|
||||||
|
--diff) # ./deploy.sh --diff [conf] — what would change in /etc, without installing
|
||||||
|
load_conf "${2:-$VANLINK_CONF}"
|
||||||
|
grep -E '^[[:space:]]*install_rendered +[^" ]+ +/' deploy.sh | while read -r _ src dst _; do
|
||||||
|
if [ ! -e "$dst" ]; then
|
||||||
|
echo "NEW $dst"
|
||||||
|
elif ! diff -q <(render "$src") "$dst" >/dev/null; then
|
||||||
|
echo "CHANGED $dst"
|
||||||
|
diff -u "$dst" <(render "$src") | sed 's/^/ /' || true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
exit 0 ;;
|
||||||
render)
|
render)
|
||||||
[ -n "${2:-}" ] || { echo "Usage: $0 render <file>"; exit 1; }
|
[ -n "${2:-}" ] || { echo "Usage: $0 render <file>"; exit 1; }
|
||||||
load_conf "$VANLINK_CONF"
|
load_conf "$VANLINK_CONF"
|
||||||
@@ -135,8 +146,10 @@ REQUIRED_PACKAGES=(
|
|||||||
python3-paho-mqtt
|
python3-paho-mqtt
|
||||||
mobile-broadband-provider-info
|
mobile-broadband-provider-info
|
||||||
zerotier-one
|
zerotier-one
|
||||||
podman
|
|
||||||
)
|
)
|
||||||
|
if [ "$ENABLE_HA" = 1 ]; then
|
||||||
|
REQUIRED_PACKAGES+=(podman)
|
||||||
|
fi
|
||||||
OPTIONAL_PACKAGES=(
|
OPTIONAL_PACKAGES=(
|
||||||
)
|
)
|
||||||
for pkg in "${REQUIRED_PACKAGES[@]}"; do
|
for pkg in "${REQUIRED_PACKAGES[@]}"; do
|
||||||
@@ -175,6 +188,12 @@ write_warnings() {
|
|||||||
} > "$WARNINGS_FILE"
|
} > "$WARNINGS_FILE"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# A host file with uncommitted edits means this deploy uses unreviewed values.
|
||||||
|
conf_real=$(readlink -f "$VANLINK_CONF")
|
||||||
|
if git -c safe.directory='*' -C "$(dirname "$conf_real")" status --porcelain -- "$conf_real" 2>/dev/null | grep -q .; then
|
||||||
|
warn "$conf_real has uncommitted changes — commit it so the host config stays reviewable"
|
||||||
|
fi
|
||||||
|
|
||||||
echo "== netplan drift check =="
|
echo "== netplan drift check =="
|
||||||
# Netplan is never installed by this script (applying it flaps the uplinks —
|
# 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
|
# see note below), so it's easy to edit ap/50-van-wan.yaml and forget the
|
||||||
@@ -321,7 +340,6 @@ python3 -c 'import paho.mqtt' 2>/dev/null \
|
|||||||
install -D -m0644 router-status/mosquitto-listener.conf /etc/mosquitto/conf.d/van-listener.conf
|
install -D -m0644 router-status/mosquitto-listener.conf /etc/mosquitto/conf.d/van-listener.conf
|
||||||
# Restart limit drop-ins: prevent infinite restart loops that trigger hardware watchdog
|
# Restart limit drop-ins: prevent infinite restart loops that trigger hardware watchdog
|
||||||
install -D -m0644 router-status/van-gps-owntracks-restart-limit.conf /etc/systemd/system/van-gps-owntracks.service.d/restart-limit.conf
|
install -D -m0644 router-status/van-gps-owntracks-restart-limit.conf /etc/systemd/system/van-gps-owntracks.service.d/restart-limit.conf
|
||||||
install -D -m0644 li3/van-li3-battery-restart-limit.conf /etc/systemd/system/van-li3-battery.service.d/restart-limit.conf
|
|
||||||
|
|
||||||
echo "== gps (cellular modem GNSS -> gpsd) =="
|
echo "== gps (cellular modem GNSS -> gpsd) =="
|
||||||
if dpkg -s gpsd >/dev/null 2>&1; then
|
if dpkg -s gpsd >/dev/null 2>&1; then
|
||||||
@@ -344,20 +362,23 @@ python3 -c 'import gps' 2>/dev/null \
|
|||||||
python3 -c 'import paho.mqtt' 2>/dev/null \
|
python3 -c 'import paho.mqtt' 2>/dev/null \
|
||||||
|| warn "python3-paho-mqtt missing (apt install python3-paho-mqtt) — van-gps-owntracks won't start"
|
|| warn "python3-paho-mqtt missing (apt install python3-paho-mqtt) — van-gps-owntracks won't start"
|
||||||
|
|
||||||
echo "== li3 (RV house battery BMS -> MQTT/HA) =="
|
if [ "$ENABLE_LI3" = 1 ]; then
|
||||||
# NOT the laptop's own AC/battery monitor — that's power/van-battery (different
|
echo "== li3 (RV house battery BMS -> MQTT/HA) =="
|
||||||
# hardware, different concern). This is the Lithionics Li3 12V LiFePO4 house
|
# NOT the laptop's own AC/battery monitor — that's power/van-battery (different
|
||||||
# battery, over its BLE HM-10 UART module (no pairing) -> Home Assistant MQTT
|
# hardware, different concern). This is the Lithionics Li3 12V LiFePO4 house
|
||||||
# discovery. Broker + creds live only on the system (0600, seeded from
|
# battery, over its BLE HM-10 UART module (no pairing) -> Home Assistant MQTT
|
||||||
# li3/config.json.example — same pattern as gps/pushover).
|
# discovery. Broker + creds live only on the system (0600, seeded from
|
||||||
install -D -m0755 li3/van-li3-battery /usr/local/sbin/van-li3-battery
|
# li3/config.json.example — same pattern as gps/pushover).
|
||||||
install -D -m0644 li3/van-li3-battery.service /etc/systemd/system/van-li3-battery.service
|
install -D -m0755 li3/van-li3-battery /usr/local/sbin/van-li3-battery
|
||||||
if [ ! -f /etc/van-li3/config.json ]; then
|
install -D -m0644 li3/van-li3-battery.service /etc/systemd/system/van-li3-battery.service
|
||||||
install -D -m0600 li3/config.json.example /etc/van-li3/config.json
|
install -D -m0644 li3/van-li3-battery-restart-limit.conf /etc/systemd/system/van-li3-battery.service.d/restart-limit.conf
|
||||||
warn "seeded /etc/van-li3/config.json (EDIT IT: add MQTT username + password)"
|
if [ ! -f /etc/van-li3/config.json ]; then
|
||||||
|
install -D -m0600 li3/config.json.example /etc/van-li3/config.json
|
||||||
|
warn "seeded /etc/van-li3/config.json (EDIT IT: add MQTT username + password)"
|
||||||
|
fi
|
||||||
|
python3 -c 'import bleak' 2>/dev/null \
|
||||||
|
|| warn "python3-bleak missing (apt install python3-bleak) — van-li3-battery won't start"
|
||||||
fi
|
fi
|
||||||
python3 -c 'import bleak' 2>/dev/null \
|
|
||||||
|| warn "python3-bleak missing (apt install python3-bleak) — van-li3-battery won't start"
|
|
||||||
|
|
||||||
echo "== thermal monitor =="
|
echo "== thermal monitor =="
|
||||||
install -D -m0755 power/van-thermal /usr/local/sbin/van-thermal
|
install -D -m0755 power/van-thermal /usr/local/sbin/van-thermal
|
||||||
@@ -370,24 +391,30 @@ if [ ! -f /etc/van-battery/pushover.json ]; then
|
|||||||
warn "seeded /etc/van-battery/pushover.json (EDIT IT: add Pushover token + user)"
|
warn "seeded /etc/van-battery/pushover.json (EDIT IT: add Pushover token + user)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "== nvme watchdog =="
|
if [ "$ENABLE_NVME_WATCH" = 1 ]; then
|
||||||
install -D -m0755 power/van-nvme-watch /usr/local/sbin/van-nvme-watch
|
echo "== nvme watchdog =="
|
||||||
install_rendered power/nvme-watch-config.json /etc/van-nvme-watch/config.json
|
install -D -m0755 power/van-nvme-watch /usr/local/sbin/van-nvme-watch
|
||||||
install -D -m0644 power/van-nvme-watch.service /etc/systemd/system/van-nvme-watch.service
|
install_rendered power/nvme-watch-config.json /etc/van-nvme-watch/config.json
|
||||||
|
install -D -m0644 power/van-nvme-watch.service /etc/systemd/system/van-nvme-watch.service
|
||||||
|
fi
|
||||||
|
|
||||||
echo "== home assistant =="
|
echo "== home assistant =="
|
||||||
# Native HA (Podman Quadlet, replaced the ha_van VM). daemon-reload below
|
# Native HA (Podman Quadlet, replaced the ha_van VM). daemon-reload below
|
||||||
# regenerates homeassistant.service; started (not restarted) at the end so a
|
# regenerates homeassistant.service; started (not restarted) at the end so a
|
||||||
# deploy never bounces HA — after editing the .container, restart it manually.
|
# deploy never bounces HA — after editing the .container, restart it manually.
|
||||||
install -D -m0644 ha/homeassistant.container /etc/containers/systemd/homeassistant.container
|
if [ "$ENABLE_HA" = 1 ]; then
|
||||||
install -d -m0755 /srv/homeassistant
|
install -D -m0644 ha/homeassistant.container /etc/containers/systemd/homeassistant.container
|
||||||
# ESPHome dashboard (sibling container, same rationale as HA above — no
|
install -d -m0755 /srv/homeassistant
|
||||||
# Supervisor/add-on store here).
|
# ESPHome dashboard (sibling container, same rationale as HA above — no
|
||||||
install -D -m0644 ha/esphome.container /etc/containers/systemd/esphome.container
|
# Supervisor/add-on store here).
|
||||||
install -d -m0755 /srv/esphome
|
install -D -m0644 ha/esphome.container /etc/containers/systemd/esphome.container
|
||||||
|
install -d -m0755 /srv/esphome
|
||||||
|
fi
|
||||||
# Frigate NVR (sibling container, same rationale as HA/ESPHome above).
|
# Frigate NVR (sibling container, same rationale as HA/ESPHome above).
|
||||||
install -D -m0644 ha/frigate.container /etc/containers/systemd/frigate.container
|
if [ "$ENABLE_FRIGATE" = 1 ]; then
|
||||||
install -d -m0755 /srv/frigate/config /srv/frigate/storage
|
install -D -m0644 ha/frigate.container /etc/containers/systemd/frigate.container
|
||||||
|
install -d -m0755 /srv/frigate/config /srv/frigate/storage
|
||||||
|
fi
|
||||||
|
|
||||||
echo "== hardware watchdog =="
|
echo "== hardware watchdog =="
|
||||||
install -D -m0644 power/10-vanlink-watchdog.conf /etc/systemd/system.conf.d/10-vanlink-watchdog.conf
|
install -D -m0644 power/10-vanlink-watchdog.conf /etc/systemd/system.conf.d/10-vanlink-watchdog.conf
|
||||||
@@ -410,24 +437,41 @@ systemctl mask systemd-networkd-wait-online.service >/dev/null 2>&1 || true
|
|||||||
systemctl unmask hostapd >/dev/null 2>&1 || true
|
systemctl unmask hostapd >/dev/null 2>&1 || true
|
||||||
# Disable system dnsmasq.service to avoid port 53 conflicts — van-ap-dnsmasq owns AP DHCP
|
# Disable system dnsmasq.service to avoid port 53 conflicts — van-ap-dnsmasq owns AP DHCP
|
||||||
systemctl disable dnsmasq.service >/dev/null 2>&1 || true
|
systemctl disable dnsmasq.service >/dev/null 2>&1 || true
|
||||||
systemctl enable regdomain.service van-br0-setup.service hostapd hostapd-2g van-ap-dnsmasq nftables systemd-networkd van-failover van-thermal van-nvme-watch van-ap-watchdog van-ap-watchdog-2g van-wlan-watchdog van-modem-watch van-sms-watch van-gps-owntracks van-li3-battery van-router-mqtt >/dev/null 2>&1 || true
|
ENABLE_UNITS=(regdomain.service van-br0-setup.service hostapd hostapd-2g van-ap-dnsmasq nftables systemd-networkd van-failover van-thermal van-ap-watchdog van-ap-watchdog-2g van-wlan-watchdog van-modem-watch van-sms-watch van-gps-owntracks van-router-mqtt)
|
||||||
|
if [ "$ENABLE_NVME_WATCH" = 1 ]; then
|
||||||
|
ENABLE_UNITS+=(van-nvme-watch)
|
||||||
|
fi
|
||||||
|
if [ "$ENABLE_LI3" = 1 ]; then
|
||||||
|
ENABLE_UNITS+=(van-li3-battery)
|
||||||
|
fi
|
||||||
|
systemctl enable "${ENABLE_UNITS[@]}" >/dev/null 2>&1 || true
|
||||||
# bluetooth: host BlueZ serves the onboard hci0 to the HA container over D-Bus
|
# bluetooth: host BlueZ serves the onboard hci0 to the HA container over D-Bus
|
||||||
systemctl enable --now bluetooth >/dev/null 2>&1 || true
|
systemctl enable --now bluetooth >/dev/null 2>&1 || true
|
||||||
systemctl start homeassistant || warn "homeassistant failed to start (podman/quadlet — check journalctl -u homeassistant)"
|
if [ "$ENABLE_HA" = 1 ]; then
|
||||||
systemctl start esphome || warn "esphome failed to start (podman/quadlet — check journalctl -u esphome)"
|
systemctl start homeassistant || warn "homeassistant failed to start (podman/quadlet — check journalctl -u homeassistant)"
|
||||||
systemctl start frigate || warn "frigate failed to start (podman/quadlet — check journalctl -u frigate)"
|
systemctl start esphome || warn "esphome failed to start (podman/quadlet — check journalctl -u esphome)"
|
||||||
|
fi
|
||||||
|
if [ "$ENABLE_FRIGATE" = 1 ]; then
|
||||||
|
systemctl start frigate || warn "frigate failed to start (podman/quadlet — check journalctl -u frigate)"
|
||||||
|
fi
|
||||||
systemctl restart van-thermal
|
systemctl restart van-thermal
|
||||||
systemctl restart van-nvme-watch
|
if [ "$ENABLE_NVME_WATCH" = 1 ]; then
|
||||||
|
systemctl restart van-nvme-watch
|
||||||
|
fi
|
||||||
systemctl restart van-sms-watch
|
systemctl restart van-sms-watch
|
||||||
systemctl restart van-gps-owntracks
|
systemctl restart van-gps-owntracks
|
||||||
systemctl restart van-li3-battery
|
if [ "$ENABLE_LI3" = 1 ]; then
|
||||||
|
systemctl restart van-li3-battery
|
||||||
|
fi
|
||||||
systemctl restart van-router-mqtt
|
systemctl restart van-router-mqtt
|
||||||
# Pick up unmanaged-devices changes so NM releases/keeps the right interfaces.
|
# Pick up unmanaged-devices changes so NM releases/keeps the right interfaces.
|
||||||
nmcli general reload 2>/dev/null || systemctl reload NetworkManager 2>/dev/null || true
|
nmcli general reload 2>/dev/null || systemctl reload NetworkManager 2>/dev/null || true
|
||||||
# restart in dependency order: bridge + members first, then hostapd enslaves the
|
# restart in dependency order: bridge + members first, then hostapd enslaves the
|
||||||
# radios, then dnsmasq binds br0, then NAT/failover
|
# radios, then dnsmasq binds br0, then NAT/failover
|
||||||
systemctl restart systemd-networkd
|
systemctl restart systemd-networkd
|
||||||
systemctl restart van-ap-dnsmasq nftables van-failover van-wlan-watchdog
|
for u in van-ap-dnsmasq nftables van-failover van-wlan-watchdog; do
|
||||||
|
systemctl restart "$u" || warn "$u failed to restart (journalctl -xeu $u)"
|
||||||
|
done
|
||||||
# The AP radios live on the USB hub and may be absent; the start then fails but
|
# The AP radios live on the USB hub and may be absent; the start then fails but
|
||||||
# Restart=always keeps retrying and claims them the moment they enumerate.
|
# Restart=always keeps retrying and claims them the moment they enumerate.
|
||||||
systemctl restart hostapd hostapd-2g \
|
systemctl restart hostapd hostapd-2g \
|
||||||
|
|||||||
@@ -69,4 +69,32 @@ else
|
|||||||
ok "van: unmanaged-devices has no eth0"
|
ok "van: unmanaged-devices has no eth0"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# 6. flagged units/paths only appear inside their ENABLE_* guard in deploy.sh.
|
||||||
|
# Convention: guards are column-0 `if [ "$ENABLE_X" = 1 ]; then` ... `fi`,
|
||||||
|
# contents indented (so a nested `fi` never sits in column 0).
|
||||||
|
if awk '
|
||||||
|
BEGIN {
|
||||||
|
need["van-li3-battery"]="ENABLE_LI3"
|
||||||
|
need["van-nvme-watch"]="ENABLE_NVME_WATCH"
|
||||||
|
need["nvme-watch-config"]="ENABLE_NVME_WATCH"
|
||||||
|
need["homeassistant"]="ENABLE_HA"
|
||||||
|
need["esphome"]="ENABLE_HA"
|
||||||
|
need["frigate"]="ENABLE_FRIGATE"
|
||||||
|
need["cockpit"]="ENABLE_COCKPIT"
|
||||||
|
}
|
||||||
|
/^if \[ "\$ENABLE_[A-Z0-9_]+" = 1 \]/ { match($0, /ENABLE_[A-Z0-9_]+/); guard=substr($0, RSTART, RLENGTH); next }
|
||||||
|
/^fi([[:space:]]|$)/ { guard=""; next }
|
||||||
|
/^[[:space:]]*(#|echo)/ { next }
|
||||||
|
{ for (u in need) if (index($0, u) && guard != need[u]) {
|
||||||
|
printf " deploy.sh:%d mentions %s outside an %s guard: %s\n", NR, u, need[u], $0; bad=1 } }
|
||||||
|
END { exit bad }
|
||||||
|
' deploy.sh; then ok "flagged units are only touched inside their ENABLE_* guard"; else bad "flag gating"; fi
|
||||||
|
|
||||||
|
# 8. ./deploy.sh --diff runs (no root) and lists rendered files
|
||||||
|
if out=$(./deploy.sh --diff hosts/van.conf 2>&1) && echo "$out" | grep -qE '^(NEW|CHANGED) '; then
|
||||||
|
ok "deploy.sh --diff hosts/van.conf"
|
||||||
|
else
|
||||||
|
bad "deploy.sh --diff hosts/van.conf"; echo "$out" | sed 's/^/ /'
|
||||||
|
fi
|
||||||
|
|
||||||
exit "$fail"
|
exit "$fail"
|
||||||
|
|||||||
Reference in New Issue
Block a user