Existing borg-backup.sh/dump_db.sh, old/ reference scripts, and the brainstormed design spec for restore tooling + runbook.
146 lines
3.9 KiB
Bash
146 lines
3.9 KiB
Bash
#!/bin/bash
|
|
# =============================================================================
|
|
# Borg Backup Script - MariaDB Restart Guaranteed
|
|
# =============================================================================
|
|
|
|
set -euo pipefail
|
|
|
|
# ========================= CONFIGURATION =========================
|
|
|
|
NAME="borg-2025"
|
|
REPO="/home/srv/files/backups/$NAME"
|
|
TARGET="/home/srv/files/content"
|
|
|
|
LOGDIR="/var/log/borg"
|
|
LOGFILE="${LOGDIR}/backup-$(date +%Y-%m-%d-%H%M%S).log"
|
|
|
|
# Optional but strongly recommended
|
|
HEALTHCHECK_URL="https://hc-ping.com/your-uuid-here"
|
|
|
|
RCLONE_REMOTE="scaleway"
|
|
|
|
# =================================================================
|
|
|
|
mkdir -p "$LOGDIR"
|
|
exec > >(tee -a "$LOGFILE")
|
|
exec 2>&1
|
|
|
|
echo "=== Backup started at $(date '+%Y-%m-%d %H:%M:%S') ==="
|
|
echo "Repository: $REPO"
|
|
echo "Target: $TARGET"
|
|
echo "Log: $LOGFILE"
|
|
echo "-----------------------------------------------------------"
|
|
|
|
# ----------------------- Lockfile -----------------------
|
|
LOCKFILE="/var/lock/borg-backup.lock"
|
|
MARIADB_STOPPED=false
|
|
|
|
cleanup() {
|
|
local exit_code=${1:-$?}
|
|
|
|
if [ "$MARIADB_STOPPED" = true ]; then
|
|
echo "=== Cleanup: Starting MariaDB container ==="
|
|
docker start mariadb || echo "WARNING: Failed to start mariadb container"
|
|
sleep 3
|
|
echo "MariaDB restart completed."
|
|
fi
|
|
|
|
rm -f "$LOCKFILE"
|
|
|
|
if [ "$exit_code" -eq 0 ]; then
|
|
echo "=== Backup completed SUCCESSFULLY at $(date '+%Y-%m-%d %H:%M:%S') ==="
|
|
send_healthcheck
|
|
else
|
|
echo "=== Backup FAILED at $(date '+%Y-%m-%d %H:%M:%S') (exit code $exit_code) ==="
|
|
send_healthcheck "fail"
|
|
fi
|
|
echo "Full log: $LOGFILE"
|
|
}
|
|
|
|
if [ -e "$LOCKFILE" ]; then
|
|
echo "ERROR: Another backup is already running (lockfile exists)"
|
|
echo "Remove it manually if stale: $LOCKFILE"
|
|
exit 1
|
|
fi
|
|
|
|
touch "$LOCKFILE"
|
|
trap 'cleanup $?' EXIT
|
|
|
|
# ----------------------- Borg & Functions -----------------------
|
|
export BORG_REPO="$REPO"
|
|
export BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=yes
|
|
|
|
send_healthcheck() {
|
|
local status="${1:-}"
|
|
if [[ -n "${HEALTHCHECK_URL:-}" ]] && [[ "$HEALTHCHECK_URL" != *"your-uuid-here"* ]]; then
|
|
case "$status" in
|
|
start) curl -s -m 10 --retry 3 "${HEALTHCHECK_URL}/start" >/dev/null || true ;;
|
|
fail) curl -s -m 10 --retry 3 "${HEALTHCHECK_URL}/fail" -d "Backup failed - check $LOGFILE" >/dev/null || true ;;
|
|
*) curl -s -m 10 --retry 3 "$HEALTHCHECK_URL" >/dev/null || true ;;
|
|
esac
|
|
fi
|
|
}
|
|
|
|
run_cmd() {
|
|
echo "[RUN] $*"
|
|
"$@"
|
|
}
|
|
|
|
# =================================================================
|
|
|
|
send_healthcheck "start"
|
|
|
|
# 1. MariaDB dump (while running)
|
|
echo "=== Step 1: MariaDB dump ==="
|
|
DUMP_SCRIPT="${TARGET}/mariadb/dump_db.sh"
|
|
if [[ -x "$DUMP_SCRIPT" ]]; then
|
|
run_cmd "$DUMP_SCRIPT"
|
|
else
|
|
echo "WARNING: Dump script not found or not executable: $DUMP_SCRIPT"
|
|
fi
|
|
|
|
# 2. Stop MariaDB for consistent backup
|
|
echo "=== Step 2: Stopping MariaDB container ==="
|
|
run_cmd docker stop mariadb
|
|
MARIADB_STOPPED=true
|
|
|
|
# 3. Create Borg archive
|
|
echo "=== Step 3: Creating Borg archive ==="
|
|
run_cmd borg create \
|
|
--stats \
|
|
--progress \
|
|
--list \
|
|
--filter=AME \
|
|
--compression zstd,8 \
|
|
--exclude-caches \
|
|
--exclude-if-present .nobackup \
|
|
"::${now:%Y-%m-%dT%H-%M-%S}" \
|
|
"$TARGET"
|
|
|
|
# 4. Restart MariaDB (this line is now also in the cleanup trap)
|
|
echo "=== Step 4: Starting MariaDB container ==="
|
|
run_cmd docker start mariadb
|
|
MARIADB_STOPPED=false
|
|
|
|
# 5. Offsite sync
|
|
echo "=== Step 5: Syncing to Scaleway S3 ==="
|
|
run_cmd rclone sync -v \
|
|
--fast-list \
|
|
--transfers=8 \
|
|
--checkers=16 \
|
|
"$REPO" "${RCLONE_REMOTE}:/par-backup-1/$NAME"
|
|
|
|
# 6. Prune & Compact
|
|
echo "=== Step 6: Pruning and compacting ==="
|
|
run_cmd borg prune \
|
|
--list \
|
|
--keep-daily=7 \
|
|
--keep-weekly=4 \
|
|
--keep-monthly=6 \
|
|
--keep-within=7d \
|
|
"$REPO"
|
|
|
|
run_cmd borg compact --progress "$REPO"
|
|
|
|
# The cleanup trap will run automatically and mark success
|