482 lines
16 KiB
Bash
482 lines
16 KiB
Bash
#!/bin/bash
|
|
|
|
# Dell N2048 Switch FTP Backup Script mit externer Konfiguration
|
|
# Aufruf: ./switch_backup.sh <konfig_name>
|
|
# Konfiguration: /etc/switchbackup/<konfig_name>.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 <konfig_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
|