restic-backup.sh: dump phase carried over verbatim from plakar-backup.sh, then one restic backup invocation (dump dir + restic-paths, nextcloud excludes) into restic-data; -s dumps|backup for staged seeding. restic-incus-backup.sh: per-instance incus file mount (distinct mountpoints — restic parents by host+path), expanded config yaml alongside, giants excluded. restic-maintenance.sh: weekly prune (--max-unused 10%, --max-repack-size 4G) + structure check + rotating 1/52 data check. Plus restic-paths and the nextcloud excludes list. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
54 lines
1.7 KiB
Bash
Executable File
54 lines
1.7 KiB
Bash
Executable File
#!/bin/bash
|
||
#
|
||
# Weekly restic maintenance for both repos (Sunday, offset from the
|
||
# nightly backups — prune takes an EXCLUSIVE lock). Per repo:
|
||
# - unlock: clear locks left by crashed runs
|
||
# - prune: --max-unused 10% (our dead-data rate is ~0.1–0.4 GiB/day
|
||
# vs ~1 T repos, so pruning can skip repacking for months) and
|
||
# --max-repack-size 4G (bounds any single Sunday's rewrite to
|
||
# ~10-15 min even after a mass deletion; the rest defers)
|
||
# - check: structure every week, plus a rotating 1/52 data subset —
|
||
# a full verification of every byte once a year
|
||
#
|
||
# Usage: restic-maintenance.sh [-r <repo>[,<repo>...]]
|
||
|
||
set -u
|
||
|
||
REPOS="s3:s3.sbg.io.cloud.ovh.net/restic-data,s3:s3.sbg.io.cloud.ovh.net/restic-incus"
|
||
LOCKFILE=/run/lock/restic-maintenance.lock
|
||
ENVFILE=/root/.restic-env
|
||
|
||
while getopts r: flag; do
|
||
case "${flag}" in
|
||
r) REPOS=${OPTARG};;
|
||
*) echo "Usage: $0 [-r <repo>[,<repo>...]]" >&2; exit 2;;
|
||
esac
|
||
done
|
||
|
||
[ -r "$ENVFILE" ] || { echo "env file $ENVFILE not readable" >&2; exit 2; }
|
||
. "$ENVFILE"
|
||
|
||
exec 9>"$LOCKFILE"
|
||
if ! flock -n 9; then
|
||
echo "another restic-maintenance run holds $LOCKFILE, aborting" >&2
|
||
exit 1
|
||
fi
|
||
|
||
log() { echo "[$(date '+%F %T')] $*"; }
|
||
|
||
# rotate the read-data subset weekly: full coverage once a year
|
||
WEEK=$(( ($(date +%s) / 604800) % 52 + 1 ))
|
||
|
||
rc=0
|
||
for repo in $(printf '%s' "$REPOS" | tr ',' ' '); do
|
||
log "maintenance: $repo"
|
||
restic -r "$repo" unlock || rc=1
|
||
restic -r "$repo" prune --max-unused 10% --max-repack-size 4G --pack-size 64 || rc=1
|
||
restic -r "$repo" check || rc=1
|
||
log "check --read-data-subset=$WEEK/52"
|
||
restic -r "$repo" check --read-data-subset="$WEEK/52" || rc=1
|
||
done
|
||
|
||
log "done (rc=$rc)"
|
||
exit $rc
|