From b52d6aa49e56ab2fa3ee9c638f4ae7e2b639c254 Mon Sep 17 00:00:00 2001 From: Christoph Emsenhuber Date: Mon, 21 Sep 2026 13:14:35 +0200 Subject: [PATCH] TP45 Schicht A: Nautobot .30/.31/.32/.34 -> .154/.155/.156/.158 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Oktett-Klasse .150-.199 (App-Services). Nautobot gibt damit .30/.31 an AGH frei. .157 ist gitea, deshalb nimmt redis .158. - Datenmigration ueber neues nautobot/tp45-ip-move.py: Nautobot verbietet das Aendern einer IP nach dem Anlegen -> anlegen/primary_ip4 umhaengen/ Altobjekt loeschen, in dieser Reihenfolge - Stack-Redeploy (PUT /api/stacks/203), Caddy-Backend, Core-Literal *24 ueber GC deployt (Plan 51a90e25) mit Wirksamkeitspruefung am Geraet - caddy/deploy.sh: push_verified() ersetzt den push||push-Fallback. `pct push` meldet Exit 0 AUCH wenn es die Quelle nicht lesen kann, der Fallback griff deshalb nie und `caddy validate` pruefte die ALTE Datei -> gruene Abnahme bei unveraendertem Zustand (Symptom: 502 bei gesundem Backend) - 39 Referenzen in 28 Dateien mitgezogen; lebende Doku nachgezogen (CLAUDE.md, ip-plan.md, cf-tunnel-mapping §0-Kopf, TP16.3/TP31-Prosa) - GC-Compliance 140/140, 0 Drifts Neue Funde (TP45-Prosa + CLAUDE.md): - Die Core-Adressliste `nautobot` wird von GC nirgends gerendert -> ein Recovery von null erzeugt einen Core, in den Nautobot nicht mehr per SSH kommt. Gleiche Klasse wie die fehlenden DHCP-Reservierungen. - Regel *24 (Literal) und *28 (Liste) sind Dubletten; der Literal steht bei 0 Paketen. Zusammenlegung bleibt offen. - gc-manual-plan.py: /api/extras/job-log-entries/ liefert 404 (Nautobot 3.x) -> bei gescheitertem Deploy fehlt die Fehlermeldung. Co-Authored-By: Claude Sonnet 4.6 --- CLAUDE.md | 21 ++- caddy/Caddyfile | 2 +- caddy/deploy.sh | 27 +++- docs/cf-tunnel-mapping.md | 2 +- docs/ip-plan.md | 2 +- docs/teilprojekte.md | 71 ++++++++-- .../TP45-firewall-nautobot-154.commands.rsc | 15 ++ .../TP45-firewall-nautobot-154.rollback.rsc | 4 + .../TP45-firewall-nautobot-154.snapshot.rsc | 3 + nautobot/gc-configplan.py | 8 +- nautobot/gc-manual-plan.py | 2 +- nautobot/gc-snapshot.py | 2 +- nautobot/gc-transaktion.py | 2 +- nautobot/ingest-2026-07-22-restdaten.py | 2 +- nautobot/ingest-ap-configcontext.py | 2 +- nautobot/ingest-ap-rebuild.py | 2 +- nautobot/ingest-ap3-device.py | 2 +- nautobot/ingest-baseline.py | 2 +- nautobot/ingest-core-firewall.py | 2 +- nautobot/ingest-crs326-core-l3.py | 2 +- nautobot/ingest-crs326-ports.py | 2 +- nautobot/ingest-gc-scrubbing.py | 2 +- nautobot/ingest-logging-rule.py | 2 +- nautobot/ingest-mangle-rule.py | 2 +- nautobot/ingest-queue-rule.py | 2 +- nautobot/ingest-tp22-datamodell.py | 2 +- nautobot/ingest-tp38-oob.py | 2 +- nautobot/ingest-veth-rule.py | 2 +- nautobot/ingest-wifi-access-list-rule.py | 2 +- nautobot/tp37-dienste-seed.py | 2 +- nautobot/tp37-substrat-seed.py | 10 +- nautobot/tp44-cf-estate-seed.py | 2 +- nautobot/tp44-cf-sync.py | 2 +- nautobot/tp44-ipam-prefixes.py | 2 +- nautobot/tp45-ip-move.py | 131 ++++++++++++++++++ routeros/fetch-core-cutover-config.py | 2 +- 36 files changed, 296 insertions(+), 48 deletions(-) create mode 100644 docs/transaktionen/TP45-firewall-nautobot-154.commands.rsc create mode 100644 docs/transaktionen/TP45-firewall-nautobot-154.rollback.rsc create mode 100644 docs/transaktionen/TP45-firewall-nautobot-154.snapshot.rsc create mode 100644 nautobot/tp45-ip-move.py diff --git a/CLAUDE.md b/CLAUDE.md index bb3e5ea..88888b1 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -118,7 +118,7 @@ GW je VLAN = `.1` (crs326-core L3) · Mgmt VLAN99: core `.99.1`, branch `.99.2`, | **🔑 Einheitliches Admin-PW (2026-08-08)** | alle 4 MikroTik (core/branch/ap1/ap2) | user `admin`, gleiches PW (`~/.secrets/credentials.env` → `ROUTER_*_PASS`/`CRS326_*_PASS`; „Überlebensversicherung", User-Vorgabe). Werks-Defaults ap1/ap2 damit obsolet. | | NAS (nas-bf, DS923) | 10.40.20.10 | SSH `adm.christoph@10.40.20.10` (kein PW nötig) · Docker (Portainer endpointId=14) | | platform-pg (LXC 105, pve) | 10.40.20.20 | SSH via pve (`pct exec 105 --`) · **TP20 ✅ 2026-07-16: PG16, DB `nautobot`, Creds `postgres/.secrets`** | -| Nautobot (Portainer-Stack, NAS) | 10.40.20.30 | Portainer ep14, Stack Id 203 · **TP21 ✅ 2026-07-16: `ghcr.io/nautobot/nautobot:3.1.7`, DB=platform-pg, Creds in `docs/nas-vlan20/stacks/210-nautobot.yml` (gitignored)** · **TP22 ✅ 2026-08-13: Golden-Config-App + Device-Adoption DURCH** — alle 4 MikroTik adoptiert, Deploy-Pipeline scharf (Image `3.1.7-gc9`), **68/68 Compliance-Checks grün / 0 Drifts** (2026-08-16) | +| Nautobot (Portainer-Stack, NAS) | **10.40.20.154** (TP45 Schicht A 2026-09-21: `.30/.31/.32/.34` → `.154/.155/.156/.158`) | Portainer ep14, Stack Id 203 · **TP21 ✅ 2026-07-16: `ghcr.io/nautobot/nautobot:3.1.7`, DB=platform-pg, Creds in `docs/nas-vlan20/stacks/210-nautobot.yml` (gitignored)** · **TP22 ✅ 2026-08-13: Golden-Config-App + Device-Adoption DURCH** — alle 4 MikroTik adoptiert, Deploy-Pipeline scharf (Image `3.1.7-gc9`), **68/68 Compliance-Checks grün / 0 Drifts** (2026-08-16) | | ~~Omada-Controller~~ | — | ❌ **entfernt 2026-07-16** (User hat den Container gelöscht — overkill für 1 Switch auf der Abschussliste, s. TP2.1/TP15) | | ~~omada-mcp~~ | — | ❌ **entfernt 2026-07-16** — mit dem Controller gelöscht. ✅ **Aufräumen erledigt/gegenstandslos (geprüft 2026-08-16):** nicht mehr in `mcpServers` registriert (nur noch als „disabled" in ein paar Projekt-Scopes = harmloser Merkposten), und **kein `omada`-Hostname mehr im CF-Ingress** | | pve-mcp | 10.40.20.173 | **StreamableHTTP `http://10.40.20.173:3000/` (Root-Pfad, NICHT /sse)** · NAS-Stack ep14 (=nas-bf `.20.10`, NICHT LXC .126!) id 202 (vlan20-only, TP14.1 2026-07-10) · **mcp-pve v0.6.1 (Upgrade 2026-07-10: Single-Session-Bug 0.4.8 „Server already initialized" gefixt, TP14.2a)** · `~/.claude.json` ✓ | @@ -156,6 +156,25 @@ GW je VLAN = `.1` (crs326-core L3) · Mgmt VLAN99: core `.99.1`, branch `.99.2`, ⚠️ **`POST /api/plugins/golden-config/config-plan/` ist `405` — das ViewSet ist read-only.** ConfigPlans entstehen nur über den Job **`Generate Config Plans`** (`plan_type=manual` + `commands`-TextVar). - **Docker-Management:** Portainer API `https://10.40.20.126:9443`, Key in `mcp/portainer/.env`. +- 🔴 **`pct push` meldet Exit 0, auch wenn es die Quelldatei NICHT lesen kann** (gemessen 2026-09-21). + `pct push 130 /etc/caddy/Caddyfile` → `failed to open … for reading`, **`rc=0`**. + Ein `&&`/`||` hinter dem Push **beweist nichts**, und ein anschließendes `validate`/`reload` prüft + dann die **alte** Datei → **grüne Abnahme bei unverändertem Zustand**. Genau so sah der + Nautobot-Umzug am 2026-09-21 „gelandet" aus, während live noch die alte Backend-IP stand + (Symptom: 502 bei gesundem Backend). **Regel: Push-Werkzeug wird geprüft, nicht geglaubt** — nach + jedem `pct push` den Inhalt vergleichen (`md5sum` diesseits/jenseits in *einem* Remote-Aufruf, + Abbruch bei Abweichung). Muster: `push_verified()` in `caddy/deploy.sh`. Dieselbe Klasse wie + `nc -z` (09-01) und das `grep|sed`-Maskierungsmuster (08-31): **erst das eigene Werkzeug + verdächtigen, dann das Netz.** +- 🔴 **Die Core-Adressliste `nautobot` wird von Golden Config NIRGENDS gerendert** (Fund 2026-09-21). + Der Mgmt-Zugang des Cores für die Deploy-Pipeline läuft über `src-address-list=nautobot` + (Regel `*28`) — die Liste selbst stammt aber aus dem **handgelaufenen** + `routeros/tp5-etappe2-whitelists.rsc` und steht in **keinem** Template (`grep address-list` im + Template findet nur Kommentare). 🔴 **Ein GC-Recovery von null erzeugt damit einen Core, in den + Nautobot nicht mehr per SSH kommt** — die Pipeline wäre tot und könnte sich nicht selbst + reparieren. Gleiche Lücke wie die DHCP-Reservierungen. **Merkregel: was auf dem Gerät existiert, + aber nicht im Template, ist eine Recovery-Lücke, auch wenn Compliance 140/140 grün meldet** — + die Zahl prüft nur, was gerendert wird. Ablösung durch Komodo (native MCP) geplant. --- diff --git a/caddy/Caddyfile b/caddy/Caddyfile index 9552004..de2ef08 100644 --- a/caddy/Caddyfile +++ b/caddy/Caddyfile @@ -47,7 +47,7 @@ gitea.emsenhuber.net { # INTERN (Mesh/LAN; Split-Horizon zeigt diese Namen auf 10.40.20.40) # ========================================================================= nautobot.bf.emsenhuber.net { - reverse_proxy http://10.40.20.30:8080 + reverse_proxy http://10.40.20.154:8080 } # grafana.emsenhuber.net — 2026-08-25 entfernt: LXC 104 war seit Langem gestoppt und stand diff --git a/caddy/deploy.sh b/caddy/deploy.sh index ef251c5..c9fd0a4 100755 --- a/caddy/deploy.sh +++ b/caddy/deploy.sh @@ -19,12 +19,35 @@ if [ -z "${TOKEN}" ]; then exit 1 fi +# 🔴 `pct push` meldet Exit 0 AUCH wenn es die Quelle nicht lesen kann +# ("failed to open for reading", rc=0 — live gemessen 2026-09-21). +# Ein `&&`/`||` hinter dem Push beweist deshalb NICHTS, und die anschliessende +# `caddy validate` validiert dann die ALTE Datei -> gruene Abnahme bei +# unveraendertem Zustand. Genau so ist der Nautobot-Umzug am 2026-09-21 +# scheinbar gelandet, obwohl live noch die alte Backend-IP stand. +# Deshalb: Push + md5-Vergleich in EINEM Remote-Aufruf, der bei Abweichung +# hart abbricht. Gepusht wird nur der lokal bekannte Pfad — die frueheren +# `\$\$`/`$$`-Verrenkungen waren der Ausloeser. +push_verified() { # push_verified