Wizard: idempotenter WAN-Apply fuer DHCP-Client/PPPoE (Bug 21)
Wizard erneut auf einem Interface durchlaufen, das schon einen DHCP-Client hat (hier: aus einer zurueckgespielten Sicherung), scheiterte live mit "failure: dhcp-client on that interface already exists" - WanConfig.buildCommands() erzeugt fuer DHCP-Client/PPPoE immer .add, ohne vorher zu pruefen, ob auf dem Interface schon einer existiert. Fix: SetupViewModel.applyIdempotently faengt einen .add-Fehlschlag auf /ip dhcp-client bzw. /interface pppoe-client ab und wiederholt ihn als .set (nach "interface" gematcht) - bewusst nur fuer diese zwei Menues mit "maximal ein Eintrag pro Interface"-Semantik, nicht generell fuer jedes .add (z.B. /ip address erlaubt legitim mehrere Adressen pro Interface). Gefunden beim Versuch, M8 (Netzwerk-Isolation) live durchzutesten - dieser Test selbst ist noch nicht abgeschlossen, naechste Session dort weitermachen (siehe HANDOFF.md Naechste Schritte Punkt 1). HANDOFF.md/CHATLOG.md aktualisiert: Bug 21, Sessionende-Stand. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CTgRxJTzaQwaRkngbaE1GJ
This commit is contained in:
+20
@@ -676,3 +676,23 @@ Test, WLAN/Bonding/PPPoE-Live-Tests).
|
||||
- "ja, committen und beides aktualisieren" → dieser Eintrag, HANDOFF.md
|
||||
(M14, Bug 20, Design-Durchgang, Dark-Mode-Bestätigung) aktualisiert,
|
||||
Commit erstellt.
|
||||
|
||||
## Session: M8-Hardware-Test begonnen (nicht abgeschlossen)
|
||||
|
||||
- "was steht als nächstes auf dem Plan?" → HANDOFF-Liste zusammengefasst.
|
||||
"fangen wir bei 4 an" (M8 Netzwerk-Isolation) → per `AskUserQuestion`
|
||||
geklärt: voller Wizard-Durchlauf statt nur gezieltem Firewall-Test,
|
||||
kombiniert damit Punkt 1 (kompletter Wizard-Durchlauf) mit.
|
||||
- Unterwegs zwei praktische RouterOS-Fragen beantwortet: ether5 aus der
|
||||
Bridge entfernen (`/interface bridge port remove [find
|
||||
interface=ether5]` bzw. Experte-Tab), dann "Unerwartete Antwort vom
|
||||
Router: failure: dhcp-client on that interface already exists" beim
|
||||
WAN-Schritt — Ursache: Wizard nutzt immer `.add`, aber auf dem
|
||||
Interface existierte aus der zurückgespielten Sicherung schon ein
|
||||
DHCP-Client. "fixe es gleich" → Bug 21, `SetupViewModel.
|
||||
applyIdempotently` (Fallback auf `.set` bei `.add`-Fehlschlag auf
|
||||
DHCP-Client/PPPoE), deployt.
|
||||
- "ok, alles speichern, genug für heute" → dieser Eintrag, HANDOFF.md
|
||||
(Bug 21, Nächste-Schritte Punkt 1 als "in Arbeit" markiert — der
|
||||
eigentliche M8-Isolationstest ist noch nicht zu Ende geführt, nächste
|
||||
Session dort fortsetzen) aktualisiert, Commit erstellt. Sitzung beendet.
|
||||
|
||||
+34
-5
@@ -56,6 +56,17 @@ Farbwerte, alles adaptive System-Farben) — vom Nutzer live bestätigt.
|
||||
Release-Build unter `/Applications/RouterOS Assistant.app` ist auf
|
||||
aktuellem Stand.
|
||||
|
||||
**Zum Sessionende:** M8-Hardware-Test (Netzwerk-Isolation) begonnen —
|
||||
voller Wizard-Durchlauf über den Experte-Modus, WAN neu einrichten.
|
||||
Dabei Bug 21 gefunden: der Wizard-Apply nutzte für WAN-DHCP-Client/PPPoE
|
||||
immer `.add`, was auf einem bereits konfigurierten Interface (hier: aus
|
||||
der zurückgespielten Sicherung) mit "failure: dhcp-client on that
|
||||
interface already exists" scheiterte. Fix: `SetupViewModel.
|
||||
applyIdempotently` versucht bei `.add` auf `/ip dhcp-client` oder
|
||||
`/interface pppoe-client` nach einem Fehlschlag automatisch `.set`
|
||||
(nach "interface" gematcht) — deployt, **aber der eigentliche
|
||||
M8-Isolationstest selbst ist noch nicht zu Ende geführt/verifiziert**,
|
||||
das ist der erste Schritt für die nächste Session.
|
||||
## Ziel
|
||||
|
||||
Native macOS-App (SwiftUI), die Laien per geführtem Interview-Wizard durch
|
||||
@@ -378,6 +389,19 @@ erreichen (siehe Bug 1 unten).
|
||||
Singleton-Menü, nicht nur `/system routerboard` — der generische
|
||||
Lese-Pfad wird von Übersicht-, Geräte- und Experte-Tab gemeinsam
|
||||
genutzt.
|
||||
21. **Wizard-WAN-Apply war nicht idempotent** — Wizard erneut auf einem
|
||||
Interface durchlaufen, das schon einen DHCP-Client hat (hier: aus
|
||||
einer zurückgespielten Sicherung), scheiterte live mit "failure:
|
||||
dhcp-client on that interface already exists". `WanConfig.
|
||||
buildCommands()` erzeugt für DHCP-Client/PPPoE immer `.add`, ohne
|
||||
vorher zu prüfen, ob auf dem Interface schon einer existiert. Fix:
|
||||
`SetupViewModel.applyIdempotently` fängt einen `.add`-Fehlschlag auf
|
||||
`/ip dhcp-client`/`/interface pppoe-client` ab und wiederholt ihn als
|
||||
`.set` (nach "interface" gematcht) — bewusst nur für diese zwei
|
||||
Menüs mit "maximal ein Eintrag pro Interface"-Semantik, nicht generell
|
||||
für jedes `.add` (z.B. `/ip address` erlaubt legitim mehrere
|
||||
Adressen pro Interface). **Noch nicht erneut live getestet**, siehe
|
||||
Nächste Schritte.
|
||||
|
||||
**Lehren:** Citadel/NIOSSH-Fehler immer mit `String(describing:)` loggen,
|
||||
nie `.localizedDescription`. Jede View, die ein ObservableObject aus einem
|
||||
@@ -741,11 +765,16 @@ beim Ändern die RouterOS-Suffix-Form zurück) — angewendet auf DHCP-Server
|
||||
|
||||
## Nächste Schritte
|
||||
|
||||
1. Den kompletten Wizard einmal neu durchlaufen (WAN/LAN/VLAN/WLAN/
|
||||
Firewall) auf dem werksresetteten hEX und dabei das Firewall-Ergebnis
|
||||
mit korrektem WAN-Port per `/ip firewall filter print` /
|
||||
`/ip firewall nat print` kontrollieren (bisher nur die Interface-
|
||||
Auswahl nach dem Parser-Fix bestätigt, kein erneuter Apply).
|
||||
1. **In Arbeit, hier weitermachen:** kompletter Wizard-Durchlauf
|
||||
(WAN/LAN mit zwei Interfaces ether2+ether3, eins isoliert/Firewall)
|
||||
über den Experte-Modus — kombiniert M8-Hardware-Test (Netzwerk-
|
||||
Isolation) mit diesem Punkt. Wurde in dieser Session begonnen, brach
|
||||
beim WAN-Schritt mit Bug 21 ab (jetzt gefixt, deployt, aber
|
||||
**ungetestet**). Nach erneutem Durchlauf: Firewall-Ergebnis mit
|
||||
korrektem WAN-Port UND die Isolations-Regeln per
|
||||
`/ip firewall filter print` kontrollieren, plus praktisch testen
|
||||
(iMac ↔ Laptop sollten sich nicht erreichen, Internet für beide
|
||||
schon).
|
||||
2. WLAN (M5) an einem Gerät mit echtem WLAN-Chip nachholen.
|
||||
3. Rest von M7: Fehlerzustände/Politur, REST-Schreibtest an einem Gerät
|
||||
mit aktivem `www-ssl`.
|
||||
|
||||
@@ -213,7 +213,7 @@ final class SetupViewModel: ObservableObject {
|
||||
|
||||
for command in plannedCommands {
|
||||
applyLog.append(command.summary)
|
||||
try await connectionService.apply(command)
|
||||
try await applyIdempotently(command)
|
||||
}
|
||||
|
||||
didApplySuccessfully = true
|
||||
@@ -223,4 +223,36 @@ final class SetupViewModel: ObservableObject {
|
||||
isApplying = false
|
||||
}
|
||||
}
|
||||
|
||||
/// RouterOS allows at most one item per interface on some menus (a DHCP client, a PPPoE
|
||||
/// client) — re-running the wizard's WAN step on an interface that already has one makes the
|
||||
/// wizard's own `.add` fail live-confirmed: "failure: dhcp-client on that interface already
|
||||
/// exists". Rather than hard-fail the whole apply here, retry once as a `.set` matched by
|
||||
/// "interface" instead — reconfigures the existing entry in place, which is what re-running
|
||||
/// the wizard on the same interface should mean anyway. Scoped to exactly these two
|
||||
/// known-unique-per-interface menus, not applied generally to every `.add` — other menus
|
||||
/// (e.g. "/ip address") legitimately allow multiple items per interface, where silently
|
||||
/// converting a would-be-duplicate `.add` into a `.set` would be wrong, not helpful.
|
||||
private static let interfaceUniqueMenuPaths: Set<String> = ["/ip dhcp-client", "/interface pppoe-client"]
|
||||
|
||||
private func applyIdempotently(_ command: RouterOSCommand) async throws {
|
||||
do {
|
||||
try await connectionService.apply(command)
|
||||
} catch {
|
||||
guard case .add = command.operation,
|
||||
Self.interfaceUniqueMenuPaths.contains(command.menuPath),
|
||||
let interfaceName = command.arguments["interface"] else {
|
||||
throw error
|
||||
}
|
||||
let retryCommand = RouterOSCommand.set(
|
||||
menuPath: command.menuPath,
|
||||
restPath: command.restPath,
|
||||
matchField: "interface",
|
||||
matchValue: interfaceName,
|
||||
arguments: command.arguments,
|
||||
summary: command.summary
|
||||
)
|
||||
try await connectionService.apply(retryCommand)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user