#!/bin/bash # Dell N2048 Switch FTP Backup Script mit externer Konfiguration # Aufruf: ./switch_backup.sh # Konfiguration: /etc/switchbackup/.cfg #=========================================== # GRUNDKONFIGURATION #=========================================== # Pfad zu den Konfigurationsdateien CONFIG_DIR="/etc/switchbackup" SCRIPT_NAME=$(basename "$0") # Logging LOG_FILE="/var/log/dell_switch_backup.log" #=========================================== # PARAMETER PRÜFUNG #=========================================== if [ $# -eq 0 ]; then echo "FEHLER: Keine Konfiguration angegeben!" echo "" echo "Verwendung: $SCRIPT_NAME " echo "" echo "Beispiele:" echo " $SCRIPT_NAME switch01" echo " $SCRIPT_NAME datacenter-core" echo "" echo "Konfigurationsdateien unter: $CONFIG_DIR/" echo "Verfügbare Konfigurationen:" if [ -d "$CONFIG_DIR" ]; then ls -1 "$CONFIG_DIR"/*.cfg 2>/dev/null | sed 's|.*/||; s|\.cfg$||' | sed 's/^/ - /' || echo " (keine gefunden)" else echo " (Verzeichnis $CONFIG_DIR existiert nicht)" fi exit 1 fi CONFIG_NAME="$1" CONFIG_FILE="$CONFIG_DIR/${CONFIG_NAME}.cfg" #=========================================== # KONFIGURATION LADEN #=========================================== # Prüfe ob Konfigurationsdatei existiert if [ ! -f "$CONFIG_FILE" ]; then echo "FEHLER: Konfigurationsdatei nicht gefunden: $CONFIG_FILE" echo "" echo "Verfügbare Konfigurationen:" if [ -d "$CONFIG_DIR" ]; then ls -1 "$CONFIG_DIR"/*.cfg 2>/dev/null | sed 's|.*/||; s|\.cfg$||' | sed 's/^/ - /' || echo " (keine gefunden)" else echo " (Verzeichnis $CONFIG_DIR existiert nicht)" echo "" echo "Erstellen Sie das Verzeichnis mit:" echo " sudo mkdir -p $CONFIG_DIR" fi exit 1 fi # Konfiguration laden log() { echo "$(date '+%Y-%m-%d %H:%M:%S') [$CONFIG_NAME] - $1" | tee -a "$LOG_FILE" } log "Lade Konfiguration: $CONFIG_FILE" # Source die Konfigurationsdatei source "$CONFIG_FILE" # Validiere erforderliche Parameter required_vars="SWITCH_IP SWITCH_USER SWITCH_PASSWORD FTP_SERVER FTP_USER FTP_PASSWORD" missing_vars="" for var in $required_vars; do if [ -z "${!var}" ]; then missing_vars="$missing_vars $var" fi done if [ -n "$missing_vars" ]; then log "FEHLER: Fehlende Parameter in $CONFIG_FILE:$missing_vars" exit 1 fi # Setze Standardwerte falls nicht definiert CONFIG_TYPE="${CONFIG_TYPE:-startup-config}" MAX_BACKUPS="${MAX_BACKUPS:-10}" SKIP_SSH_TEST="${SKIP_SSH_TEST:-true}" SWITCH_NAME="${SWITCH_NAME:-${CONFIG_NAME}}" FTP_PATH="${FTP_PATH:-switch-backup}" # Config-Prefix ableiten CONFIG_PREFIX="sc" if [ "$CONFIG_TYPE" = "running-config" ]; then CONFIG_PREFIX="rc" fi # Dateiname generieren (max 32 Zeichen) TIMESTAMP=$(date +"%Y%m%d_%H%M") BACKUP_FILENAME="${SWITCH_NAME}_${CONFIG_PREFIX}_${TIMESTAMP}.cfg" # Timeout-Werte SSH_TIMEOUT="${SSH_TIMEOUT:-15}" COMMAND_TIMEOUT="${COMMAND_TIMEOUT:-30}" COPY_TIMEOUT="${COPY_TIMEOUT:-90}" #=========================================== # FUNKTIONEN #=========================================== # Prüfe ob expect installiert ist check_dependencies() { if ! command -v expect >/dev/null 2>&1; then log "FEHLER: expect ist nicht installiert." log "Installation: sudo apt-get install expect" exit 1 fi if ! command -v ftp >/dev/null 2>&1; then log "WARNUNG: ftp-client nicht installiert - FTP-Cleanup nicht möglich" log "Installation: sudo apt-get install ftp" fi } # Validiere Dateiname-Länge validate_filename() { if [ ${#BACKUP_FILENAME} -gt 32 ]; then log "FEHLER: Dateiname zu lang (${#BACKUP_FILENAME} > 32 Zeichen): $BACKUP_FILENAME" log "Kürzen Sie SWITCH_NAME in der Konfiguration" exit 1 fi log "Dateiname-Länge OK: $BACKUP_FILENAME (${#BACKUP_FILENAME} Zeichen)" } # Teste SSH-Verbindung mit expect (optional) test_ssh_connection() { if [ "$SKIP_SSH_TEST" = "true" ]; then log "SSH-Test übersprungen (SKIP_SSH_TEST=true)" return 0 fi log "Teste SSH-Verbindung zu $SWITCH_IP..." expect << EOF >/dev/null 2>&1 set timeout $SSH_TIMEOUT spawn ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null $SWITCH_USER@$SWITCH_IP expect { "password:" { send "$SWITCH_PASSWORD\r" expect { ">" { send "exit\r" expect eof exit 0 } "#" { send "exit\r" expect eof exit 0 } timeout { exit 1 } eof { exit 1 } } } timeout { exit 1 } eof { exit 1 } } EOF local result=$? if [ $result -eq 0 ]; then log "SSH-Verbindung erfolgreich" return 0 else log "FEHLER: SSH-Verbindung fehlgeschlagen" return 1 fi } # FTP-Backup mit expect ausführen execute_ftp_backup() { log "Starte FTP-Backup: $CONFIG_TYPE -> ftp://$FTP_SERVER/$BACKUP_FILENAME" # FTP-Befehl OHNE Passwort im URL local ftp_command="copy $CONFIG_TYPE ftp://$FTP_USER@$FTP_SERVER/$FTP_PATH/$BACKUP_FILENAME" # Temporäre Datei für expect-Ausgabe local temp_output="/tmp/switch_backup_output_$$" expect << EOF > "$temp_output" 2>&1 set timeout $SSH_TIMEOUT log_user 0 spawn ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null $SWITCH_USER@$SWITCH_IP expect { "password:" { send "$SWITCH_PASSWORD\r" expect { ">" { # User-Mode, enable ausführen send "enable\r" expect { "#" { # Enable-Mode, copy-Befehl ausführen send "$ftp_command\r" expect { "Remote Password:" { # Switch fragt nach FTP-Passwort send "$FTP_PASSWORD\r" expect { "Are you sure you want to start? (y/n)" { # Bestätigung erforderlich send "y\r" set timeout $COPY_TIMEOUT expect { -re "(File transfer operation completed successfully|transfer.*completed|bytes transferred)" { send "exit\r" expect eof exit 0 } -re "(Error|Failed|failed|Timeout|timeout|Access denied|denied)" { send "exit\r" expect eof exit 2 } timeout { send "exit\r" expect eof exit 3 } } } -re "(Error|Failed|Invalid|Access denied)" { send "exit\r" expect eof exit 2 } timeout { send "exit\r" expect eof exit 3 } } } -re "(Error|Failed|Invalid|Access denied)" { send "exit\r" expect eof exit 2 } timeout { send "exit\r" expect eof exit 3 } } } "password:" { # Enable-Passwort erforderlich send "$SWITCH_PASSWORD\r" expect "#" send "$ftp_command\r" expect { "Remote Password:" { send "$FTP_PASSWORD\r" expect { "Are you sure you want to start? (y/n)" { send "y\r" set timeout $COPY_TIMEOUT expect { -re "(File transfer operation completed successfully|transfer.*completed|bytes transferred)" { send "exit\r" expect eof exit 0 } -re "(Error|Failed|failed|Timeout|timeout|Access denied|denied)" { send "exit\r" expect eof exit 2 } timeout { send "exit\r" expect eof exit 3 } } } timeout { exit 3 } } } timeout { exit 3 } } } timeout { exit 1 } } } "#" { # Bereits im Enable-Mode send "$ftp_command\r" expect { "Remote Password:" { send "$FTP_PASSWORD\r" expect { "Are you sure you want to start? (y/n)" { send "y\r" set timeout $COPY_TIMEOUT expect { -re "(File transfer operation completed successfully|transfer.*completed|bytes transferred)" { send "exit\r" expect eof exit 0 } -re "(Error|Failed|failed|Timeout|timeout|Access denied|denied)" { send "exit\r" expect eof exit 2 } timeout { send "exit\r" expect eof exit 3 } } } timeout { exit 3 } } } timeout { exit 3 } } } timeout { exit 1 } eof { exit 1 } } } timeout { exit 1 } eof { exit 1 } } EOF local result=$? local output=$(cat "$temp_output" 2>/dev/null) # Nur relevante Ausgabe loggen local bytes_transferred=$(echo "$output" | grep "bytes transferred" | tail -1) if [ -n "$bytes_transferred" ]; then log "Transfer: $bytes_transferred" fi # Cleanup rm -f "$temp_output" # Ergebnis auswerten case $result in 0) log "FTP-Backup erfolgreich abgeschlossen" return 0 ;; 1) log "FEHLER: SSH-Verbindung oder Anmeldung fehlgeschlagen" return 1 ;; 2) log "FEHLER: FTP-Copy-Befehl fehlgeschlagen (Fehlermeldung erkannt)" return 1 ;; 3) log "FEHLER: Timeout beim FTP-Copy-Befehl" return 1 ;; *) log "FEHLER: Unbekannter Fehler (Exit-Code: $result)" return 1 ;; esac } # Alte Backups auf FTP-Server löschen cleanup_old_backups() { if ! command -v ftp >/dev/null 2>&1; then log "FTP-Client nicht verfügbar - Cleanup übersprungen" return 0 fi log "Bereinige alte Backups (behalte die neuesten $MAX_BACKUPS)..." # Temporäre Dateien local ftp_list="/tmp/ftp_list_$$" local files_to_delete="/tmp/files_to_delete_$$" # FTP-Verzeichnis auflisten ftp -n "$FTP_SERVER" << EOF > "$ftp_list" 2>/dev/null user $FTP_USER $FTP_PASSWORD cd $FTP_PATH ls ${SWITCH_NAME}_${CONFIG_PREFIX}_*.cfg quit EOF # Extrahiere nur Dateinamen und sortiere nach Datum (neueste zuerst) grep "\.cfg$" "$ftp_list" | awk '{print $NF}' | grep "^${SWITCH_NAME}_${CONFIG_PREFIX}_" | sort -r > "$files_to_delete" local total_files=$(wc -l < "$files_to_delete") if [ "$total_files" -gt "$MAX_BACKUPS" ]; then local files_to_remove=$((total_files - MAX_BACKUPS)) log "Gefunden: $total_files Backup-Dateien, lösche die ältesten $files_to_remove" # Die ältesten Dateien löschen (ab Zeile MAX_BACKUPS+1) tail -n +"$((MAX_BACKUPS + 1))" "$files_to_delete" | while read -r filename; do if [ -n "$filename" ]; then log "Lösche alte Backup-Datei: $filename" ftp -n "$FTP_SERVER" << EOF >/dev/null 2>&1 user $FTP_USER $FTP_PASSWORD cd $FTP_PATH delete $filename quit EOF fi done else log "Cleanup: $total_files Dateien gefunden, alle werden behalten (< $MAX_BACKUPS)" fi # Cleanup rm -f "$ftp_list" "$files_to_delete" } #=========================================== # HAUPTPROGRAMM #=========================================== log "==========================================" log "Dell N2048 FTP Backup gestartet" log "Konfiguration: $CONFIG_NAME" log "Switch: $SWITCH_IP ($SWITCH_NAME)" log "Config-Type: $CONFIG_TYPE" log "FTP-Server: $FTP_SERVER" log "Backup-Datei: $BACKUP_FILENAME" log "Max Backups: $MAX_BACKUPS" log "==========================================" # 1. Abhängigkeiten prüfen check_dependencies # 2. Dateiname validieren validate_filename # 3. SSH-Verbindung testen (optional) if ! test_ssh_connection; then log "Backup abgebrochen wegen SSH-Verbindungsproblem" exit 1 fi # 4. FTP-Backup ausführen backup_start_time=$(date +%s) if execute_ftp_backup; then backup_end_time=$(date +%s) backup_duration=$((backup_end_time - backup_start_time)) log "Backup-Dauer: ${backup_duration} Sekunden" # 5. Alte Backups bereinigen cleanup_old_backups log "==========================================" log "BACKUP ERFOLGREICH ABGESCHLOSSEN" log "Konfiguration: $CONFIG_NAME" log "Datei auf FTP-Server: $BACKUP_FILENAME" log "Backup-Dauer: ${backup_duration} Sekunden" log "==========================================" exit 0 else log "==========================================" log "BACKUP FEHLGESCHLAGEN" log "Konfiguration: $CONFIG_NAME" log "Prüfen Sie FTP-Server-Verbindung und Zugangsdaten" log "==========================================" exit 1 fi