137 lines
6.3 KiB
Bash
137 lines
6.3 KiB
Bash
#!/bin/sh
|
|
# Autonome Flash- + Recovery-Orchestrierung für ALL-SG8316M.
|
|
# LÄUFT AUF DEM MAC MINI (10.40.41.167, en0, L2-lokal zum Switch).
|
|
# Zweck: Claude stößt es detached an und ist während des Switch-Reboots OFFLINE.
|
|
# Das Script zieht die ganze Kette autonom durch und loggt alles.
|
|
#
|
|
# Kette: pre-flight -> flash -> warte down -> warte up(.1.1|.239)
|
|
# -> (falls .1.1) IP zurück auf .239 [cmd dynamisch entdeckt]
|
|
# -> VLANs (best-effort) -> save-to-flash -> verify
|
|
#
|
|
# Aufruf: ./flash-and-recover.sh preflight # nur Checks, kein Flash
|
|
# ./flash-and-recover.sh run # echter Flash + Recovery
|
|
set -u
|
|
|
|
SW_PROD=10.40.41.239
|
|
SW_DEFAULT=192.168.1.1
|
|
PROD_MASK=255.255.255.0
|
|
PROD_GW=10.40.41.254
|
|
ALIAS_IP=192.168.1.2
|
|
VLANS=10,20,30,40,100
|
|
IMG="${IMG:-$HOME/bf-switch-flash/all-sg8316m-version_2.2.1_vmlinux.bix}"
|
|
IMG_SHA=e3f160983e8b17962dc70a52360b7f560c92da8197928d702f5266027a0fc7fc
|
|
LOG="${LOG:-$HOME/bf-switch-flash/flash-$(date +%Y%m%d-%H%M%S).log}"
|
|
MODE="${1:-preflight}"
|
|
|
|
mkdir -p "$(dirname "$LOG")"
|
|
log(){ printf '%s %s\n' "$(date '+%H:%M:%S')" "$*" | tee -a "$LOG"; }
|
|
|
|
# Liveness: Webserver-Root antwortet (firmware-stabiler als ein bestimmter cmd)
|
|
http_code(){ curl -s -o /dev/null -w '%{http_code}' --max-time 5 "http://$1/" 2>/dev/null; }
|
|
up(){ [ "$(http_code "$1")" = "200" ]; }
|
|
fw_version(){ curl -s --max-time 6 "http://$1/cgi-bin/dispatcher.cgi?cmd=512" \
|
|
| sed -e 's/<[^>]*>/ /g' | grep -oiE 'Firmware Version[^0-9]*[0-9.]+' | head -1; }
|
|
|
|
wait_up(){ _e=$(( $(date +%s) + $2 )); while [ "$(date +%s)" -lt "$_e" ]; do up "$1" && return 0; sleep 4; done; return 1; }
|
|
wait_down(){ _e=$(( $(date +%s) + $2 )); while [ "$(date +%s)" -lt "$_e" ]; do up "$1" || return 0; sleep 4; done; return 1; }
|
|
|
|
# IP zurücksetzen — cmd + Seite dynamisch aus der Live-UI entdecken (firmware-drift-sicher)
|
|
restore_ip(){
|
|
_host=$1
|
|
_menu=$(curl -s --max-time 8 "http://$_host/cgi-bin/dispatcher.cgi?cmd=2")
|
|
_ipcmd=$(printf '%s' "$_menu" | grep -i 'IP Address' | grep -oE 'cmd=[0-9]+' | head -1 | cut -d= -f2)
|
|
[ -z "$_ipcmd" ] && _ipcmd=517
|
|
_form=$(curl -s --max-time 8 "http://$_host/cgi-bin/dispatcher.cgi?cmd=$_ipcmd")
|
|
_post=$(printf '%s' "$_form" | grep -i 'name="cmd"' | grep -oE 'value="[0-9]+"' | head -1 | grep -oE '[0-9]+')
|
|
[ -z "$_post" ] && _post=518
|
|
log "restore_ip: ip-page=$_ipcmd post-cmd=$_post -> set $SW_PROD"
|
|
curl -s --max-time 10 -X POST "http://$_host/cgi-bin/dispatcher.cgi" \
|
|
--data "mode=0" --data "ip=$SW_PROD" --data "netmask=$PROD_MASK" \
|
|
--data "gateway=$PROD_GW" --data "cmd=$_post" >/dev/null 2>&1
|
|
}
|
|
add_vlans(){ curl -s --max-time 10 -X POST "http://$1/cgi-bin/dispatcher.cgi" \
|
|
--data "vlanlist=$VLANS" --data "vlanAction=0" --data "name=" --data "cmd=1284" >/dev/null 2>&1; }
|
|
save_flash(){ curl -s --max-time 15 "http://$1/cgi-bin/dispatcher.cgi?cmd=4358" >/dev/null 2>&1; }
|
|
|
|
# ---------- PRE-FLIGHT ----------
|
|
log "=== PRE-FLIGHT (mode=$MODE) ==="
|
|
fail=0
|
|
if [ -f "$IMG" ]; then
|
|
h=$(shasum -a 256 "$IMG" 2>/dev/null | awk '{print $1}')
|
|
if [ "$h" = "$IMG_SHA" ]; then log "OK image sha256"; else log "FAIL image sha256: $h"; fail=1; fi
|
|
else log "FAIL image missing: $IMG"; fail=1; fi
|
|
if ifconfig en0 2>/dev/null | grep -q "$ALIAS_IP"; then log "OK recovery-alias $ALIAS_IP on en0";
|
|
else log "FAIL alias $ALIAS_IP missing -> sudo ifconfig en0 alias $ALIAS_IP 255.255.255.0"; fail=1; fi
|
|
if up "$SW_PROD"; then log "OK switch up at $SW_PROD (FW: $(fw_version "$SW_PROD"))";
|
|
else log "FAIL switch not reachable at $SW_PROD"; fail=1; fi
|
|
if [ "$fail" -ne 0 ]; then log "PRE-FLIGHT FAILED -> abort"; exit 2; fi
|
|
log "PRE-FLIGHT OK"
|
|
[ "$MODE" = "preflight" ] && { log "preflight-only -> done (kein Flash)"; exit 0; }
|
|
|
|
# ---------- FLASH ----------
|
|
MARKER="$HOME/bf-switch-flash/.flashed-2.2.1"
|
|
if [ -f "$MARKER" ] && up "$SW_PROD"; then
|
|
log "Marker vorhanden + Switch up @ $SW_PROD -> Flash übersprungen (nur reconfig)"; skip=1
|
|
else skip=0; fi
|
|
if [ "$skip" -eq 0 ]; then
|
|
log "=== FLASH: lade Image hoch ($IMG) ==="
|
|
curl -s --max-time 200 -F "type=0" -F "http_file=@$IMG" -F "cmd=4364" \
|
|
"http://$SW_PROD/cgi-bin/httpupload.cgi" >>"$LOG" 2>&1
|
|
log "Upload abgeschlossen, warte auf Reboot (down)..."
|
|
# Der Reboot selbst ist das verlässliche Flash-Signal (Flash erzwingt Neustart).
|
|
if wait_down "$SW_PROD" 180; then
|
|
log "Switch down (Reboot) — Flash hat gegriffen"
|
|
else
|
|
log "FAIL kein Reboot binnen 180s — Flash vermutlich nicht angenommen (Upload/Format/Auth?)."
|
|
log " Switch unverändert @ $SW_PROD, Netz intakt, KEIN Reset. Abbruch."
|
|
exit 3
|
|
fi
|
|
fi
|
|
|
|
# ---------- WARTEN AUF WIEDERKEHR ----------
|
|
log "=== RECOVERY: warte auf Switch (max 6 min, .1.1 ODER .239) ==="
|
|
target=""; _e=$(( $(date +%s) + 360 ))
|
|
while [ "$(date +%s)" -lt "$_e" ]; do
|
|
if up "$SW_DEFAULT"; then target=$SW_DEFAULT; break; fi
|
|
if up "$SW_PROD"; then target=$SW_PROD; break; fi
|
|
sleep 4
|
|
done
|
|
if [ -z "$target" ]; then
|
|
log "FAIL Switch kam binnen 6min nicht auf $SW_DEFAULT noch $SW_PROD zurück."
|
|
log " -> MANUELLE Recovery nötig (Reset-Knopf 10s, dann erneut)."
|
|
exit 4
|
|
fi
|
|
log "Switch zurück an $target"
|
|
|
|
# ---------- IP WIEDERHERSTELLEN ----------
|
|
if [ "$target" = "$SW_DEFAULT" ]; then
|
|
log "Switch auf Default $SW_DEFAULT -> stelle $SW_PROD wieder her"
|
|
restore_ip "$SW_DEFAULT"
|
|
if wait_up "$SW_PROD" 60; then
|
|
log "OK Switch wieder auf $SW_PROD"
|
|
else
|
|
log "FAIL set-ip griff nicht — FW 2.2.1 erzwingt vermutlich Login (FW1.0 war offen)."
|
|
log " LAN/Internet laufen TROTZDEM (L2-Forwarding). Nur die Mgmt-IP hängt auf $SW_DEFAULT."
|
|
log " MANUELL: Browser http://$SW_DEFAULT Login admin/admin -> Network/IP Address"
|
|
log " -> $SW_PROD Maske $PROD_MASK GW $PROD_GW -> Save to Flash."
|
|
exit 5
|
|
fi
|
|
else
|
|
log "Switch hat $SW_PROD behalten (Firmware bewahrte IP)"
|
|
fi
|
|
|
|
# ---------- RECONFIG (best-effort, unkritisch — online nachholbar) ----------
|
|
log "=== reconfig (best-effort) ==="
|
|
if add_vlans "$SW_PROD"; then log "VLANs $VLANS abgeschickt"; else log "WARN VLAN-Add fehlgeschlagen (online nachholen)"; fi
|
|
if save_flash "$SW_PROD"; then log "save-to-flash abgeschickt"; else log "WARN save fehlgeschlagen (online nachholen!)"; fi
|
|
|
|
# ---------- VERIFY ----------
|
|
if up "$SW_PROD"; then
|
|
touch "$HOME/bf-switch-flash/.flashed-2.2.1"
|
|
log "=== SUCCESS: Switch up @ $SW_PROD (Marker gesetzt) ==="
|
|
exit 0
|
|
else
|
|
log "=== WARN: Switch am Ende nicht bestätigt up ==="
|
|
exit 6
|
|
fi
|