Hallo zusammen,
ich habe aktuell einen Proxmox Backup Server für unser Archiv im Einsatz,
der mit HDDs bestückt ist (10-Jahres-Archiv).
Deswegen dauert das Verify nun mal seine Zeit.
Der Archiv-Server ist so aufgebaut, dass er täglich die Backups vom Live-System abholt (Georedundanz).
Er hat jedoch eine andere Garbage Collection (GC),
sodass ältere Backups erhalten bleiben und nicht wie auf dem Produktionssystem nach x Tagen gelöscht werden.
Soweit so gut, und wir sind damit zufrieden.
Das Verify auf dem Server dauert aber "ewigs",
vor allem aus dem Grund, weil er auch die aktuellen Tagesbackups mit überprüft – die ja in ein paar Tagen ohnehin gelöscht werden.
Gibt es eine Möglichkeit, einzustellen, dass er beim Verify nur Backups berücksichtigt, die "älter als x Tage" sind?
via bash wäre ich so aber ich finde laut doku keinen weg wie ich ein verify starten kann (explizit für ein backup)
via web geht es auf
https://xxxxxxx:8007/api2/extjs/admin/datastore/svdrz120/verify
mit dem Payload
der gedanke währe an irgenddwie sowas wie im script mal eingebaut:
proxmox-backup-client verify $ns_option "$snapshot_id"
ich habe aktuell einen Proxmox Backup Server für unser Archiv im Einsatz,
der mit HDDs bestückt ist (10-Jahres-Archiv).
Deswegen dauert das Verify nun mal seine Zeit.
Der Archiv-Server ist so aufgebaut, dass er täglich die Backups vom Live-System abholt (Georedundanz).
Er hat jedoch eine andere Garbage Collection (GC),
sodass ältere Backups erhalten bleiben und nicht wie auf dem Produktionssystem nach x Tagen gelöscht werden.
Soweit so gut, und wir sind damit zufrieden.
Das Verify auf dem Server dauert aber "ewigs",
vor allem aus dem Grund, weil er auch die aktuellen Tagesbackups mit überprüft – die ja in ein paar Tagen ohnehin gelöscht werden.
Gibt es eine Möglichkeit, einzustellen, dass er beim Verify nur Backups berücksichtigt, die "älter als x Tage" sind?
via bash wäre ich so aber ich finde laut doku keinen weg wie ich ein verify starten kann (explizit für ein backup)
via web geht es auf
https://xxxxxxx:8007/api2/extjs/admin/datastore/svdrz120/verify
mit dem Payload
- backup-type:
- backup-id:
- backup-time:
1685229263 - ignore-verified:
false - ns:
der gedanke währe an irgenddwie sowas wie im script mal eingebaut:
proxmox-backup-client verify $ns_option "$snapshot_id"
Bash:
#!/bin/bash
# === Konfiguration ===
# Anzahl der Tage, nach denen Snapshots als "alt" gelten und verifiziert werden sollen
RETENTION_DAYS=900
# Pfad zur Log-Datei
LOG_FILE="/var/log/pbs_verify_old_snapshots.log"
# Testmodus: "true" zum Aktivieren (nur protokollieren, nicht ausführen), "false" zum Deaktivieren
# EMPFOHLEN: Zuerst auf "true" lassen und Log prüfen!
TEST_MODE="false"
# --- PBS Authentifizierung (API Token - Empfohlen) ---
# Tragen Sie hier die Token ID und das Secret ein, die Sie generiert haben.
# Beispiel Token ID: root@pam!verify-script
PBS_TOKEN_ID="root@pam!verify_script" # ANPASSEN, falls nötig
# Beispiel Secret: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
PBS_TOKEN_SECRET='0b0d511d-0bec-4653-b2a3-1dac68e3fbb8' # ANPASSEN!
# Basis für den Repository String (wird in der Schleife vervollständigt)
# Format: <token-id>@<hostname_oder_ip>
# Für lokalen Zugriff kann oft localhost oder 127.0.0.1 verwendet werden.
PBS_REPOSITORY_BASE="${PBS_TOKEN_ID}@localhost" # Ggf. Host anpassen
# Setzen Sie das Token Secret als Passwort-Variable für proxmox-backup-client
export PBS_PASSWORD="${PBS_TOKEN_SECRET}"
# --- Ende PBS Authentifizierung ---
# === Ende der Konfiguration ===
# --- Funktion zur Protokollierung ---
log_message() {
# Stellt sicher, dass die Ausgabe sowohl auf der Konsole als auch im Log landet
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
# --- Funktion zum Verarbeiten von Snapshots (für Root oder Namespace) ---
# $1: Namespace-Option (z.B. "" für Root oder "--ns namespace/name")
# $2: Name für Logging (z.B. "root level" oder "namespace/name")
process_snapshots() {
local ns_option="$1" # z.B. "" oder "--ns namespace/name"
local ns_name_log="$2" # z.B. "root level" oder "namespace/name"
local snapshot_list_output
local list_exit_code
local snapshot_id
local snapshot_timestamp_str
local snapshot_timestamp_seconds
log_message "--- Bearbeite: $ns_name_log in Datastore '$datastore' ---"
# Verwende 'snapshot list'. Die Namespace-Option wird als $ns_option übergeben (leer für Root).
log_message "Suche Snapshots mit 'snapshot list $ns_option' und speichere Ausgabe..."
# Führe das Kommando aus. $ns_option wird durch die Shell korrekt expandiert.
snapshot_list_output=$(proxmox-backup-client snapshot list $ns_option --output-format=text | awk -F'│' 'NR > 3 && NF > 2 { gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); if ($2 != "") print $2 }')
list_exit_code=${PIPESTATUS[0]} # Exit Code von 'snapshot list'
log_message "--- START Ausgabe der gefilterten Snapshot-IDs für $ns_name_log ---"
if [[ -z "$snapshot_list_output" ]]; then
log_message "(Keine Snapshot-IDs nach Filterung gefunden)"
else
# Logge jede gefundene ID einzeln
printf '%s\n' "$snapshot_list_output" | while IFS= read -r line; do log_message " $line"; done
fi
log_message "--- ENDE Ausgabe der gefilterten Snapshot-IDs ---"
log_message "Exit Code von 'proxmox-backup-client snapshot list $ns_option' war: $list_exit_code"
# Verarbeite nur bei Erfolg
if [[ $list_exit_code -eq 0 ]]; then
log_message "Verarbeite die gespeicherte Snapshot-Liste für $ns_name_log..."
if [[ -z "$snapshot_list_output" ]]; then
log_message "Keine Snapshots in der Ausgabe gefunden zum Verarbeiten für $ns_name_log."
else
# Lese aus der Variable Zeile für Zeile
while IFS= read -r snapshot_id; do
if [[ -z "$snapshot_id" ]]; then continue; fi # Sollte nicht vorkommen, aber sicher ist sicher
# Extrahiere Zeitstempel (letzter Teil nach '/')
snapshot_timestamp_str=$(echo "$snapshot_id" | awk -F'/' '{print $NF}')
snapshot_timestamp_seconds=$(date +%s -d "$snapshot_timestamp_str" 2>/dev/null)
if [[ $? -ne 0 ]]; then
log_message "WARNUNG: Konnte Zeitstempel '$snapshot_timestamp_str' für Snapshot '$snapshot_id' ($ns_name_log) nicht parsen. Überspringe."
continue
fi
# Prüfe Alter und verifiziere ggf.
if [[ "$snapshot_timestamp_seconds" -lt "$cutoff_date_seconds" ]]; then
log_message "Gefunden: Alter Snapshot '$snapshot_id' (Datum: $snapshot_timestamp_str) in $ns_name_log"
if [[ "$TEST_MODE" == "true" ]]; then
# Verwende $ns_option (leer für Root, --ns ... für Namespace)
log_message "[TEST MODUS] Würde jetzt ausführen: proxmox-backup-client verify $ns_option \"$snapshot_id\""
else
log_message "Starte Verifizierung für Snapshot '$snapshot_id' in $ns_name_log..."
# Verwende $ns_option (leer für Root, --ns ... für Namespace)
if proxmox-backup-client verify $ns_option "$snapshot_id" >> "$LOG_FILE" 2>&1; then
log_message "ERFOLG: Verifizierung für Snapshot '$snapshot_id' in $ns_name_log abgeschlossen."
else
log_message "FEHLER: Verifizierung für Snapshot '$snapshot_id' in $ns_name_log fehlgeschlagen. Siehe Logdatei für Details."
fi
fi
fi
done <<< "$snapshot_list_output" # Lese aus Variable via Here-String
fi
else
# snapshot list ist fehlgeschlagen
log_message "FEHLER: 'proxmox-backup-client snapshot list $ns_option' fehlgeschlagen (Exit Code: $list_exit_code). Verarbeitung übersprungen."
log_message "Versuche, die Fehlermeldung (stderr) erneut abzurufen..."
# Leite stdout und stderr ins Log um
proxmox-backup-client snapshot list $ns_option --output-format=text >> "$LOG_FILE" 2>&1
log_message "--- Ende des erneuten Abrufversuchs ---"
fi
log_message "--- Verarbeitung für $ns_name_log abgeschlossen ---"
} # Ende der Funktion process_snapshots
# --- Haupt-Skriptlogik ---
# Start des Skripts protokollieren
log_message "===== Script Start: Verify Old Snapshots ====="
log_message "Konfiguration: RETENTION_DAYS=${RETENTION_DAYS}, TEST_MODE=${TEST_MODE}, LOG_FILE=${LOG_FILE}"
log_message "Verwendete Token ID: ${PBS_TOKEN_ID}" # Secret nicht loggen!
# Grundlegende Prüfung der Konfiguration
if [[ -z "$PBS_TOKEN_ID" ]] || [[ "$PBS_TOKEN_ID" == "DEINE-TOKEN-ID-HIER" ]]; then log_message "FEHLER: PBS_TOKEN_ID wurde nicht im Skript gesetzt!"; exit 1; fi
if [[ -z "$PBS_PASSWORD" ]] || [[ "$PBS_PASSWORD" == "DEIN-TOKEN-SECRET-HIER-EINFUEGEN" ]]; then log_message "FEHLER: PBS_TOKEN_SECRET wurde nicht im Skript gesetzt (Variable PBS_PASSWORD ist leer)!"; exit 1; fi
if [[ "$TEST_MODE" == "true" ]]; then log_message "!!! TEST MODUS AKTIV: Verify-Befehle werden nur protokolliert, nicht ausgeführt !!!"; fi
# Berechne Cutoff-Datum
cutoff_date_seconds=$(date +%s -d "$RETENTION_DAYS days ago")
log_message "Snapshots älter als $(date -d "@$cutoff_date_seconds" '+%Y-%m-%d %H:%M:%S') werden geprüft."
# 1. Alle konfigurierten Datastores ermitteln
log_message "Ermittle Datastores..."
datastores=$(proxmox-backup-manager datastore list | awk -F'│' 'NR > 3 && NF > 3 { gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); if ($2 != "") print $2 }')
if [[ -z "$datastores" ]]; then log_message "FEHLER: Keine Datastores gefunden oder Fehler beim Auflisten."; unset PBS_PASSWORD; exit 1; fi
log_message "Gefundene Datastores: $datastores"
# 2. Schleife über alle Datastores
for datastore in $datastores; do
log_message "==================== Bearbeite Datastore: $datastore ===================="
# Setze Repository-Variable für den aktuellen Datastore
export PBS_REPOSITORY="${PBS_REPOSITORY_BASE}:${datastore}"
log_message "Setze PBS_REPOSITORY auf: ${PBS_REPOSITORY}"
# *** Hauptordner (Root Level) prüfen ***
process_snapshots "" "root level"
# *** Namespaces prüfen (inkl. verschachtelter) ***
log_message "Ermittle Namespaces in Datastore '$datastore'..."
namespace_list=$(proxmox-backup-client namespace list)
ns_list_exit_code=$?
if [[ $ns_list_exit_code -ne 0 ]]; then
log_message "FEHLER: Konnte Namespaces für Datastore '$datastore' nicht auflisten (Exit Code: $ns_list_exit_code)."
log_message "Versuche Fehlermeldung (stderr) von 'namespace list' abzurufen..."
proxmox-backup-client namespace list >> "$LOG_FILE" 2>&1
log_message "--- Ende Abrufversuch ---"
# Fahre mit nächstem Datastore fort, Root wurde schon geprüft
elif [[ -z "$namespace_list" ]]; then
log_message "Keine Namespaces im Datastore '$datastore' gefunden."
else
log_message "Gefundene Namespaces für '$datastore': $(echo "$namespace_list" | tr '\n' ' ')"
# Schleife über alle gefundenen Namespaces (auch verschachtelte)
for namespace in $namespace_list; do
# Rufe die Funktion für jeden Namespace auf
process_snapshots "--ns $namespace" "$namespace"
done
fi
# Variable für den nächsten Datastore löschen
unset PBS_REPOSITORY
log_message "==================== Datastore '$datastore' abgeschlossen ===================="
done # Ende der Datastore-Schleife
# Passwort/Secret Variable am Ende löschen
unset PBS_PASSWORD
log_message "===== Script Ende ====="
exit 0