BetterFrame/deploy/systemd/betterframe-firmware-rollback.sh
Mitchell R 69cd0391b5 feat(ota): phase 3 — rollouts + automated rollback
Rollouts (server side):
- /admin/firmware/rollouts page lists + creates campaigns. Pick release,
  target kiosk_ids (empty = whole channel), percentage (1-100).
- Active rollouts override channel-latest in /api/kiosk/firmware/check.
- Deterministic bucket via sha256(rollout_id:kiosk_id) % 100 — same kiosk
  consistently lands in the same bucket across re-checks.
- Pause / resume / complete state controls.

Rollback (kiosk side):
- Before swap, kiosk writes firmware-applying.json marker.
- After clean boot + first successful heartbeat, marker deleted.
- New ExecStartPre hook (/usr/local/sbin/betterframe-firmware-rollback.sh)
  runs every service start; stale marker (>120s) + .prev present →
  restore .prev. Pairs with systemd's StartLimit to catch crash loops.
2026-05-14 07:28:20 +02:00

43 lines
1.4 KiB
Bash
Executable file

#!/usr/bin/env bash
# Rollback the kiosk binary if a recent OTA update never reached a healthy
# heartbeat. Run as ExecStartPre on the betterframe-kiosk service.
#
# Logic:
# - Marker file at /var/lib/betterframe/kiosk/firmware-applying.json
# written by the kiosk just before swapping in the new binary.
# - Kiosk deletes it after a successful heartbeat post-boot.
# - If we're running and the marker still exists older than 120s, the
# previous start failed before heartbeat → restore .prev, drop the marker.
#
# Idempotent. Silent on the happy path. Logs to journal otherwise.
set -euo pipefail
BIN="/opt/betterframe/kiosk/betterframe-kiosk"
PREV="${BIN}.prev"
MARKER="/var/lib/betterframe/kiosk/firmware-applying.json"
if [ ! -f "$MARKER" ]; then
exit 0
fi
# Marker mtime in epoch seconds.
marker_mtime=$(stat -c %Y "$MARKER" 2>/dev/null || stat -f %m "$MARKER" 2>/dev/null || echo 0)
now=$(date +%s)
age=$(( now - marker_mtime ))
# Marker fresh → previous boot is still in progress, leave it.
if [ "$age" -lt 120 ]; then
exit 0
fi
# Stale marker + .prev present → rollback.
if [ -f "$PREV" ]; then
echo "[bf-firmware-rollback] stale apply marker (${age}s old) + .prev exists — rolling back" >&2
cp -f "$PREV" "$BIN"
chmod +x "$BIN"
rm -f "$MARKER"
else
echo "[bf-firmware-rollback] stale marker but no .prev — clearing marker, manual intervention needed" >&2
rm -f "$MARKER"
fi