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 <noreply@anthropic.com>
52 lines
1.9 KiB
Python
52 lines
1.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Holt crs326-core intended config aus Nautobot, setzt WG-Privkey,
|
|
fügt ap1 static leases hinzu, speichert als tp15-core-cutover-intended.rsc.
|
|
"""
|
|
import json
|
|
import pathlib
|
|
import re
|
|
import urllib.request
|
|
|
|
NAUTOBOT_URL = "http://10.40.20.154:8080"
|
|
TOKEN_PATH = pathlib.Path(__file__).parent.parent / "docs" / "nas-vlan20" / "stacks" / "210-nautobot.yml"
|
|
OUT = pathlib.Path(__file__).with_name("tp15-core-cutover-intended.rsc")
|
|
LEASES_RSC = pathlib.Path(__file__).with_name("ap1-leases-to-core.rsc")
|
|
PRIVKEY_PATH = pathlib.Path(__file__).with_name("ap1-wg-hub.privkey")
|
|
|
|
|
|
def get_token():
|
|
text = TOKEN_PATH.read_text()
|
|
m = re.search(r"^NAUTOBOT_SUPERUSER_API_TOKEN=(.+)$", text, re.MULTILINE)
|
|
if not m:
|
|
raise SystemExit("NAUTOBOT_SUPERUSER_API_TOKEN not found")
|
|
return m.group(1).strip()
|
|
|
|
|
|
def main():
|
|
token = get_token()
|
|
req = urllib.request.Request(
|
|
f"{NAUTOBOT_URL}/api/plugins/golden-config/golden-config/?device=crs326-core",
|
|
headers={"Authorization": f"Token {token}", "Accept": "application/json"},
|
|
)
|
|
with urllib.request.urlopen(req) as resp:
|
|
data = json.loads(resp.read().decode())
|
|
config = data["results"][0]["intended_config"]
|
|
|
|
privkey = PRIVKEY_PATH.read_text().strip()
|
|
if "<<< AP1_WG_HUB_PRIVKEY >>>" not in config:
|
|
raise SystemExit("placeholder missing in intended config")
|
|
config = config.replace("<<< AP1_WG_HUB_PRIVKEY >>>", privkey)
|
|
|
|
leases = LEASES_RSC.read_text()
|
|
# Entferne Kommentarblock-Lease-Datei, damit nur Befehle bleiben
|
|
lease_lines = [line for line in leases.splitlines() if line and not line.startswith("#")]
|
|
# Füge Leases vor dem WG-HUB-Block ein? Oder ans Ende. Ans Ende ist einfacher.
|
|
out = config.rstrip() + "\n\n# [9] ap1 static leases -> core (STAGING)" + "\n" + "\n".join(lease_lines) + "\n"
|
|
|
|
OUT.write_text(out)
|
|
print(f"{OUT} written ({len(out)} bytes)")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|