(a) Docs: reserve tools/ scripts/ resources/ as LibrePortal folder names (apps must not bind-mount to them); document resources/ as the home for nest-able data AND for .sh payloads that execute on load (vs scripts/ for sourced functions); document the backup model (what's captured vs reproducible). (b) System-config backup so a bare-metal restore is self-sufficient — this is why the system root is its own tree. New scripts/backup/system/backup_system.sh: - backupSystemConfig snapshots <system>/configs (global settings, WebUI creds, and the BACKUP-LOCATION creds — otherwise the keys to reach your own backups live only on the box) to every enabled location. Lightweight static-dir snapshot — it does NOT go through backupAppStart (no containers to quiesce / DBs to dump). - restic adapter resticBackupSystemToLocation (tag system=config) + dispatcher engineBackupSystem; restore via resticRestoreSystemLatest / engineRestoreSystemLatest + backupRestoreSystemConfig (restores to a STAGING dir — never auto-overwrites live config). - backupAllApps runs it after the app loop. WebUI exclusion: backupAllApps skips the 'libreportal' app — its frontend + generated JSON regenerate, and its only state (the login) is in the system config now captured above. Nothing in its data dir warrants a snapshot. Verified with stubs: app loop skips libreportal + invokes the system backup; the system backup dispatches to both locations; backup/restore function names pair with the dispatcher. NOTE: restic-only (the sole live engine adapter); end-to-end repo round-trip still needs a live box before being relied on. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> Signed-off-by: librelad <librelad@digitalangels.vip>
41 lines
1.4 KiB
Bash
41 lines
1.4 KiB
Bash
#!/bin/bash
|
|
|
|
backupAllApps()
|
|
{
|
|
isHeader "Backing up all installed applications"
|
|
|
|
if [ ! -f "$docker_dir/$db_file" ]; then
|
|
isError "Database not found: $docker_dir/$db_file"
|
|
return 1
|
|
fi
|
|
|
|
local app_names=()
|
|
while IFS= read -r name; do
|
|
app_names+=("$name")
|
|
done < <(runInstallOp sqlite3 "$docker_dir/$db_file" "SELECT name FROM apps WHERE status = 1;")
|
|
|
|
local done_count=0
|
|
for name in "${app_names[@]}"; do
|
|
# The libreportal WebUI app is reproducible — frontend + generated JSON
|
|
# regenerate on deploy, and its only state (the login) lives in the system
|
|
# config, captured by backupSystemConfig below. Nothing in its data dir is
|
|
# worth a snapshot.
|
|
if [[ "$name" == "libreportal" ]]; then
|
|
isNotice "Skipping '$name' — WebUI is reproducible; its state is in the system config"
|
|
continue
|
|
fi
|
|
backupAppStart "$name"
|
|
((done_count++))
|
|
done
|
|
|
|
# System config snapshot (global settings, WebUI creds, backup-location creds)
|
|
# so a bare-metal restore is self-sufficient — this is why the system root is
|
|
# its own backup-able tree. The code/install tree is reproducible from the
|
|
# release, so it is deliberately NOT included.
|
|
if declare -f backupSystemConfig >/dev/null 2>&1; then
|
|
backupSystemConfig
|
|
fi
|
|
|
|
isSuccessful "Backup pass complete — ${done_count} app(s) + system config"
|
|
}
|