From e577c55489ff7bc52e3621c7540098adc60c8f42 Mon Sep 17 00:00:00 2001 From: Mikei386 <44135113+Mikei386@users.noreply.github.com> Date: Mon, 21 Sep 2026 15:20:40 +0200 Subject: [PATCH] Prune portable backup slot before export --- docs/RECOVERY.md | 7 +++++++ platform/backup/athena-export-backup | 16 ++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/docs/RECOVERY.md b/docs/RECOVERY.md index 71f9d92..a296d32 100644 --- a/docs/RECOVERY.md +++ b/docs/RECOVERY.md @@ -34,6 +34,13 @@ letzte Lauf am 16. September 2026 um 13:50 Uhr verzeichnet. Sie liegen unter `/data/emergency-backups`. Schutz vor Datenplattenausfall setzt eine außerhalb Athenas aufbewahrte Kopie voraus. +Die lokale Rotation hält fünf verschlüsselte Generationen. Da ein Paket rund +46 GB umfasst, gibt das Exportscript bei bereits erreichter Aufbewahrungszahl +vor dem Schreiben genau den ältesten Slot frei. Ohne diese Reihenfolge hätte +der Lauf am 21. September bei nur noch 17 GB freiem Speicher die neue Datei +nicht mehr vollständig schreiben können. Scheitert der neue Lauf danach, +bleiben weiterhin vier gültige Generationen erhalten. + Die externe Restic-Sicherung über `athena-disaster-backup.timer` ist derzeit nicht eingerichtet: Der Timer ist zwar aktiviert, aber `/etc/mike-ai/disaster-backup.env` fehlt. Bis ein externes diff --git a/platform/backup/athena-export-backup b/platform/backup/athena-export-backup index bf3ebf2..51d1521 100755 --- a/platform/backup/athena-export-backup +++ b/platform/backup/athena-export-backup @@ -37,6 +37,22 @@ target="$OUTPUT_DIR/$name" list=$(mktemp /tmp/athena-export-list.XXXXXX) trap 'rm -f "$list" "$partial"' EXIT +# The encrypted export is roughly the size of its predecessor. Keeping all +# generations until after writing the next one requires one extra archive of +# free space and can deadlock a full backup disk. Release exactly one slot +# before writing when the configured retention is already reached. If the new +# export fails, KEEP-1 valid generations remain available. +mapfile -t existing < <(find "$OUTPUT_DIR" -maxdepth 1 -type f \ + -name 'athena-portable-*.tar.zst.age' -printf '%T@ %p\n' \ + | sort -rn | cut -d' ' -f2-) +while ((${#existing[@]} >= KEEP)); do + last_index=$((${#existing[@]} - 1)) + oldest=${existing[$last_index]} + rm -f -- "$oldest" "$oldest.sha256" + unset 'existing[last_index]' + existing=("${existing[@]}") +done + add_path() { local path=${1#/} [[ ! -e /$path ]] || printf '%s\0' "$path" >>"$list"