143 lines
3.5 KiB
Bash
Executable File
143 lines
3.5 KiB
Bash
Executable File
#!/bin/bash
|
|
# =============================================================================
|
|
# Restore tooling for the borg-backup.sh / dump_db.sh backup system.
|
|
# Modes:
|
|
# restore.sh full [--archive NAME] [--force] [--dry-run]
|
|
# restore.sh db <db_name> [--archive NAME] [--yes] [--dry-run]
|
|
# restore.sh file <path-within-target> [--archive NAME] [--dest DIR] [--dry-run]
|
|
# restore.sh --list-archives
|
|
# =============================================================================
|
|
|
|
set -euo pipefail
|
|
|
|
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH"
|
|
umask 077
|
|
|
|
# ========================= CONFIGURATION =========================
|
|
|
|
NAME="borg-2025"
|
|
REPO="/home/srv/files/backups/$NAME"
|
|
TARGET="/home/srv/files/content"
|
|
ARCHIVE_TARGET_PATH="${TARGET#/}"
|
|
|
|
DB_CONTAINER="mariadb"
|
|
DB_START_TIMEOUT=180
|
|
|
|
BORG_PASSPHRASE_FILE="${BORG_PASSPHRASE_FILE:-/root/.borg-passphrase}"
|
|
ROOT_PASSWORD_FILE="${ROOT_PASSWORD_FILE:-/root/.mariadb-root.pw}"
|
|
DUMP_SUBDIR="mariadb/dump"
|
|
|
|
LOGDIR="${RESTORE_LOGDIR:-/var/log/borg}"
|
|
mkdir -p "$LOGDIR" 2>/dev/null || LOGDIR="/tmp"
|
|
LOGFILE="$LOGDIR/restore-$(date +%Y-%m-%d-%H%M%S).log"
|
|
|
|
export BORG_REPO="$REPO"
|
|
export BORG_PASSCOMMAND="cat $BORG_PASSPHRASE_FILE"
|
|
|
|
# =================================================================
|
|
|
|
log() {
|
|
local line
|
|
line="[$(date '+%F %T')] $*"
|
|
echo "$line"
|
|
echo "$line" >> "$LOGFILE" 2>/dev/null || true
|
|
}
|
|
|
|
step() { echo; echo "=== $* ==="; }
|
|
|
|
die() { log "ERROR: $*"; exit 1; }
|
|
|
|
run_cmd() {
|
|
log "[RUN] $*"
|
|
"$@"
|
|
}
|
|
|
|
resolve_archive() {
|
|
if [[ -n "$ARCHIVE_OVERRIDE" ]]; then
|
|
RESOLVED_ARCHIVE="$ARCHIVE_OVERRIDE"
|
|
return 0
|
|
fi
|
|
RESOLVED_ARCHIVE="$(borg list --short --lock-wait 60 2>/dev/null | tail -n1)"
|
|
[[ -n "$RESOLVED_ARCHIVE" ]] || die "no archives found in repo $REPO"
|
|
}
|
|
|
|
list_archives() {
|
|
borg list --lock-wait 60
|
|
}
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
Usage:
|
|
restore.sh full [--archive NAME] [--force] [--dry-run]
|
|
restore.sh db <db_name> [--archive NAME] [--yes] [--dry-run]
|
|
restore.sh file <path-within-target> [--archive NAME] [--dest DIR] [--dry-run]
|
|
restore.sh --list-archives
|
|
restore.sh -h | --help
|
|
EOF
|
|
}
|
|
|
|
DRY_RUN=false
|
|
FORCE=false
|
|
YES=false
|
|
ARCHIVE_OVERRIDE=""
|
|
DEST=""
|
|
|
|
parse_common_flags() {
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--archive) ARCHIVE_OVERRIDE="$2"; shift 2 ;;
|
|
--force) FORCE=true; shift ;;
|
|
--yes) YES=true; shift ;;
|
|
--dry-run) DRY_RUN=true; shift ;;
|
|
--dest) DEST="$2"; shift 2 ;;
|
|
*) die "unknown flag: $1" ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
main() {
|
|
local cmd="${1:-}"
|
|
case "$cmd" in
|
|
"")
|
|
usage
|
|
exit 1
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
--list-archives)
|
|
shift
|
|
parse_common_flags "$@"
|
|
list_archives
|
|
;;
|
|
full)
|
|
shift
|
|
parse_common_flags "$@"
|
|
cmd_full
|
|
;;
|
|
db)
|
|
shift
|
|
local dbname="${1:-}"
|
|
[[ -n "$dbname" ]] || die "db: missing <db_name>"
|
|
shift
|
|
parse_common_flags "$@"
|
|
cmd_db "$dbname"
|
|
;;
|
|
file)
|
|
shift
|
|
local relpath="${1:-}"
|
|
[[ -n "$relpath" ]] || die "file: missing <path>"
|
|
shift
|
|
parse_common_flags "$@"
|
|
cmd_file "$relpath"
|
|
;;
|
|
*)
|
|
usage
|
|
die "unknown command: $cmd"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
main "$@"
|