TP45 Schicht B2 Ruecknahme: VLAN30 vollstaendig auf den Stand vor dem Umzug
Zwei Christoph-Direktiven am 2026-09-21, in dieser Reihenfolge: 1. "mach die shellys sofort rueckgaengig" -- HA bindet sie per IP ein. 2. "wir sollten alle vlan30-aenderungen rueckgaengig machen" -- Sperr-Risiko Nuki: ein Fehlgriff haette aussperren koennen. Neu in tp45-leases.py: die Tabellen SHELLY/REVERT und das Kommando `revert` (nur die 26 Shellys) sowie `restore` (alles zurueck auf vor B2, inkl. NSPanelPro-Reservierung und wiederangelegter CCU-Zeile). In gc-configplan.py die Jobs tp45-v30-revert und tp45-v30-restore; _lease_move nimmt jetzt ein tag, damit die :log-Zeilen den Job unterscheidbar machen. Abnahme: Geraete-Read (alle 36 Adressen zurueck, NSPanelPro ohne Reservierung, CCU .232 wieder da) und --refresh-compliance 145/145, 0 Drifts. Zwei Funde, die als Merkregel bleiben: `make-dynamic` gibt es in RouterOS 7.24 nicht (der Rueckweg ist `remove`), und der GC-Plan-Status beweist nichts -- beide Laeufe meldeten Failed, waehrend der Job-:log alle 36 Statements protokollierte. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -618,7 +618,7 @@ def _tp45_leases_module():
|
|||||||
return mod
|
return mod
|
||||||
|
|
||||||
|
|
||||||
def _lease_move(mac, soll):
|
def _lease_move(mac, soll, tag="tp45-v30"):
|
||||||
"""Eine Umzugs-Zeile — EINZEILIG und klammer-vollstaendig (E1015-Lehre, s. _pool_set).
|
"""Eine Umzugs-Zeile — EINZEILIG und klammer-vollstaendig (E1015-Lehre, s. _pool_set).
|
||||||
|
|
||||||
Der Selektor wird GEZAEHLT: ein `find where`, das 0 trifft, sieht wie
|
Der Selektor wird GEZAEHLT: ein `find where`, das 0 trifft, sieht wie
|
||||||
@@ -653,8 +653,8 @@ def _lease_move(mac, soll):
|
|||||||
arg = f'[find where mac-address={mac}]'
|
arg = f'[find where mac-address={mac}]'
|
||||||
return (f':if ([:len [/ip dhcp-server lease {find}]] = 1) do={{ '
|
return (f':if ([:len [/ip dhcp-server lease {find}]] = 1) do={{ '
|
||||||
f'/ip dhcp-server lease set {arg} address={soll}; '
|
f'/ip dhcp-server lease set {arg} address={soll}; '
|
||||||
f':log info ("tp45-v30: {mac} -> {soll}") }} '
|
f':log info ("{tag}: {mac} -> {soll}") }} '
|
||||||
f'else={{ :log info ("tp45-v30: {mac} NICHT EINDEUTIG -- nicht angefasst") }}')
|
f'else={{ :log info ("{tag}: {mac} NICHT EINDEUTIG -- nicht angefasst") }}')
|
||||||
|
|
||||||
|
|
||||||
def job_tp45_v30_leases():
|
def job_tp45_v30_leases():
|
||||||
@@ -723,6 +723,134 @@ def job_tp45_v30_leases():
|
|||||||
return [(["crs326-core"], "\n".join(lines), "TP45-v30-leases")]
|
return [(["crs326-core"], "\n".join(lines), "TP45-v30-leases")]
|
||||||
|
|
||||||
|
|
||||||
|
def job_tp45_v30_revert():
|
||||||
|
"""RUECKNAHME 2026-09-21: die 26 Shelly-Reservierungen zurueck auf ihre ALTEN Adressen.
|
||||||
|
|
||||||
|
Christoph-Direktive, sofort: *„mach die shellys sofort rueckgaengig! das gibt
|
||||||
|
sonst ein riesen durcheinander mit home assistant"*. Grund: HA hat die Shellys
|
||||||
|
mit ihren alten Adressen eingebunden -- ein Umzug zerreisst die Integrationen.
|
||||||
|
|
||||||
|
🔴 **NUR die Shellys** — das war die erste, eng gefasste Ruecknahme. Die
|
||||||
|
uebrigen 10 Umzuege aus `job_tp45_v30_leases` (NukiBridge .11, P750W .13,
|
||||||
|
DTUBI .14, NukiSmartlock .177, SwitchBot .178, Twinkly .179, lichterketten
|
||||||
|
.190/.191, Withings .195/.196) und die beiden Sonderfaelle (CCU-Leiche
|
||||||
|
entfernt, NSPanelPro statisch auf .12) liess er unangetastet.
|
||||||
|
|
||||||
|
⚠️ **Noch am selben Tag ueberholt:** auf die weitergehende Direktive
|
||||||
|
(„wir sollten ALLE vlan30-aenderungen rueckgaengig machen" — Sperr-Risiko
|
||||||
|
Nuki) folgte `job_tp45_v30_restore`, der auch diese 10 plus beide
|
||||||
|
Sonderfaelle zurueckdreht. Dieser Job bleibt als der engere, zuerst
|
||||||
|
gelaufene Schritt bestehen.
|
||||||
|
|
||||||
|
Die Tabelle steht in `tp45-leases.py` als `REVERT` (abgeleitet aus `MOVES`,
|
||||||
|
gefiltert auf die 26 Shelly-MACs) -- NICHT hier, aus demselben Grund wie
|
||||||
|
`MOVES`: eine zweite Kopie laeuft still auseinander.
|
||||||
|
|
||||||
|
⚠️ **Reihenfolge:** erst `python3 nautobot/tp45-leases.py revert --apply`
|
||||||
|
(Soll zurueck), DANN diesen Job. Umgekehrt meldet GC sofort wieder Drift --
|
||||||
|
das Geraet waere richtig und das Soll falsch.
|
||||||
|
|
||||||
|
Abnahme: Geraete-Read `proplist=address,comment where server=dhcp-v30` -- die
|
||||||
|
26 Shellys muessen auf .202-.226/.233 stehen, die uebrigen 13 Eintraege
|
||||||
|
unveraendert. Danach `--refresh-compliance`, erwartet 145/145 und 0 Drifts.
|
||||||
|
"""
|
||||||
|
mod = _tp45_leases_module()
|
||||||
|
lines = [_lease_move(mac, alt, tag="tp45-v30-revert")
|
||||||
|
for mac, (_neu, alt) in sorted(mod.REVERT.items())]
|
||||||
|
|
||||||
|
# Abnahme-Zeile: die alten Baender muessen wieder voll sein, die neuen leer.
|
||||||
|
# Bewusst ein Bereichs-Paar statt aller 26 Adressen -- .202/.233 rahmen den
|
||||||
|
# alten Shelly-Block ein, .151/.176 den neuen.
|
||||||
|
lines.append(
|
||||||
|
':log info ("tp45-v30-revert: .151=" . [:tostr [:len [/ip dhcp-server lease '
|
||||||
|
'find where address=10.40.30.151]]] . " .176=" . [:tostr [:len '
|
||||||
|
'[/ip dhcp-server lease find where address=10.40.30.176]]] . " .202=" . '
|
||||||
|
'[:tostr [:len [/ip dhcp-server lease find where address=10.40.30.202]]] . '
|
||||||
|
' " .233=" . [:tostr [:len [/ip dhcp-server lease '
|
||||||
|
'find where address=10.40.30.233]]])')
|
||||||
|
|
||||||
|
return [(["crs326-core"], "\n".join(lines), "TP45-v30-shelly-revert")]
|
||||||
|
|
||||||
|
|
||||||
|
def job_tp45_v30_restore():
|
||||||
|
"""VOLLRUECKNAHME 2026-09-21: alle VLAN30-Aenderungen aus B2 zuruecknehmen.
|
||||||
|
|
||||||
|
Christoph-Direktive: *„wir sollten alle vlan30-aenderungen rueckgaengig machen.
|
||||||
|
du koenntest mich auf diesem wege aus meiner wohnung aussperren."*
|
||||||
|
|
||||||
|
Was B2 am 2026-09-21 getan hat, und was hier einzeln zurueckgedreht wird:
|
||||||
|
|
||||||
|
1. **36 Reservierungs-Adressen** verschoben -> hier ALLE 36 zurueck auf ihre
|
||||||
|
`MOVES`-Ist-Adresse (idempotent: die 26 Shellys stehen schon dort, ein
|
||||||
|
zweites `set` auf dieselbe Adresse ist ein No-Op).
|
||||||
|
2. **CCU-Leiche entfernt** (`BC:24:11:8E:0A:57`, .30.232) -> wieder angelegt,
|
||||||
|
wortgleich der Stand vor B2. Ob die Leiche spaeter geloescht werden soll,
|
||||||
|
ist eine **eigene** Entscheidung, nicht Teil dieser Ruecknahme.
|
||||||
|
3. **SONOFF-NSPanelPro auf statisch .12 gepinnt** -> Reservierung entfernt;
|
||||||
|
vor B2 hatte es keine (reiner DHCP-Client auf .249). `remove` ist der
|
||||||
|
Weg, weil RouterOS 7.24 kein `make-dynamic` kennt (s. u.).
|
||||||
|
|
||||||
|
⚠️ **Reihenfolge:** erst `python3 nautobot/tp45-leases.py restore --apply`
|
||||||
|
(Soll zurueck), DANN diesen Job.
|
||||||
|
|
||||||
|
🔴 **Warum die Eile berechtigt war:** die Reservierung eines Geraets mit
|
||||||
|
**lokaler** IP zu aendern, bewegt das Geraet nicht — aber bei einem Geraet,
|
||||||
|
das **DHCP** nutzt, haette die naechste Erneuerung es auf die neue Adresse
|
||||||
|
gezogen, und IP-gebundene Einbindungen (Home Assistant: Nuki, Shelly, …)
|
||||||
|
waeren gerissen. Dass hier nichts passiert ist, war Glueck, kein Entwurf.
|
||||||
|
|
||||||
|
Abnahme: Geraete-Read der v30-Leases + ARP-Band-Zaehlung; danach
|
||||||
|
`--refresh-compliance`, erwartet 145/145 und 0 Drifts.
|
||||||
|
"""
|
||||||
|
mod = _tp45_leases_module()
|
||||||
|
lines = [_lease_move(mac, ist, tag="tp45-v30-restore")
|
||||||
|
for mac, (ist, _soll) in sorted(mod.MOVES.items())]
|
||||||
|
|
||||||
|
# NSPanelPro: die statische Reservierung ENTFERNEN -- vor B2 hatte es keine,
|
||||||
|
# es war ein reiner DHCP-Client (dynamische Lease auf .249).
|
||||||
|
#
|
||||||
|
# 🔴 `make-dynamic` gibt es in RouterOS 7.24 NICHT: `/ip dhcp-server lease
|
||||||
|
# make-dynamic` antwortet `bad command name make-dynamic` (live gemessen
|
||||||
|
# 2026-09-21). Der erste Versuch dieses Jobs ist daran gestorben und hat den
|
||||||
|
# Plan auf `Failed` gesetzt, OBWOHL alle uebrigen Statements gelandet sind —
|
||||||
|
# genau die Klasse „Completed/Failed beweist nichts, das Geraet ist die
|
||||||
|
# Wahrheit". `make-static` existiert (B2 hat es benutzt), das Gegenstueck
|
||||||
|
# fehlt; der Rueckweg ist `remove`.
|
||||||
|
#
|
||||||
|
# ⚠️ Das Panel haelt .12 noch bis zum Lease-Ablauf (~20 h, `status=bound`,
|
||||||
|
# `active-address=10.40.30.12`) und faellt danach in den Pool zurueck.
|
||||||
|
# Das ist eine von B2 erzeugte Uebergangserscheinung, keine neue Aenderung.
|
||||||
|
for add in mod.ADDS:
|
||||||
|
mac = re.search(r"mac-address=(\S+)", add).group(1)
|
||||||
|
find = f'find where mac-address={mac}'
|
||||||
|
arg = f'[find where mac-address={mac}]'
|
||||||
|
lines.append(f':if ([:len [/ip dhcp-server lease {find}]] = 1) do={{ '
|
||||||
|
f'/ip dhcp-server lease remove {arg}; '
|
||||||
|
f':log info ("tp45-v30-restore: NSPanelPro-Reservierung entfernt") }} '
|
||||||
|
f'else={{ :log info ("tp45-v30-restore: NSPanelPro hat keine Reservierung") }}')
|
||||||
|
|
||||||
|
# CCU-Leiche wieder anlegen -- nur wenn sie fehlt.
|
||||||
|
for mac in sorted(mod.REMOVE):
|
||||||
|
find = f'find where mac-address={mac}'
|
||||||
|
lines.append(f':if ([:len [/ip dhcp-server lease {find}]] = 0) do={{ '
|
||||||
|
f'/ip dhcp-server lease {mod.RESTORE_ADD}; '
|
||||||
|
f':log info ("tp45-v30-restore: CCU-Leiche wieder angelegt") }} '
|
||||||
|
f'else={{ :log info ("tp45-v30-restore: CCU-Leiche ist schon da") }}')
|
||||||
|
|
||||||
|
# Abnahme: die alten Baender muessen voll sein, die neuen leer.
|
||||||
|
lines.append(
|
||||||
|
':log info ("tp45-v30-restore: alt .202=" . [:tostr [:len [/ip dhcp-server lease '
|
||||||
|
'find where address=10.40.30.202]]] . " .233=" . [:tostr [:len '
|
||||||
|
'[/ip dhcp-server lease find where address=10.40.30.233]]] . " .244=" . '
|
||||||
|
'[:tostr [:len [/ip dhcp-server lease find where address=10.40.30.244]]] . '
|
||||||
|
' " neu .11=" . [:tostr [:len [/ip dhcp-server lease '
|
||||||
|
'find where address=10.40.30.11]]] . " .151=" . [:tostr [:len '
|
||||||
|
'[/ip dhcp-server lease find where address=10.40.30.151]]] . " .177=" . '
|
||||||
|
'[:tostr [:len [/ip dhcp-server lease find where address=10.40.30.177]]])')
|
||||||
|
|
||||||
|
return [(["crs326-core"], "\n".join(lines), "TP45-v30-restore")]
|
||||||
|
|
||||||
|
|
||||||
JOBS = {
|
JOBS = {
|
||||||
"drift-cleanup": job_drift_cleanup,
|
"drift-cleanup": job_drift_cleanup,
|
||||||
"mgmt-acl": job_mgmt_acl,
|
"mgmt-acl": job_mgmt_acl,
|
||||||
@@ -732,6 +860,8 @@ JOBS = {
|
|||||||
"tp45-agh-dhcp": job_tp45_agh_dhcp,
|
"tp45-agh-dhcp": job_tp45_agh_dhcp,
|
||||||
"tp45-pool-v20": job_tp45_pool_v20,
|
"tp45-pool-v20": job_tp45_pool_v20,
|
||||||
"tp45-v30-leases": job_tp45_v30_leases,
|
"tp45-v30-leases": job_tp45_v30_leases,
|
||||||
|
"tp45-v30-revert": job_tp45_v30_revert,
|
||||||
|
"tp45-v30-restore": job_tp45_v30_restore,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,10 @@ Drift mehr (genau der Grund, warum `ingest-core-firewall.py` manuell bleibt).
|
|||||||
python3 nautobot/tp45-leases.py seed --force --apply # Neuschnitt, ueberschreibt
|
python3 nautobot/tp45-leases.py seed --force --apply # Neuschnitt, ueberschreibt
|
||||||
python3 nautobot/tp45-leases.py move # Dry-Run, s. MOVES
|
python3 nautobot/tp45-leases.py move # Dry-Run, s. MOVES
|
||||||
python3 nautobot/tp45-leases.py move --apply # B2
|
python3 nautobot/tp45-leases.py move --apply # B2
|
||||||
|
python3 nautobot/tp45-leases.py revert # Dry-Run, s. REVERT (nur Shellys)
|
||||||
|
python3 nautobot/tp45-leases.py revert --apply # Ruecknahme 2026-09-21
|
||||||
|
python3 nautobot/tp45-leases.py restore # Dry-Run: ALLES zurueck auf vor B2
|
||||||
|
python3 nautobot/tp45-leases.py restore --apply # Vollruecknahme 2026-09-21
|
||||||
|
|
||||||
Token: docs/nas-vlan20/stacks/210-nautobot.yml (gitignored), NAUTOBOT_SUPERUSER_API_TOKEN.
|
Token: docs/nas-vlan20/stacks/210-nautobot.yml (gitignored), NAUTOBOT_SUPERUSER_API_TOKEN.
|
||||||
Der Wert wird nie ausgegeben.
|
Der Wert wird nie ausgegeben.
|
||||||
@@ -116,12 +120,49 @@ MOVES = {
|
|||||||
# .150 (Ender3V3KE) und .180 (espressif/Airfryer) bleiben, wo sie sind.
|
# .150 (Ender3V3KE) und .180 (espressif/Airfryer) bleiben, wo sie sind.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# RUECKNAHME 2026-09-21 (Christoph-Direktive, sofort): NUR die Shellys.
|
||||||
|
#
|
||||||
|
# Die 26 Shelly-Reservierungen gehen auf ihre ALTEN Adressen zurueck. Grund:
|
||||||
|
# Home Assistant hat sie mit den alten Adressen eingebunden -- der Umzug haette
|
||||||
|
# die HA-Integrationen zerrissen. Die uebrigen 10 Umzuege (NukiBridge, P750W,
|
||||||
|
# DTUBI, NukiSmartlock, SwitchBot, Twinkly, Lichterketten, Withings) BLEIBEN.
|
||||||
|
#
|
||||||
|
# Bewusst als eigene Menge und nicht als Bereichs-Ableitung: welche MAC eine
|
||||||
|
# Shelly ist, steht nur im Kommentar der Soll-Zeile, nicht im MOVES-Key.
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
SHELLY = {
|
||||||
|
"E4:B0:63:D7:C7:A4", "28:37:2F:36:F4:7C", "E4:B0:63:E4:EF:7C",
|
||||||
|
"E4:B0:63:E4:0F:30", "D8:85:AC:0C:5C:C8", "D0:CF:13:D8:18:FC",
|
||||||
|
"D0:CF:13:D9:94:E8", "E4:B0:63:FA:FD:E0", "E8:F6:0A:61:88:08",
|
||||||
|
"E4:B0:63:FC:57:E4", "E4:B0:63:FA:6C:00", "48:F6:EE:C8:E6:AC",
|
||||||
|
"48:F6:EE:DD:6A:F4", "E4:B0:63:FC:59:48", "E4:B0:63:FA:D5:34",
|
||||||
|
"10:20:BA:FA:F5:40", "10:20:BA:FB:6D:64", "48:F6:EE:CC:16:E4",
|
||||||
|
"10:20:BA:FB:70:FC", "98:A3:16:7C:5F:EC", "20:6E:F1:01:F9:F8",
|
||||||
|
"A0:85:E3:C8:65:34", "AC:15:18:7B:62:20", "14:33:5C:D8:2D:7C",
|
||||||
|
"98:A3:16:79:38:50", "98:A3:16:7A:A3:54",
|
||||||
|
}
|
||||||
|
if len(SHELLY) != 26:
|
||||||
|
raise SystemExit("SHELLY hat %d MACs statt 26 -- Tabelle beschaedigt." % len(SHELLY))
|
||||||
|
# Schluessel = MAC, Wert = (aktuelle Soll-Adresse, Adresse davor) -- also die
|
||||||
|
# Umkehrung von MOVES, aber nur fuer den Shelly-Block.
|
||||||
|
REVERT = {mac: (soll, ist) for mac, (ist, soll) in MOVES.items() if mac in SHELLY}
|
||||||
|
if len(REVERT) != 26:
|
||||||
|
raise SystemExit("REVERT hat %d Eintraege statt 26 -- MOVES/SHELLY passen nicht zusammen."
|
||||||
|
% len(REVERT))
|
||||||
|
|
||||||
# CCU-Leiche: VLAN30-Reservierung `pve-homematic-raspi-ccu`, status=waiting,
|
# CCU-Leiche: VLAN30-Reservierung `pve-homematic-raspi-ccu`, status=waiting,
|
||||||
# last-seen=never. Die CCU ist live in VLAN20 (10.40.20.232, ARP+HTTP belegt,
|
# last-seen=never. Die CCU ist live in VLAN20 (10.40.20.232, ARP+HTTP belegt,
|
||||||
# Caddys ccu.bf proxyt dorthin) — dieser Eintrag ist ein Zombie aus dem
|
# Caddys ccu.bf proxyt dorthin) — dieser Eintrag ist ein Zombie aus dem
|
||||||
# Core-Cutover. Er wird ENTFERNT, nicht umgezogen.
|
# Core-Cutover. Er wird ENTFERNT, nicht umgezogen.
|
||||||
REMOVE = {"BC:24:11:8E:0A:57"}
|
REMOVE = {"BC:24:11:8E:0A:57"}
|
||||||
|
|
||||||
|
# Die Zeile, mit der B2 die CCU-Leiche entfernt hat -- wortgleich der Zustand
|
||||||
|
# VOR B2, Quelle `routeros/tp21-core-dhcp-from-ap1.rsc` Z. 70 (dort ohne
|
||||||
|
# `disabled`). Fuer den vollstaendigen Rueckweg wird sie wieder angelegt.
|
||||||
|
RESTORE_ADD = ("add address=10.40.30.232 comment=pve-homematic-raspi-ccu "
|
||||||
|
"mac-address=BC:24:11:8E:0A:57 server=dhcp-v30")
|
||||||
|
|
||||||
# SONOFF-NSPanelPro hat KEINE Reservierung, nur eine dynamische Lease auf .249.
|
# SONOFF-NSPanelPro hat KEINE Reservierung, nur eine dynamische Lease auf .249.
|
||||||
# Wird in B2 per make-static + set address gepinnt. Zeile hier nur als Soll.
|
# Wird in B2 per make-static + set address gepinnt. Zeile hier nur als Soll.
|
||||||
ADDS = [
|
ADDS = [
|
||||||
@@ -207,7 +248,7 @@ def show(old, new):
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
argv = sys.argv[1:]
|
argv = sys.argv[1:]
|
||||||
if not argv or argv[0] not in ("seed", "move", "check"):
|
if not argv or argv[0] not in ("seed", "move", "revert", "restore", "check"):
|
||||||
raise SystemExit(__doc__.strip().splitlines()[-2].strip())
|
raise SystemExit(__doc__.strip().splitlines()[-2].strip())
|
||||||
cmd, apply_ = argv[0], "--apply" in argv
|
cmd, apply_ = argv[0], "--apply" in argv
|
||||||
dev = device()
|
dev = device()
|
||||||
@@ -232,6 +273,57 @@ def main():
|
|||||||
new, when = backup_lines()
|
new, when = backup_lines()
|
||||||
print("== seed aus Backup %s (%d Zeilen)%s =="
|
print("== seed aus Backup %s (%d Zeilen)%s =="
|
||||||
% (when, len(new), " [--force, ueberschreibt %d Zeilen]" % len(soll) if soll else ""))
|
% (when, len(new), " [--force, ueberschreibt %d Zeilen]" % len(soll) if soll else ""))
|
||||||
|
elif cmd == "restore":
|
||||||
|
if not soll:
|
||||||
|
raise SystemExit("Soll ist leer — nichts wiederherzustellen.")
|
||||||
|
drop = {mac_of(a) for a in ADDS}
|
||||||
|
new, seen, moved, dropped = [], set(), [], []
|
||||||
|
for line in soll:
|
||||||
|
mac = mac_of(line)
|
||||||
|
if mac in drop:
|
||||||
|
dropped.append(mac)
|
||||||
|
continue
|
||||||
|
if mac in MOVES:
|
||||||
|
ist_ip, soll_ip = MOVES[mac]
|
||||||
|
cur = re.search(r"address=(\S+)", line).group(1)
|
||||||
|
if cur != ist_ip:
|
||||||
|
if cur != soll_ip:
|
||||||
|
raise SystemExit("%s: Soll traegt weder %s noch %s — Soll, MOVES und "
|
||||||
|
"Wirklichkeit auseinander. Zeile: %s"
|
||||||
|
% (mac, ist_ip, soll_ip, line[:120]))
|
||||||
|
line = set_address(line, ist_ip)
|
||||||
|
moved.append(mac)
|
||||||
|
seen.add(mac)
|
||||||
|
new.append(line)
|
||||||
|
fehlend = set(MOVES) - seen
|
||||||
|
if fehlend:
|
||||||
|
raise SystemExit("MOVES nennt MACs, die im Soll fehlen: %s"
|
||||||
|
% ", ".join(sorted(fehlend)))
|
||||||
|
for mac in sorted(REMOVE):
|
||||||
|
if mac not in seen:
|
||||||
|
new.append(RESTORE_ADD)
|
||||||
|
moved.append(mac)
|
||||||
|
print("== restore: %d Adressen zurueck, %d Zeilen entfernt, %d wieder angelegt "
|
||||||
|
"(Soll jetzt %d Zeilen) ==" % (len(moved), len(dropped), len(REMOVE), len(new)))
|
||||||
|
elif cmd == "revert":
|
||||||
|
if not soll:
|
||||||
|
raise SystemExit("Soll ist leer — es gibt nichts zurueckzunehmen.")
|
||||||
|
new, seen = [], set()
|
||||||
|
for line in soll:
|
||||||
|
mac = mac_of(line)
|
||||||
|
if mac in REVERT:
|
||||||
|
neu_ip, alt_ip = REVERT[mac]
|
||||||
|
if re.search(r"address=(\S+)", line).group(1) != neu_ip:
|
||||||
|
raise SystemExit("%s: Soll traegt nicht %s — Soll und REVERT auseinander. "
|
||||||
|
"Zeile: %s" % (mac, neu_ip, line[:120]))
|
||||||
|
line = set_address(line, alt_ip)
|
||||||
|
seen.add(mac)
|
||||||
|
new.append(line)
|
||||||
|
if seen != set(REVERT):
|
||||||
|
raise SystemExit("REVERT nennt MACs, die im Soll fehlen: %s"
|
||||||
|
% ", ".join(sorted(set(REVERT) - seen)))
|
||||||
|
print("== revert: %d Shelly-Reservierungen zurueck auf die alten Adressen =="
|
||||||
|
% len(REVERT))
|
||||||
else:
|
else:
|
||||||
if not soll:
|
if not soll:
|
||||||
raise SystemExit("Soll ist leer — erst `seed` laufen lassen (Schicht B1).")
|
raise SystemExit("Soll ist leer — erst `seed` laufen lassen (Schicht B1).")
|
||||||
|
|||||||
Reference in New Issue
Block a user