API container writes trigger files to a shared volume (data/upgrade/), and a systemd path watcher on the host detects them and runs the upgrade scripts. This avoids giving the container Docker socket access. - Add upgrade-check.sh (git fetch + compare + write status.json) - Add upgrade-watcher.sh (systemd bridge, dispatches check/upgrade) - Add systemd path/service units with placeholder substitution - Modify upgrade.sh with --api-mode flag (progress.json + result.json) - Add API upgrade module (service + routes, SUPER_ADMIN only) - Add System tab to Settings page with version info, changelog, progress steps, and upgrade confirmation modal - Add upgrade watcher installation to config.sh wizard - Add data/upgrade/ shared volume to api service in docker-compose Bunker Admin
89 lines
2.9 KiB
Bash
Executable File
89 lines
2.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# =============================================================================
|
|
# Changemaker Lite V2 — Upgrade Watcher (systemd bridge)
|
|
# Called by systemd path unit when data/upgrade/trigger.json is created.
|
|
# Reads the trigger, dispatches to the appropriate script, cleans up.
|
|
# =============================================================================
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
|
UPGRADE_DIR="${PROJECT_DIR}/data/upgrade"
|
|
TRIGGER_FILE="${UPGRADE_DIR}/trigger.json"
|
|
LOG_DIR="${PROJECT_DIR}/logs"
|
|
|
|
mkdir -p "$LOG_DIR"
|
|
|
|
log() {
|
|
echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] $*" | tee -a "${LOG_DIR}/upgrade-watcher.log"
|
|
}
|
|
|
|
# Bail if no trigger file
|
|
if [[ ! -f "$TRIGGER_FILE" ]]; then
|
|
log "No trigger file found, exiting."
|
|
exit 0
|
|
fi
|
|
|
|
# Read trigger (minimal JSON parsing with grep/sed — no jq dependency)
|
|
TRIGGER_CONTENT="$(cat "$TRIGGER_FILE")"
|
|
ACTION="$(echo "$TRIGGER_CONTENT" | grep -o '"action"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"action"[[:space:]]*:[[:space:]]*"//' | sed 's/".*//')"
|
|
|
|
if [[ -z "$ACTION" ]]; then
|
|
log "ERROR: Could not parse action from trigger file"
|
|
rm -f "$TRIGGER_FILE"
|
|
exit 1
|
|
fi
|
|
|
|
log "Received trigger: action=${ACTION}"
|
|
|
|
# Remove trigger immediately to prevent re-execution
|
|
rm -f "$TRIGGER_FILE"
|
|
|
|
case "$ACTION" in
|
|
check)
|
|
log "Running update check..."
|
|
# Extract optional branch
|
|
BRANCH="$(echo "$TRIGGER_CONTENT" | grep -o '"branch"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"branch"[[:space:]]*:[[:space:]]*"//' | sed 's/".*//' || true)"
|
|
ARGS=()
|
|
if [[ -n "$BRANCH" ]]; then
|
|
ARGS+=(--branch "$BRANCH")
|
|
fi
|
|
"$SCRIPT_DIR/upgrade-check.sh" "${ARGS[@]}" 2>&1 | tee -a "${LOG_DIR}/upgrade-watcher.log"
|
|
log "Update check complete."
|
|
;;
|
|
|
|
upgrade)
|
|
log "Running upgrade..."
|
|
# Parse options from trigger
|
|
ARGS=(--api-mode)
|
|
|
|
SKIP_BACKUP="$(echo "$TRIGGER_CONTENT" | grep -o '"skipBackup"[[:space:]]*:[[:space:]]*true' || true)"
|
|
if [[ -n "$SKIP_BACKUP" ]]; then
|
|
ARGS+=(--skip-backup --force)
|
|
fi
|
|
|
|
PULL_SERVICES="$(echo "$TRIGGER_CONTENT" | grep -o '"pullServices"[[:space:]]*:[[:space:]]*true' || true)"
|
|
if [[ -n "$PULL_SERVICES" ]]; then
|
|
ARGS+=(--pull-services)
|
|
fi
|
|
|
|
DRY_RUN="$(echo "$TRIGGER_CONTENT" | grep -o '"dryRun"[[:space:]]*:[[:space:]]*true' || true)"
|
|
if [[ -n "$DRY_RUN" ]]; then
|
|
ARGS+=(--dry-run)
|
|
fi
|
|
|
|
BRANCH="$(echo "$TRIGGER_CONTENT" | grep -o '"branch"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"branch"[[:space:]]*:[[:space:]]*"//' | sed 's/".*//' || true)"
|
|
if [[ -n "$BRANCH" ]]; then
|
|
ARGS+=(--branch "$BRANCH")
|
|
fi
|
|
|
|
"$SCRIPT_DIR/upgrade.sh" "${ARGS[@]}" 2>&1 | tee -a "${LOG_DIR}/upgrade-watcher.log"
|
|
log "Upgrade complete."
|
|
;;
|
|
|
|
*)
|
|
log "ERROR: Unknown action '${ACTION}'"
|
|
exit 1
|
|
;;
|
|
esac
|