Files
scripts/plakar-incus-backup.sh
T
Julien LutranandClaude Fable 5 528dec1121 plakar-incus-backup: self-heal a silently expelled incus plugin
plakar's pkg backend deletes an installed ptar when its cache
re-extraction fails (observed 2026-08-24: orphaned .incus-* temps,
final ptar unlinked, 'unsupported importer protocol'). Reinstall from
the kept ptar before backing up instead of failing the night.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 18:19:35 +02:00

77 lines
2.4 KiB
Bash
Executable File

#!/bin/bash
#
# Nightly plakar backup of the incus instances (leg 4): backs up the
# configured incus source (the plakar incus integration walking the
# quiesced replicas of the `backup` project) into the target kloset,
# then applies retention. Runs CHAINED after incus-copy.sh in the same
# cron entry — the snapshot is only as fresh as the last completed
# local replica refresh:
#
# 0 1 * * * incus-copy.sh -p backup -s backup >> /var/log/incus-copy.log 2>&1 ; plakar-incus-backup.sh >> /var/log/plakar-incus.log 2>&1
#
# Usage: plakar-incus-backup.sh [-k <kloset>] [-s <source>] [-r <retention-days>]
#
# The kloset passphrase comes from $PLAKAR_PASSPHRASE or, failing
# that, /root/.plakar-passphrase (mode 600).
set -u
KLOSET=@s3incus
SOURCE=ks4-incus
RETENTION=30
LOCKFILE=/run/lock/plakar-incus-backup.lock
PASSFILE=/root/.plakar-passphrase
usage() {
echo "Usage: $0 [-k <kloset>] [-s <source>] [-r <retention-days>]" >&2
exit 2
}
while getopts k:s:r: flag; do
case "${flag}" in
k) KLOSET=${OPTARG};;
s) SOURCE=${OPTARG};;
r) RETENTION=${OPTARG};;
*) usage;;
esac
done
exec 9>"$LOCKFILE"
if ! flock -n 9; then
echo "another plakar-incus-backup run holds $LOCKFILE, aborting" >&2
exit 1
fi
log() { echo "[$(date '+%F %T')] $*"; }
if [ -z "${PLAKAR_PASSPHRASE:-}" ]; then
[ -r "$PASSFILE" ] || { echo "no PLAKAR_PASSPHRASE in env and $PASSFILE not readable" >&2; exit 1; }
PLAKAR_PASSPHRASE=$(cat "$PASSFILE")
fi
export PLAKAR_PASSPHRASE
rc=0
# The plakar pkg backend has been observed to silently expel an
# installed plugin (its reload path deletes the ptar when the cache
# re-extraction fails — seen 2026-08-24). Self-heal from the kept
# ptar instead of failing the nightly run with
# "unsupported importer protocol".
if ! plakar pkg list 2>/dev/null | grep -q "^incus@"; then
PTAR=$(ls -t /root/incus-plugin/incus_v*.ptar 2>/dev/null | head -1)
echo "incus plugin missing — reinstalling ${PTAR:-<no ptar found>}" >&2
[ -n "$PTAR" ] && plakar pkg add "$PTAR" \
|| { echo "incus plugin reinstall failed" >&2; exit 1; }
fi
log "backup @$SOURCE -> $KLOSET"
plakar -quiet at "$KLOSET" backup -tag "$SOURCE" "@$SOURCE" \
|| { echo "backup @$SOURCE failed" >&2; rc=1; }
log "prune: keep the last $RETENTION days of snapshots"
plakar at "$KLOSET" prune -days "$RETENTION" -apply || rc=1
plakar at "$KLOSET" maintenance || rc=1
log "done (rc=$rc)"
exit $rc