TP25 Fund E wieder geoeffnet + WLAN-Logging persistent (27. ComplianceRule system-logging)
Auslöser war eine unabhaengige Meldung: seit Tagen/Wochen verliert das iPhone den WiFi-Link bei gutem Signal und landet auf Mobilfunk. Auf Mobilfunk zu fallen ist KEIN Roaming-Problem -- bei schlechtem Roaming bliebe das Telefon im WLAN und waere nur langsam. Es heisst, die Assoziation ist gestorben und die Neuanmeldung gescheitert. Der Manager-Log zeigt dasselbe iPhone (F2:62:4C:E1:AF:09) mit 16 Bandwechseln in 20 Minuten zwischen ap3s 5-GHz- und 2,4-GHz-Radio, zweimal im Abstand von einer Sekunde, bei -53..-81 dBm -- kurz darauf dasselbe an ap2. Also nicht ap3-spezifisch. Das stand schon im Repo: TP25 Fund E beschreibt es seit dem 2026-08-20, mit derselben MAC und der Zeile "disconnected, not responding, signal strength -47" -- Abbruch bei ausgezeichnetem Signal. Fund E war zurueckgestellt mit der Auflage "erst wieder aufgreifen, wenn ein Sticky-Fall erneut gemessen ist". Die ist eingetreten. Das ist heute der zweite Fall (nach dem TP25-Kanalplan fuer ap3), in dem eine fertige Analyse im TP-Body stand und ich sie erst nach einer Extrarunde gefunden habe. Der eigentliche Mangel war aber die Beweislage: `wireless` lief NUR nach action=memory, nur `firewall` ging in den Kollektor. Der Ringpuffer fasste 75 Zeilen und war von einer Stunde ap3-Arbeit fast ueberschrieben -- rueckwirkend war nichts diagnostizierbar. Jetzt: zwei Regeln am Core (topics=wireless und topics=caps) in denselben Kollektor wie TP5 (10.40.20.18:514). Gegenprobe auf beiden Seiten -- 32 Zeilen liegen bereits im Tagesfile, inkl. `associated` (debug) und `connected` (info). Und unter Drift-Kontrolle, denn /system logging stand unter KEINER der 26 Rules und gar nicht im Template: neue ComplianceFeature/Rule `system-logging` (Muster: TP6 /queue, TP26 /ip firewall filter), Template-Block [6a2] nur im Core-Zweig -- RouterOS exportiert Defaults nicht, auf ap1/ap2/ap3/branch sind Soll und Ist beide leer. Compliance 130/130 -> 135/135, 0 Drifts. Die Zahl MUSS sich bewegen: eine gleichbleibende Zahl nach dem Hinzufuegen einer Regel waere ein Befund, kein Erfolg. Zwei RouterOS-Fallen, beide als Gotcha in CLAUDE.md: - Der Topic heisst `wireless`, NICHT `wifi` -- auch auf dem neuen wifi-qcom-Stack. Ein geratenes topics=wifi waere wirkungslos geblieben. - RouterOS UND-verknuepft Topics innerhalb EINER Regel (`info,!firewall` = info UND NICHT firewall). `topics=wireless,caps` haette NICHTS gematcht -> zwei Regeln. Recherche-Ergebnis gegen die offizielle MikroTik-Doku, das meine eigene erste Hypothese widerlegt: transition-threshold steht per Default auf -80 dBm (-time 10s, -request-period 30s, -count 3), und unsere Steering-Objekte setzen davon nichts. Bei -53..-74 dBm wird das iPhone gar nicht Transition-Kandidat -- unsolicited BTM scheidet als Treiber weitgehend aus. Die vielzitierte WPA3/802.11r-Inkompatibilitaet steht NICHT in der Doku (dort nur: FT geht nicht ueber OWE); sie bleibt Hypothese. BEWUSST NICHT geaendert: kein einziger Funk-Parameter. Drei Hebel sind dokumentiert und priorisiert -- (1) 2g-probe-delay=yes, kann keinen Client stranden lassen, (2) ft-over-ds=no, nimmt die Aenderung vom 2026-08-17 zurueck, (3) signal-range-Boden, der invasivste und einzige, der Clients aussperren kann. Einzeln, je als Transaktion, erst mit Daten. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
131
nautobot/ingest-logging-rule.py
Normal file
131
nautobot/ingest-logging-rule.py
Normal file
@@ -0,0 +1,131 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
ComplianceRule `system-logging` anlegen (idempotent). TP25 Fund E, 2026-08-30.
|
||||
|
||||
Die Luecke, die das schliesst
|
||||
-----------------------------
|
||||
`wireless`-Logs liefen bis 2026-08-30 NUR nach `action=memory`. Nur `firewall` ging in
|
||||
den Kollektor (`tp5syslog` -> 10.40.20.18:514). Ein wiederkehrendes Client-Problem
|
||||
hinterliess damit KEINE dauerhafte Spur: der Ringpuffer fasste an dem Tag 75 Zeilen und
|
||||
war von einer Stunde ap3-Arbeit fast ueberschrieben. Christophs seit Wochen gemeldeter
|
||||
iPhone-Abbruch war rueckwirkend deshalb nicht diagnostizierbar.
|
||||
|
||||
Am 2026-08-30 sind zwei Regeln dazugekommen (`topics=wireless` und `topics=caps`, beide
|
||||
-> tp5syslog). Ohne ComplianceRule waeren sie ungeschuetzt: sie koennten still
|
||||
verschwinden, und niemandem fiele es auf -- bei einer Beweissicherung, die wochenlang
|
||||
laufen soll, ist das der falsche Zustand. Dieselbe blinde Stelle wie bei `/queue`
|
||||
(TP6) und `/ip firewall filter` (TP26).
|
||||
|
||||
⚠️ RouterOS UND-verknuepft Topics innerhalb EINER Regel (`topics=info,!firewall` heisst
|
||||
"info UND NICHT firewall"). `topics=wireless,caps` haette deshalb NICHTS gematcht --
|
||||
es braucht zwei Regeln. Und der Topic heisst `wireless`, NICHT `wifi`, auch auf dem
|
||||
neuen wifi-qcom-Stack (am Geraet nachgelesen, nicht geraten).
|
||||
|
||||
Warum ein Praefix reicht
|
||||
------------------------
|
||||
`/system logging action add ...` beginnt ebenfalls mit `/system logging`, ein einziges
|
||||
Praefix fasst also Regeln UND Actions. Und weil RouterOS Defaults nicht exportiert,
|
||||
ist der Block auf ap1/ap2/ap3/branch LEER -- Soll und Ist sind dort beide leer, also
|
||||
compliant. Nur der Core traegt Zeilen.
|
||||
|
||||
python3 nautobot/ingest-logging-rule.py # Dry-Run
|
||||
python3 nautobot/ingest-logging-rule.py --apply
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import urllib.error
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
|
||||
BASE = "http://10.40.20.30:8080/api"
|
||||
TOKEN = os.environ.get("NAUTOBOT_TOKEN", "")
|
||||
APPLY = "--apply" in sys.argv
|
||||
|
||||
FEATURE = "system-logging"
|
||||
BESCHREIBUNG = ("TP25 Fund E: /system logging unter Drift-Kontrolle. Die wireless-/caps-Regeln "
|
||||
"in den Kollektor sind Beweissicherung und duerfen nicht still verschwinden.")
|
||||
MATCH = "/system logging"
|
||||
PLATTFORM = "RouterOS"
|
||||
|
||||
|
||||
def req(method, path, data=None):
|
||||
url = path if path.startswith("http") else BASE + path
|
||||
body = json.dumps(data).encode() if data is not None else None
|
||||
r = urllib.request.Request(url, data=body, method=method)
|
||||
r.add_header("Authorization", "Token " + TOKEN)
|
||||
r.add_header("Content-Type", "application/json")
|
||||
r.add_header("Accept", "application/json")
|
||||
try:
|
||||
with urllib.request.urlopen(r, timeout=60) as resp:
|
||||
raw = resp.read()
|
||||
return json.loads(raw) if raw else {}
|
||||
except urllib.error.HTTPError as e:
|
||||
# 🔴 Fehlerkoerper ausgeben: Nautobot begruendet 400er praezise, und ohne den
|
||||
# Text raet man an Feldnamen herum (TP22-Erfahrung).
|
||||
sys.exit("!! %s %s -> %s\n %s" % (method, url, e.code, e.read().decode()[:600]))
|
||||
|
||||
|
||||
def eins(pfad, **filter):
|
||||
q = urllib.parse.urlencode(filter)
|
||||
res = req("GET", "%s?%s" % (pfad, q)).get("results", [])
|
||||
if len(res) > 1:
|
||||
sys.exit("FEHLER: %s?%s liefert %d Treffer, erwartet 0 oder 1" % (pfad, q, len(res)))
|
||||
return res[0] if res else None
|
||||
|
||||
|
||||
def main():
|
||||
if not TOKEN:
|
||||
sys.exit("NAUTOBOT_TOKEN fehlt.")
|
||||
print("Modus:", "APPLY" if APPLY else "DRY-RUN (nichts wird geschrieben)")
|
||||
|
||||
plat = eins("/dcim/platforms/", name=PLATTFORM)
|
||||
if not plat:
|
||||
sys.exit("Plattform %r nicht gefunden." % PLATTFORM)
|
||||
print("Plattform : %s (%s)" % (plat["display"], plat["id"]))
|
||||
|
||||
feat = eins("/plugins/golden-config/compliance-feature/", name=FEATURE)
|
||||
if feat:
|
||||
print("Feature : existiert bereits (%s)" % feat["id"])
|
||||
else:
|
||||
print("Feature : anlegen -> %s" % FEATURE)
|
||||
if APPLY:
|
||||
feat = req("POST", "/plugins/golden-config/compliance-feature/",
|
||||
{"name": FEATURE, "slug": FEATURE, "description": BESCHREIBUNG})
|
||||
print(" angelegt (%s)" % feat["id"])
|
||||
|
||||
if not feat:
|
||||
print("\nDry-Run: ohne Feature kann die Rule nicht geprueft werden. Mit --apply erneut.")
|
||||
return
|
||||
|
||||
rule = eins("/plugins/golden-config/compliance-rule/",
|
||||
feature=feat["id"], platform=plat["id"])
|
||||
if rule:
|
||||
print("Rule : existiert bereits (%s), match_config=%r"
|
||||
% (rule["id"], rule.get("match_config")))
|
||||
if rule.get("match_config") != MATCH:
|
||||
print(" ⚠️ match_config weicht ab -- erwartet %r" % MATCH)
|
||||
return
|
||||
|
||||
nutzlast = {
|
||||
"feature": feat["id"],
|
||||
"platform": plat["id"],
|
||||
"description": BESCHREIBUNG,
|
||||
# Reihenfolge ist hier bedeutungslos: Queue-Trees haengen ueber `parent=`
|
||||
# am Namen, nicht an der Position. Anders als /ip firewall filter.
|
||||
"config_ordered": False,
|
||||
"config_type": "cli",
|
||||
"match_config": MATCH,
|
||||
"custom_compliance": False,
|
||||
"config_remediation": False,
|
||||
}
|
||||
print("Rule : anlegen -> %s auf %s, match_config=%r" % (FEATURE, PLATTFORM, MATCH))
|
||||
if APPLY:
|
||||
r = req("POST", "/plugins/golden-config/compliance-rule/", nutzlast)
|
||||
print(" angelegt (%s)" % r["id"])
|
||||
else:
|
||||
print(" Nutzlast: %s" % json.dumps(nutzlast))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -160,6 +160,27 @@
|
||||
/system ntp client servers add address=at.pool.ntp.org
|
||||
/system ntp server set enabled=yes
|
||||
|
||||
# [6a2] LOGGING — Beweissicherung, kein Betriebsdetail. TP25 Fund E, 2026-08-30.
|
||||
#
|
||||
# Bis dahin liefen `wireless`-Logs NUR nach `action=memory`; nur `firewall` ging in den
|
||||
# Kollektor. Der Ringpuffer fasste 75 Zeilen und war von einer Stunde Arbeit fast
|
||||
# ueberschrieben -- ein seit Wochen gemeldeter iPhone-Abbruch war rueckwirkend deshalb
|
||||
# nicht diagnostizierbar. Die zwei neuen Zeilen sind die Datengrundlage fuer die
|
||||
# Entscheidung ueber die Steering-Hebel (2g-probe-delay / ft-over-ds / signal-range).
|
||||
#
|
||||
# ⚠️ Der Topic heisst `wireless`, NICHT `wifi` -- auch auf dem neuen wifi-qcom-Stack
|
||||
# (am Geraet nachgelesen). Ein geratenes `wifi` waere wirkungslos geblieben.
|
||||
# ⚠️ RouterOS UND-verknuepft Topics innerhalb EINER Regel (`info,!firewall` = info UND
|
||||
# NICHT firewall). `topics=wireless,caps` haette NICHTS gematcht -> zwei Regeln.
|
||||
# 📌 Nur der Core traegt hier Zeilen: RouterOS exportiert Defaults nicht, und unter
|
||||
# CAPsMAN fuehrt ohnehin der MANAGER die Roaming-Events -- die CAPs loggen lokal nichts.
|
||||
# Auf ap1/ap2/ap3/branch sind Soll und Ist beide leer, also compliant.
|
||||
/system logging action add name=tp5syslog remote=10.40.20.18 target=remote
|
||||
/system logging set 0 topics=info,!firewall
|
||||
/system logging add action=tp5syslog topics=firewall
|
||||
/system logging add action=tp5syslog comment="TP25 Fund E: WLAN-Roaming/Disconnects dauerhaft in den Kollektor" topics=wireless
|
||||
/system logging add action=tp5syslog comment="TP25 Fund E: CAP-An-/Abmeldungen dauerhaft in den Kollektor" topics=caps
|
||||
|
||||
# [6b] WLAN — CAPsMAN. Seit TP28 (2026-08-17) ist der Core der Manager und ap1/ap2
|
||||
# sind reine CAPs. Die fuenf wifi-*-ComplianceFeatures gehoeren deshalb HIERHER
|
||||
# und nicht mehr in den AP-Zweig; auf den APs ist die entsprechende Config
|
||||
@@ -247,11 +268,16 @@
|
||||
# --scope wifi-access-list --change-id TEST-... --expires JJJJ-MM-TT
|
||||
#
|
||||
# 🔴 Hier landet TP25 **Fund E** (`signal-range`-Boden gegen klebende Clients),
|
||||
# sobald er entschieden ist. Stand 2026-08-22 ist er es NICHT: der Sticky-Client
|
||||
# vom 08-20 reproduzierte sich beim Rundgang am 08-22 nicht, und in den schwachen
|
||||
# Raeumen gibt es keinen besseren AP, auf den ein Boden steuern koennte. Ein
|
||||
# voreilig gesetzter Boden verschlechtert die Terrasse, statt zu helfen.
|
||||
# Vor dem Eintragen also: Sticky-Fall erneut messen. Siehe teilprojekte.md TP25.
|
||||
# sobald er entschieden ist. Die alte Auflage lautete "vor dem Eintragen den
|
||||
# Sticky-Fall erneut messen" -- das ist am 2026-08-30 passiert: dasselbe iPhone
|
||||
# machte 16 Bandwechsel in 20 Minuten bei -53..-81 dBm, erst an ap3, dann an ap2.
|
||||
# Fund E ist damit WIEDER OFFEN.
|
||||
# Eingetragen wird hier trotzdem NICHTS, und zwar bewusst: ein signal-range-Boden
|
||||
# ist der invasivste der drei Hebel und kann Clients AUSSPERREN -- genau das war
|
||||
# 08-22 das Gegenargument (in den schwachen Raeumen gibt es keinen besseren AP,
|
||||
# auf den ein Boden steuern koennte). Erst kommen (1) `2g-probe-delay=yes` und
|
||||
# (2) `ft-over-ds=no`, jeder einzeln und als Transaktion, mit dem seit 2026-08-30
|
||||
# laufenden wireless-Logging als Messgrundlage. Siehe teilprojekte.md TP25 Fund E.
|
||||
|
||||
# Kanonischer Mgmt-Nummernplan (User-Bestaetigung 2026-08-13, verbindlich):
|
||||
# core .99.1 | branch .99.2 | ap1 .99.11 | ap2 .99.12
|
||||
|
||||
Reference in New Issue
Block a user