backup/restore/restore-from-b2.sh

#!/usr/bin/env bash
# backup/restore/restore-from-b2.sh
# Fetch a backup date from B2 into /srv/homelab/restore/<date>/ and
# decompress the pieces into something we can actually inspect before
# clobbering the live data. This script never overwrites live state.
#
# Usage: restore-from-b2.sh YYYYMMDD [pg|sqlite|vols|all]
#
# Docs: mercemay.top/src/homelab-compose/

set -euo pipefail

HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=/dev/null
. "${HERE}/../../scripts/lib/log.sh"

DATE="${1:-}"
KIND="${2:-all}"
RCLONE_CONF="${RCLONE_CONF:-/srv/homelab/secrets/rclone.conf}"
REMOTE="${REMOTE:-b2-homelab:homelab-backups}"
DEST_ROOT="${DEST_ROOT:-/srv/homelab/restore}"

if [[ -z "${DATE}" ]]; then
    echo "usage: $0 YYYYMMDD [pg|sqlite|vols|all]" >&2
    exit 2
fi
if [[ ! "${DATE}" =~ ^[0-9]{8}$ ]]; then
    echo "bad date: ${DATE}" >&2
    exit 2
fi

DEST="${DEST_ROOT}/${DATE}"
install -d "${DEST}"

fetch() {
    local sub="$1"
    log_info "fetch ${sub}"
    rclone --config "${RCLONE_CONF}" copy --fast-list \
        "${REMOTE}/${DATE}/${sub}" "${DEST}/${sub}"
}

expand_pg() {
    log_info "expand pg dumps"
    find "${DEST}/pg" -type f -name '*.sql.zst' -print0 \
        | while IFS= read -r -d '' f; do
              local out="${f%.zst}"
              zstd -q -d -f "${f}" -o "${out}"
          done
}

expand_vols() {
    log_info "expand volume archives"
    local work="${DEST}/vols-extracted"
    install -d "${work}"
    find "${DEST}/vols" -type f -name '*.tar.zst' -print0 \
        | while IFS= read -r -d '' f; do
              local name
              name=$(basename "${f}" .tar.zst)
              install -d "${work}/${name}"
              zstd -q -d -c "${f}" | tar -xf - -C "${work}/${name}"
          done
}

case "${KIND}" in
    pg)
        fetch pg; expand_pg
        ;;
    sqlite)
        fetch sqlite
        find "${DEST}/sqlite" -name '*.zst' -exec zstd -q -d -f {} \;
        ;;
    vols)
        fetch vols; expand_vols
        ;;
    all)
        fetch pg; expand_pg
        fetch sqlite
        find "${DEST}/sqlite" -name '*.zst' -exec zstd -q -d -f {} \;
        fetch vols; expand_vols
        ;;
    *)
        echo "unknown kind: ${KIND}" >&2
        exit 2
        ;;
esac

log_info "restored artifacts under ${DEST}"
log_info "nothing has been applied to live containers yet"