Restore detailed backup mail reports with bounded local delivery
This commit is contained in:
1 parent
3374019ad6
commit
99da6460d2
10 files changed
+396
-13
No files matched your search
@@ -36,12 +36,14 @@ printf 'meta\tmetadata\n' > "$PLAN"
|
||||
printf '%s\n' "$RUN_ID" > "$STAGING_DIR/meta/run-id.txt"
|
||||
# The config may contain secrets or executable substitutions; never copy it into reports.
|
||||
printf 'format=2\ncompressor=%s\n' "$COMPRESSOR" > "$STAGING_DIR/meta/format.txt"
|
||||
BACKUP_PHASE='Dienste anhalten'
|
||||
quiesce
|
||||
|
||||
for i in "${!DB_LABELS[@]}"; do
|
||||
assert_services_quiescent
|
||||
label=${DB_LABELS[i]}
|
||||
out="$STAGING_DIR/db/${label#db-}.sql"
|
||||
BACKUP_PHASE="DB-Dump: ${DB_NAMES[i]}"
|
||||
echo "-- Dump: ${DB_NAMES[i]}"
|
||||
# Defaults-extra-file must be the first option. lock-all-tables also covers MyISAM;
|
||||
# this can block ALL server databases during each dump (see documentation).
|
||||
@@ -59,10 +61,11 @@ for i in "${!LABELS[@]}"; do
|
||||
check_space "$STAGING_ROOT"
|
||||
mkdir -p -- "$STAGING_DIR/$root"
|
||||
exclusions "$label"
|
||||
BACKUP_PHASE="Dateikopie: $label"
|
||||
echo "-- Copy: $label ($src)"
|
||||
# Never accept vanished-file (24) or partial-copy (23) as success.
|
||||
# Parent retains both locks; rsync itself needs neither inherited descriptor.
|
||||
rsync -aHAX --numeric-ids "${EXCLUDES[@]}" -- "$src/" "$STAGING_DIR/$root/" 8>&- 9>&-
|
||||
rsync -aHAX --stats --numeric-ids "${EXCLUDES[@]}" -- "$src/" "$STAGING_DIR/$root/" 8>&- 9>&-
|
||||
assert_services_quiescent
|
||||
printf '%s\t%s\n' "$label" "$src" >> "$PLAN"
|
||||
done
|
||||
@@ -70,6 +73,7 @@ done
|
||||
# use this frozen private staging tree, so application downtime ends here.
|
||||
assert_services_quiescent
|
||||
echo '-- Copy window complete; writer guards verified'
|
||||
BACKUP_PHASE='Dienste wiederherstellen'
|
||||
resume_services || die 'Failed to resume original service state'
|
||||
|
||||
while IFS=$'\t' read -r label _; do
|
||||
@@ -77,6 +81,7 @@ while IFS=$'\t' read -r label _; do
|
||||
elif [[ $label == db-* ]]; then root="db/${label#db-}.sql"
|
||||
else root="files/$label"; fi
|
||||
check_space "$ARCHIVE_DIR"
|
||||
BACKUP_PHASE="Archiv: $label"
|
||||
echo "-- Archive: $label"
|
||||
if [[ $COMPRESSOR == zstd ]]; then
|
||||
out="$PARTIAL_DIR/$label.tar.zst"
|
||||
@@ -89,6 +94,7 @@ while IFS=$'\t' read -r label _; do
|
||||
fi
|
||||
mv -- "$out.partial" "$out"
|
||||
done < "$PLAN"
|
||||
BACKUP_PHASE='Lokale Archivprüfung'
|
||||
helper create "$PARTIAL_DIR" "$RUN_ID" "$PLAN"
|
||||
RUN_DIR="$ARCHIVE_DIR/$RUN_ID"
|
||||
mv -- "$PARTIAL_DIR" "$RUN_DIR"
|
||||
@@ -99,10 +105,13 @@ if [[ $ENABLE_UPLOAD == true ]]; then
|
||||
remote_run="${RCLONE_REMOTE_BASE%/}/$RUN_ID"
|
||||
# Upload COMPLETE last. An interrupted upload cannot look like a valid set.
|
||||
echo '-- Remote upload started (archives and manifest; completion marker withheld)'
|
||||
BACKUP_PHASE='Remote-Upload'; UPLOAD_STATUS=COPY
|
||||
rc copy "$RUN_DIR" "$remote_run" --exclude /COMPLETE --exclude /UPLOADED --immutable
|
||||
echo '-- Remote upload finished; reading all uploaded files back for verification'
|
||||
BACKUP_PHASE='Remote-Rückleseprüfung'; UPLOAD_STATUS=CHECK
|
||||
rc check "$RUN_DIR" "$remote_run" --download --exclude /COMPLETE --exclude /UPLOADED
|
||||
echo '-- Remote readback passed; publishing completion marker'
|
||||
BACKUP_PHASE='Remote-Abschlussmarker'; UPLOAD_STATUS=MARKER
|
||||
rc copyto "$RUN_DIR/COMPLETE" "$remote_run/COMPLETE" --immutable
|
||||
# Command substitution strips trailing newlines, which could accept a marker
|
||||
# that the strict restore parser rejects. Compare the exact returned bytes.
|
||||
@@ -115,16 +124,19 @@ sys.exit(0 if local.stat().st_size == remote.stat().st_size and local.read_bytes
|
||||
PY
|
||||
date -u -Is > "$RUN_DIR/UPLOADED"
|
||||
sync -f "$RUN_DIR"
|
||||
UPLOAD_STATUS=VERIFIED
|
||||
echo '-- Remote backup fully read back and verified'
|
||||
fi
|
||||
|
||||
if [[ $SKIP_RETENTION == true ]]; then
|
||||
BACKUP_PHASE='Abgeschlossen (Retention übersprungen)'
|
||||
echo "SUCCESS: $RUN_ID (retention skipped for acceptance run)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Retention works on complete v2 sets only, after a new successful backup.
|
||||
# Older flat archives, partial runs and unknown folders are deliberately preserved.
|
||||
BACKUP_PHASE=Retention
|
||||
valid="$STAGING_DIR/local-retention.txt"
|
||||
: > "$valid"
|
||||
for dir in "$ARCHIVE_DIR/${ARCHIVE_PREFIX}_"*; do
|
||||
@@ -160,8 +172,9 @@ if [[ $ENABLE_UPLOAD == true && $ENABLE_REMOTE_RETENTION == true ]]; then
|
||||
done < "$STAGING_DIR/remote-delete.txt"
|
||||
fi
|
||||
# Per-run filenames need age-based cleanup, not rotating an empty successor file.
|
||||
for operation in backup restore; do
|
||||
find "$LOG_DIR" -maxdepth 1 -type f -name "${operation}_${ARCHIVE_PREFIX}_*.log" \
|
||||
for operation in backup restore report; do
|
||||
find "$LOG_DIR" -maxdepth 1 -type f \( -name "${operation}_${ARCHIVE_PREFIX}_*.log" -o -name "${operation}_${ARCHIVE_PREFIX}_*.eml" \) \
|
||||
-mtime "+${LOG_RETENTION_DAYS}" ! -name "$(basename "$LOG_FILE")" -delete
|
||||
done
|
||||
BACKUP_PHASE=Abgeschlossen
|
||||
echo "SUCCESS: $RUN_ID"
|
||||
Reference in new issue
Block a user