#!/usr/bin/env python3 """ netvm-registry.py — single source of truth for node -> CDP port mapping. Parses NODES.md (the fleet registry). Every script that needs a node's CDP port reads it from here instead of hardcoding — new nodes propagate automatically. Usage: from netvm_registry import port_for, load port_for("muse") # -> 9410 (int), None if unknown CLI: netvm-registry.py # prints "node:port" lines for active nodes netvm-registry.py # prints just the port (for bash) """ import os import re import sys REGISTRY = os.path.join(os.path.dirname(os.path.dirname( os.path.abspath(__file__))), "NODES.md") def load(registry_path=None): """Return {node: {netns, egress_ip, cdp_port, status, agent}}.""" path = registry_path or REGISTRY nodes = {} try: with open(path) as f: for line in f: line = line.rstrip("\n") if not line.startswith("|"): continue cells = [c.strip() for c in line.strip("|").split("|")] if len(cells) < 6: continue node, netns, egress, port, status, agent = cells[:6] if node in ("node", "") or not re.fullmatch(r"[a-z0-9-]+", node): continue if node.startswith("-"): continue try: port_n = int(port) except ValueError: continue nodes[node] = {"netns": netns, "egress_ip": egress, "cdp_port": port_n, "status": status, "agent": agent} except FileNotFoundError: pass return nodes def port_for(node, registry_path=None): """CDP port for a node, or None if the node isn't registered.""" rec = load(registry_path).get(node) return rec["cdp_port"] if rec else None def active_nodes(registry_path=None): """{node: port} for nodes with status == active.""" return {n: r["cdp_port"] for n, r in load(registry_path).items() if r["status"] == "active"} if __name__ == "__main__": if len(sys.argv) == 2: port = port_for(sys.argv[1]) if port is None: print("unknown node: %s" % sys.argv[1], file=sys.stderr) sys.exit(1) print(port) else: for node, port in sorted(active_nodes().items()): print("%s:%d" % (node, port))