#!/usr/bin/env python3 """Konvertiert ap1-leases-export.json in RouterOS-Befehle für crs326-core. Nur dynamic=false-Leases werden übernommen, mit server-Namen 1:1 übernommen (dhcp-v10..dhcp-v99), disabled=yes, damit sie im Cutover zusammen mit den DHCP-Servern enabled werden. Ausgabe: routeros/ap1-leases-to-core.rsc """ import json import pathlib import shlex LEASES = pathlib.Path(__file__).with_name("ap1-leases-export.json") OUT = pathlib.Path(__file__).with_name("ap1-leases-to-core.rsc") def escape(s): # RouterOS comment darf Leerzeichen enthalten; wir quotieren mit doppelten Anführungszeichen return s.replace('\\', '\\\\').replace('"', '\\"') def main(): leases = json.loads(LEASES.read_text()) static = [l for l in leases if str(l.get("dynamic")).lower() == "false"] lines = [ "# ap1 static leases -> crs326-core (STAGED, disabled=yes)", f"# Quelle: {LEASES.name} | {len(static)} statische Leases", "", ] for l in sorted(static, key=lambda x: (x.get("server", ""), x.get("address", ""))): server = l.get("server", "") if not server.startswith("dhcp-v"): lines.append(f"# SKIP unbekannter server '{server}': {l.get('address')} {l.get('mac-address')}") continue mac = l.get("mac-address", "") addr = l.get("address", "") client_id = l.get("client-id", "") hostname = l.get("host-name", "") dhcp_option = l.get("dhcp-option", "") comment_parts = [hostname, l.get("comment", "")] comment = " / ".join(p for p in comment_parts if p).strip() if not comment: comment = f"lease {addr}" cmd = f'/ip/dhcp-server/lease add server={server} mac-address="{mac}" address="{addr}"' if client_id: cmd += f' client-id="{client_id}"' if dhcp_option: cmd += f' dhcp-option={shlex.quote(dhcp_option)}' cmd += f' comment="{escape(comment)}" disabled=yes' lines.append(cmd) lines.append("") lines.append("# Cutover: /ip/dhcp-server/lease/enable [find comment~\"ap1 lease\"]") OUT.write_text("\n".join(lines) + "\n") print(f"{OUT} written with {len(static)} static lease commands") if __name__ == "__main__": main()