Verify Limitieren

CH.illig

Renowned Member
Feb 20, 2016
79
17
73
34
Switzerland
it-statistik.ch
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
  1. backup-type:
  2. backup-id:
  3. backup-time:
    1685229263
  4. ignore-verified:
    false
  5. 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
 
Du könntest das Re-Verify Setting sehr hoch stellen: Standardmäßig steht es bei 30 Tagen, so dass frühere Backups alle 30 Tage einmal überprüft werden. Stellst du das auf 90, 180, 365 Tage, werden die alten Backups seltener geprüft.

Falls du darunter ein Filesystem wie ZFS verwendest, was ein eigenständiges Scrubbing/Resilvering durchführt sind wiederholte komplette Verify des Inhaltes eigentlich nicht mehr notwendig, so lange man zumindest prüfen kann dass alle Chunks noch da sind. Für den Fall gibt es einen Feature Request nach einem light- oder logical-verify unter https://bugzilla.proxmox.com/show_bug.cgi?id=6244.
 
  • Like
Reactions: Johannes S
Warum hast du denn ignore-verified auf false gesetzt? In euren Fall würde das doch im Kombination mit dem re-verify-Setting schon mal etwas helfen?
<span>ignore-verified</span><span>&lt;boolean&gt;</span>&nbsp;&nbsp; <span>(default=true)</span>
Do not verify backups that are already verified if their verification is not outdated.

https://pbs.proxmox.com/docs/configuration-files.html

Davon abgesehen die Standardempfehlung: Auch wenn bei verify-Jobs der Effekt nicht so groß ist wie bei der garbage-collection: Ein special device mit Enterprise-SSDs könnte wenigstens ein bissel helfen: https://pbs.proxmox.com/docs/sysadmin.html#zfs-special-device

Wie ist eurer HDD-Pool aufgebaut? RAIDZ, striped mirror oder ganz anders?
 
  • Like
Reactions: UdoB