# SDN Setup für Ring Network mit Thunderbolt - Datacenter auswählen - SDN > Fabrics - Add Fabric > OpenFabric - Name: `tbfabric` (max 8 Zeichen) - IPv4 Prefix: `10.0.21.0/29` - Add Node (für alle Nodes des Clusters) - IPv4 10.0.21.1 (statische IP aus Netz des Prefixes von oben) - X `thunderbolt0` (keine IP zuweisen) - X `thunderbolt1` (keine IP zuweisen) - SDN auswählen im Hauptmenu wieder - Apply # Thunderbolt Interface Monitor für Proxmox Automatisches Monitoring und Recovery für Thunderbolt-Interfaces zwischen Proxmox-Nodes. ## Features - 🔍 Überwacht `thunderbolt0` und `thunderbolt1` - 🔄 Automatischer Neustart bei Interface-Problemen - 📝 Detailliertes Logging mit farbigen Status-Icons - 🚀 systemd Service Integration - 🔧 Konfigurierbare Check-Intervalle - 📊 Log-Rotation bei großen Dateien ## Manuelle Installation ### 1. Thunderbolt Monitor Script erstellen ```bash cat > /usr/local/bin/thunderbolt-monitor.sh << 'SCRIPT_EOF' #!/bin/bash # ========================= # Konfiguration # ========================= INTERFACES=("thunderbolt0" "thunderbolt1") CHECK_INTERVAL=30 LOG_FILE="/var/log/thunderbolt-monitor.log" MAX_LOG_SIZE=10485760 # Ziel-IPs (eigene Dummy-IP aus /etc/network/interfaces.d/sdn wird automatisch ausgeschlossen) PING_TARGETS=("10.0.21.1" "10.0.21.2" "10.0.21.3") PING_COUNT=1 PING_TIMEOUT=1 SELF_CONF_FILE="/etc/network/interfaces.d/sdn" SELF_IP="" # Icons ICON_INFO="🔵" # Info / UP keine Aktion ICON_OK="✅" # Erfolg/Haken ICON_ERR="❌" # Fehler ICON_WARN="⚠️" # Warnung (z. B. Interface existiert nicht) ICON_RESTART="🔄" # Neustart-Aktion ICON_UP="🟢" # Up ICON_DOWN="🔴" # Down # Farbe Interface-Name (ANSI bleibt im Log → sichtbar mit `tail -f`) IF_COLOR_START=$'\033[95m' IF_COLOR_END=$'\033[0m' # ========================= # Interner Zustand # ========================= # Map: pro Interface die Liste zuletzt fehlgeschlagener Ping-Ziele (für Retry im nächsten Zyklus) declare -A FAILMAP # key: iface, value: "ip1 ip2 ..." # ========================= # Logging / Utilities # ========================= ci() { printf '%b' "${IF_COLOR_START}$1${IF_COLOR_END}"; } log_line() { local icon="$1"; shift local msg="$*" local ts ts=$(date '+%Y-%m-%d %H:%M:%S') printf '[%s] %s %s\n' "$ts" "$icon" "$msg" | tee -a "$LOG_FILE" } rotate_log() { if [[ -f "$LOG_FILE" ]]; then local size size=$(stat -c%s "$LOG_FILE" 2>/dev/null || stat -f%z "$LOG_FILE" 2>/dev/null || echo 0) (( size > MAX_LOG_SIZE )) && { mv "$LOG_FILE" "${LOG_FILE}.old"; log_line "$ICON_INFO" "Log rotiert – alte Datei: ${LOG_FILE}.old"; } fi } # Eigene Dummy-IP aus der sdn-Datei ermitteln (Zeile "address /" im Block von dummy_tbfabric) detect_self_ip() { [[ -r "$SELF_CONF_FILE" ]] || { SELF_IP=""; return 0; } local addr_line addr_line=$(awk ' BEGIN{found=0} /^iface[ \t]+dummy_tbfabric[ \t]+inet[ \t]+static/{found=1;next} found && /address[ \t]+/ {print; exit} ' "$SELF_CONF_FILE") if [[ -n "$addr_line" ]]; then local raw_ip raw_ip=$(echo "$addr_line" | awk '{print $2}') SELF_IP="${raw_ip%%/*}" fi } # Source-IP des Interfaces ermitteln (erste IPv4) iface_src_ip() { local iface="$1" ip -4 -o addr show dev "$iface" 2>/dev/null | awk '{print $4}' | cut -d/ -f1 | head -n1 } # ROBUSTE PING-STRATEGIE: # 1) routingbasiert (ohne -I) # 2) -I (Gerätebindung) # 3) -I (Quelle fixen) ping_host() { local iface="$1" ip="$2" # 1) normal über Routing if ping -c "$PING_COUNT" -W "$PING_TIMEOUT" "$ip" &>/dev/null; then return 0 fi # 2) Interface binden if ping -I "$iface" -c "$PING_COUNT" -W "$PING_TIMEOUT" "$ip" &>/dev/null; then return 0 fi # 3) Source-IP binden local src; src="$(iface_src_ip "$iface")" if [[ -n "$src" ]]; then ping -I "$src" -c "$PING_COUNT" -W "$PING_TIMEOUT" "$ip" &>/dev/null && return 0 fi return 1 } # Status ermitteln is_interface_up() { local iface="$1" ip link show "$iface" &>/dev/null || return 2 # 2 = existiert nicht local state oper state=$(ip link show "$iface" | grep -o 'state [A-Z]*' | awk '{print $2}') oper=$(cat "/sys/class/net/$iface/operstate" 2>/dev/null || echo "unknown") [[ "$state" == "UP" && "$oper" == "up" ]] && return 0 || return 1 } # Hilfen für FAILMAP add_failed_targets() { local iface="$1"; shift local existing="${FAILMAP[$iface]}" local -A seen=() for ip in $existing "$@"; do [[ -z "$ip" ]] && continue seen["$ip"]=1 done local merged="" for ip in "${!seen[@]}"; do merged+="$ip "; done FAILMAP[$iface]="${merged%% }" } retry_failed_targets() { local iface="$1" local list="${FAILMAP[$iface]}" [[ -z "$list" ]] && return 0 log_line "$ICON_INFO" "Retry fehlgeschlagener Pings: $list" local -a new_fail=() local ip for ip in $list; do if ping_host "$iface" "$ip"; then log_line "$ICON_OK" "Retry erfolgreich: $ip" else log_line "$ICON_ERR" "Retry fehlgeschlagen: $ip" new_fail+=("$ip") fi done if (( ${#new_fail[@]} == 0 )); then log_line "$ICON_OK" "Alle zuvor fehlgeschlagenen Ziele nun erreichbar" unset 'FAILMAP[$iface]' else FAILMAP[$iface]="${new_fail[*]}" fi } # Neustart + Reachability-Checks (5s delay), ausführliches Logging restart_with_checks() { local iface="$1" log_line "$ICON_RESTART" "Starte Interface $(ci "$iface") neu..." /sbin/ifdown "$iface" &>/dev/null && log_line "$ICON_INFO" "Interface $(ci "$iface") heruntergefahren" sleep 2 if /sbin/ifup "$iface" &>/dev/null; then log_line "$ICON_OK" "Interface $(ci "$iface") erfolgreich gestartet" sleep 5 # Gegenstellen pingen (eigene Dummy-IP ausschließen) detect_self_ip local -a targets=() for ip in "${PING_TARGETS[@]}"; do [[ -z "$ip" ]] && continue [[ -n "$SELF_IP" && "$ip" == "$SELF_IP" ]] && continue targets+=("$ip") done local all_ok=1 local -a failed_now=() local ip for ip in "${targets[@]}"; do if ping_host "$iface" "$ip"; then log_line "$ICON_OK" "Ping erfolgreich: $ip" else all_ok=0 failed_now+=("$ip") log_line "$ICON_ERR" "Ping fehlgeschlagen: $ip" fi done # Für nächste Runde merken if (( ${#failed_now[@]} > 0 )); then add_failed_targets "$iface" "${failed_now[@]}" fi if (( all_ok == 1 )); then log_line "$ICON_OK" "Interface $(ci "$iface") erfolgreich neugestartet" fi else log_line "$ICON_ERR" "Interface $(ci "$iface") konnte nicht gestartet werden" fi } # Hauptroutine: alle 30s prüfen, je Interface separat handeln + ggf. Retry-Queue monitor_loop() { log_line "$ICON_INFO" "Thunderbolt Monitor gestartet (Intervall: ${CHECK_INTERVAL}s)" detect_self_ip [[ -n "$SELF_IP" ]] && log_line "$ICON_INFO" "Eigene Dummy-IP erkannt: $SELF_IP (von Pings ausgeschlossen)" while true; do rotate_log for iface in "${INTERFACES[@]}"; do is_interface_up "$iface" case $? in 0) log_line "$ICON_INFO" "Interface $(ci "$iface") ist UP – keine Aktion erforderlich." # Retry offen gebliebener Ping-Fehlschläge retry_failed_targets "$iface" ;; 1) log_line "$ICON_DOWN" "Interface $(ci "$iface") ist DOWN – versuche Neustart." restart_with_checks "$iface" ;; 2) log_line "$ICON_WARN" "Interface $(ci "$iface") existiert nicht" ;; esac done sleep "$CHECK_INTERVAL" done } cleanup() { log_line "$ICON_WARN" "Thunderbolt Monitor wird beendet"; exit 0; } trap cleanup SIGTERM SIGINT case "${1:-}" in "--test") monitor_loop & pid=$! sleep 3 kill $pid ;; "--clear") : > "$LOG_FILE"; log_line "$ICON_INFO" "Log-Datei geleert";; *) monitor_loop;; esac SCRIPT_EOF chmod +x /usr/local/bin/thunderbolt-monitor.sh ``` ### 2. systemd Service erstellen ```bash cat > /etc/systemd/system/thunderbolt-monitor.service << 'EOF' [Unit] Description=🔌 Thunderbolt Interface Monitor After=network.target frr.service Wants=network.target Requires=network.target [Service] Type=simple User=root ExecStart=/usr/local/bin/thunderbolt-monitor.sh ExecReload=/bin/kill -HUP $MAINPID Restart=always RestartSec=10 StandardOutput=journal StandardError=journal # Umgebungsvariablen Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin # Security Settings NoNewPrivileges=true ProtectSystem=strict ReadWritePaths=/var/log /var/run /sys/class/net [Install] WantedBy=multi-user.target EOF ``` ### 3. Service aktivieren und starten ```bash # Log-Datei vorbereiten touch /var/log/thunderbolt-monitor.log chmod 644 /var/log/thunderbolt-monitor.log # Service aktivieren systemctl daemon-reload systemctl enable thunderbolt-monitor systemctl start thunderbolt-monitor ``` ## Verwendung ### Status-Icons im Log | Icon | Bedeutung | Level | |------|-----------|--------| | 🔵 | Allgemeine Information | INFO | | ✅ | Erfolgreiche Aktion | SUCCESS | | ❌ | Fehler aufgetreten | ERROR | | ⚠️ | Warnung | WARNING | | 🔄 | Aktion wird ausgeführt | ACTION | | 🟢 | Interface ist UP | UP | | 🔴 | Interface ist DOWN | DOWN | ### Befehle ```bash # Service starten systemctl start thunderbolt-monitor # Service stoppen systemctl stop thunderbolt-monitor # Status prüfen systemctl status thunderbolt-monitor # Live-Logs verfolgen tail -f /var/log/thunderbolt-monitor.log # journalctl Logs journalctl -u thunderbolt-monitor -f # Einmaliger Test /usr/local/bin/thunderbolt-monitor.sh --test # Manuell im Vordergrund starten /usr/local/bin/thunderbolt-monitor.sh ``` ### Konfiguration anpassen ```bash # Script bearbeiten nano /usr/local/bin/thunderbolt-monitor.sh # Check-Interval ändern (in Sekunden) CHECK_INTERVAL=30 # Überwachte Interfaces ändern INTERFACES=("thunderbolt0" "thunderbolt1" "thunderbolt2") ``` ## Log-Beispiele ``` [2025-08-14 10:59:10] 🔵 Thunderbolt Monitor gestartet (Intervall: 30s) [2025-08-14 10:59:10] 🔵 Eigene Dummy-IP erkannt: 10.0.21.2 (von Pings ausgeschlossen) [2025-08-14 10:59:10] 🔵 Interface thunderbolt0 ist UP - keine Aktion erforderlich. [2025-08-14 10:59:10] 🔵 Interface thunderbolt1 ist UP - keine Aktion erforderlich. [2025-08-14 10:59:40] 🔵 Interface thunderbolt0 ist UP - keine Aktion erforderlich. [2025-08-14 10:59:40] 🔵 Interface thunderbolt1 ist UP - keine Aktion erforderlich. [2025-08-14 11:00:10] 🔵 Interface thunderbolt0 ist UP - keine Aktion erforderlich. [2025-08-14 11:00:10] 🔵 Interface thunderbolt1 ist UP - keine Aktion erforderlich. [2025-08-14 11:00:40] 🔵 Interface thunderbolt0 ist UP - keine Aktion erforderlich. [2025-08-14 11:00:40] ⚠️ Interface thunderbolt1 existiert nicht [2025-08-14 11:01:10] 🔵 Interface thunderbolt0 ist UP - keine Aktion erforderlich. [2025-08-14 11:01:10] 🔴 Interface thunderbolt1 ist DOWN - versuche Neustart. [2025-08-14 11:01:10] 🔄 Starte Interface thunderbolt1 neu... [2025-08-14 11:01:10] 🔵 Interface thunderbolt1 heruntergefahren [2025-08-14 11:01:13] ✅ Interface thunderbolt1 erfolgreich gestartet [2025-08-14 11:01:19] ✅ Ping erfolgreich: 10.0.21.1 [2025-08-14 11:01:19] ✅ Ping erfolgreich: 10.0.21.3 [2025-08-14 11:01:19] ✅ Interface thunderbolt1 erfolgreich neugestartet [2025-08-14 11:01:49] 🔵 Interface thunderbolt0 ist UP - keine Aktion erforderlich. [2025-08-14 11:01:49] 🔵 Interface thunderbolt1 ist UP - keine Aktion erforderlich. ``` ## Troubleshooting ### Häufige Probleme 1. **Service startet nicht:** ```bash journalctl -u thunderbolt-monitor -o cat -f ``` 2. **Interfaces werden nicht erkannt:** ```bash ip link show | grep thunderbolt ``` 3. **Permissions-Probleme:** ```bash ls -la /usr/local/bin/thunderbolt-monitor.sh ``` ### Debug-Modus ```bash # Service stoppen und manuell mit Debug starten systemctl stop thunderbolt-monitor /usr/local/bin/thunderbolt-monitor.sh --test ```