LibrePortal/scripts/cli/commands/backup/cli_backup_commands.sh
librelad 4ce0340ef8 refactor(backup): replace per-app cron stagger with task-queue scheduler
Application backups were driven by one crontab entry per app, each offset by
id * CFG_BACKUP_CRONTAB_APP_INTERVAL minutes. That minute offset is written
straight into cron's 0-59 minute field, so past ~20 apps it overflowed into
an invalid entry that silently never fired, and the fixed spacing could not
serialize backups that ran longer than the gap.

Replace it with a single daily entry (`libreportal backup scheduled`) that
enqueues a backup task per enabled app. The existing systemd task processor
drains them serially — no minute overflow, real serialization, and backups
are now visible/cancellable in the Tasks UI. Per-app enable is read from
CFG_<APP>_BACKUP at schedule time instead of being mirrored into crontab.

Removes the stagger machinery (timing/setup/check/remove scripts), the
now-unused cron_jobs table + insert, and the CFG_BACKUP_CRONTAB_APP_INTERVAL
config knob and its WebUI field.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-22 14:34:35 +01:00

100 lines
3.7 KiB
Bash
Executable File

#!/bin/bash
cliHandleBackupCommands()
{
local backup_type="$initial_command2"
local action="$initial_command3"
local name="$initial_command4"
local extra="$initial_command5"
local extra2="$initial_command6"
if [[ -z "$backup_type" ]]; then
cliShowBackupHelp
return
fi
case "$backup_type" in
app)
case "$action" in
""|help) cliShowBackupHelp ;;
create)
[[ -z "$name" ]] && { isNotice "No app name provided."; cliShowBackupHelp; return; }
backupAppStart "$name"
;;
schedule)
[[ -z "$name" ]] && { isNotice "No app name provided."; cliShowBackupHelp; return; }
backupAppSchedule "$name"
;;
delete)
[[ -z "$name" ]] && { isNotice "No app name provided."; cliShowBackupHelp; return; }
[[ -z "$extra" ]] && { isNotice "No <location_idx>:<snapshot_id> provided (e.g. 1:abc123)."; cliShowBackupHelp; return; }
local idx="${extra%%:*}"
local snap="${extra##*:}"
backupAppDeleteSnapshot "$idx" "$snap"
;;
delete_all)
[[ -z "$name" ]] && { isNotice "No app name provided."; cliShowBackupHelp; return; }
backupAppDeleteAll "$name"
;;
list)
[[ -z "$name" ]] && { isNotice "No app name provided."; cliShowBackupHelp; return; }
local idx
while IFS= read -r idx; do
[[ -z "$idx" ]] && continue
echo "--- $(resticLocationName "$idx") (loc $idx) ---"
engineSnapshotsJson "$idx" "$name"
done < <(resticEnabledLocations)
;;
*)
isNotice "Invalid app backup action: $action"
cliShowBackupHelp
;;
esac
;;
all)
backupAllApps
;;
scheduled)
backupScheduleEnabledApps
;;
location)
case "$action" in
add)
[[ -z "$name" ]] && { isNotice "Usage: backup location add <name> [type]"; cliShowBackupHelp; return; }
locationAdd "$name" "$extra"
;;
remove)
[[ -z "$name" ]] && { isNotice "Usage: backup location remove <idx>"; cliShowBackupHelp; return; }
locationRemove "$name" "$extra"
;;
list)
local idx
while IFS= read -r idx; do
[[ -z "$idx" ]] && continue
local enabled="no"; resticLocationEnabled "$idx" && enabled="yes"
echo "[$idx] $(resticLocationName "$idx") — type=$(resticLocationType "$idx"), enabled=$enabled"
done < <(resticAllLocationIndices)
;;
init)
engineInitAllLocations
;;
check)
engineCheckAllLocations "${name:-5}"
;;
stats)
[[ -z "$name" ]] && name="1"
engineLocationStats "$name"
;;
*) isNotice "Invalid location action: $action"; cliShowBackupHelp ;;
esac
;;
verify)
engineCheckAllLocations "${action:-5}"
;;
*)
isNotice "Invalid backup type: $backup_type"
cliShowBackupHelp
;;
esac
}