First cron run (2026-08-28 05:00) failed with 'restic: command not found'; interactive shells had /usr/local/bin, cron does not. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
55 lines
1.8 KiB
Bash
Executable File
55 lines
1.8 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
|
||
RESTIC=/usr/local/bin/restic # cron PATH lacks /usr/local/bin
|
||
|
||
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
|