Initial import from bf-network-r6.opencode — opencode migration

This commit is contained in:
2026-08-26 12:44:21 +02:00
commit 5ee0716dda
297 changed files with 72324 additions and 0 deletions

41
switch/recovery/README.md Normal file
View File

@@ -0,0 +1,41 @@
# Mac-mini Recovery-Anker für den Switch-Flash
**Zweck:** Der Mac mini (10.40.41.167, en0, L2-benachbart zum Switch) trägt dauerhaft eine
**Zweit-IP 192.168.1.2/24**. Nach einem Firmware-Flash kommt der Switch auf `192.168.1.1` hoch
(Werks-Default) — über die Zweit-IP erreicht Claude ihn **vom Mac mini aus** und setzt ihn
automatisch auf `10.40.41.239` zurück. Kein manuelles IP-Suchen, kein Laptop nötig.
## Variante A — nur für heute (transient, kein Reboot dazwischen)
Auf dem Mac mini (deine SSH-Session):
```
sudo ifconfig en0 alias 192.168.1.2 255.255.255.0
ifconfig en0 | grep 192.168.1 # prüfen
```
Entfernen: `sudo ifconfig en0 -alias 192.168.1.2`
## Variante B — persistent (übersteht Reboots, empfohlen wenn Dauer-Anker)
Auf dem Mac mini, aus diesem Repo-Ordner (`switch/recovery/`):
```
sudo cp switch-recovery-ip.sh /usr/local/sbin/switch-recovery-ip.sh
sudo chmod 755 /usr/local/sbin/switch-recovery-ip.sh
sudo cp com.bf.switchrecoveryip.plist /Library/LaunchDaemons/
sudo chown root:wheel /Library/LaunchDaemons/com.bf.switchrecoveryip.plist
sudo launchctl load -w /Library/LaunchDaemons/com.bf.switchrecoveryip.plist
ifconfig en0 | grep 192.168.1 # prüfen
```
Deinstallieren:
```
sudo launchctl unload -w /Library/LaunchDaemons/com.bf.switchrecoveryip.plist
sudo rm /Library/LaunchDaemons/com.bf.switchrecoveryip.plist /usr/local/sbin/switch-recovery-ip.sh
sudo ifconfig en0 -alias 192.168.1.2
```
## Recovery-Ablauf nach Flash (Claude führt aus, vom Mac mini)
```
ssh 10.40.41.167
cd ~/.../bf-network-r6/switch # Repo muss auf dem Mac mini liegen ODER Claude tunnelt
SW_HOST=192.168.1.1 SW_USER=admin SW_PASS=admin ./sg8316m.sh set-ip 10.40.41.239
# Switch nun wieder auf .239 → .secrets zurück, dann VLANs/Ports/save
```
> Hinweis: Claude erreicht den Switch nach Flash **nur** über den Mac mini (.1.1 ist L2-lokal am Mac mini).
> Der Treiber `sg8316m.sh` muss daher vom Mac mini aus laufen (Repo dorthin klonen/kopieren oder via SSH ausführen).

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.bf.switchrecoveryip</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/sbin/switch-recovery-ip.sh</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StandardErrorPath</key>
<string>/var/log/switch-recovery-ip.log</string>
</dict>
</plist>

View File

@@ -0,0 +1,136 @@
#!/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

View File

@@ -0,0 +1,15 @@
#!/bin/sh
# Recovery-Anker: Zweit-IP 192.168.1.2/24 auf en0, damit der Mac mini den
# ALL-SG8316M nach einem Firmware-Flash (Reset auf 192.168.1.1) erreichen kann.
# Wird per LaunchDaemon bei jedem Boot ausgeführt (retry bis en0 da ist).
IFACE=en0
IP=192.168.1.2
MASK=255.255.255.0
i=0
while [ "$i" -lt 10 ]; do
if ifconfig "$IFACE" >/dev/null 2>&1; then
ifconfig "$IFACE" alias "$IP" "$MASK" 2>/dev/null && exit 0
fi
i=$((i+1)); sleep 3
done
exit 1