86 lines
3.8 KiB
Bash
Executable File
86 lines
3.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Main pipeline orchestrator.
|
|
#
|
|
# Execution order:
|
|
# 1. Create cold archives for the selected Docker Compose projects.
|
|
# 2. Run each enabled transfer stage listed in BACKUP_METHODS.
|
|
# 3. Prune old local archives only after every earlier stage succeeds.
|
|
#
|
|
# An EXIT trap publishes the final MQTT result even when a stage fails. The
|
|
# original exit code is preserved so cron, systemd and shell callers can detect
|
|
# failure normally.
|
|
set -Eeuo pipefail
|
|
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
|
|
. "$SCRIPT_DIR/lib/common.sh"
|
|
DRY_RUN=0; SKIP_CONTAINERS=0; SKIP_PRUNE=0; CONTAINERS_OVERRIDE=""
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--dry-run|-t) DRY_RUN=1 ;; --skip-containers) SKIP_CONTAINERS=1 ;; --skip-prune) SKIP_PRUNE=1 ;;
|
|
--containers|-f) CONTAINERS_OVERRIDE="${2:?Missing containers file}"; shift ;;
|
|
-h|--help)
|
|
echo "Usage: ${0##*/} [--dry-run] [--containers FILE] [--skip-containers] [--skip-prune]"
|
|
echo "Transfer stages run in BACKUP_METHODS order. Add stages/NN-name.sh and list name in BACKUP_METHODS."
|
|
exit 0 ;;
|
|
*) die "Unknown option: $1" 2 ;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
BACKUP_RUN_ID="$(run_id)"
|
|
BACKUP_STARTED_EPOCH="$(date +%s)"
|
|
# Every script sourced through this process appends structured log lines here.
|
|
# The MQTT reporting stage parses this temporary log to build its summary.
|
|
BACKUP_RUN_LOG="$(mktemp "${TMPDIR:-/tmp}/zorruno-docker-backup.XXXXXX.log")"
|
|
export BACKUP_RUN_ID BACKUP_STARTED_EPOCH BACKUP_RUN_LOG
|
|
|
|
finish_run() {
|
|
local exit_code=$? finished status
|
|
# Prevent recursion when this function exits with the pipeline's status.
|
|
trap - EXIT
|
|
# Reporting is best-effort and must never replace the real pipeline result.
|
|
set +e
|
|
finished="$(date +%s)"
|
|
if (( exit_code == 0 )); then
|
|
if (( DRY_RUN )); then status="dry_run_success"; else status="success"; fi
|
|
else
|
|
if (( DRY_RUN )); then status="dry_run_failed"; else status="failed"; fi
|
|
fi
|
|
if is_true "$MQTT_REPORT_ENABLED"; then
|
|
"$SCRIPT_DIR/stages/99-mqtt-report.sh" "$status" "$exit_code" \
|
|
"$BACKUP_STARTED_EPOCH" "$finished" "$BACKUP_RUN_ID" "$BACKUP_RUN_LOG" \
|
|
|| log ERROR "Unable to publish final MQTT result"
|
|
fi
|
|
rm -f -- "$BACKUP_RUN_LOG"
|
|
exit "$exit_code"
|
|
}
|
|
trap finish_run EXIT
|
|
|
|
require_command flock
|
|
mkdir -p "$(dirname "$LOCK_FILE")"
|
|
# Keep descriptor 9 open for the whole run. Closing it automatically releases
|
|
# the advisory lock, including on errors and signals that terminate the shell.
|
|
exec 9>"$LOCK_FILE"
|
|
flock -n 9 || die "Another backup run holds lock: $LOCK_FILE"
|
|
stage_args=()
|
|
(( DRY_RUN )) && stage_args+=(--dry-run)
|
|
[[ -n "$CONTAINERS_OVERRIDE" ]] && stage_args+=(--containers "$CONTAINERS_OVERRIDE")
|
|
log START "Backup pipeline for $BACKUP_HOSTNAME"
|
|
if is_true "$MQTT_REPORT_ENABLED"; then
|
|
# The retained running state lets Home Assistant show that work is active.
|
|
"$SCRIPT_DIR/stages/99-mqtt-report.sh" running 0 "$BACKUP_STARTED_EPOCH" \
|
|
"$BACKUP_STARTED_EPOCH" "$BACKUP_RUN_ID" "$BACKUP_RUN_LOG" \
|
|
|| log WARN "Unable to publish MQTT running state; backup will continue"
|
|
fi
|
|
(( SKIP_CONTAINERS )) || "$SCRIPT_DIR/stages/10-containers.sh" "${stage_args[@]}"
|
|
method_args=(); (( DRY_RUN )) && method_args+=(--dry-run)
|
|
# BACKUP_METHODS contains short names (for example: "rclone smb"). Numeric
|
|
# prefixes control directory ordering without becoming part of configuration.
|
|
for method in $BACKUP_METHODS; do
|
|
method_script=""
|
|
while IFS= read -r candidate; do method_script="$candidate"; break; done < <(find "$SCRIPT_DIR/stages" -maxdepth 1 -type f -name "*-${method}.sh" -print | sort)
|
|
[[ -n "$method_script" ]] || die "Configured backup method not found: $method"
|
|
"$method_script" "${method_args[@]}"
|
|
done
|
|
(( SKIP_PRUNE )) || "$SCRIPT_DIR/stages/90-prune.sh" "${method_args[@]}"
|
|
log DONE "Backup pipeline completed successfully"
|