from graphviz import Digraph def make_network_diagram(output_name: str = "network-architecture"): g = Digraph( "network", filename=f"{output_name}.gv", format="png", ) # Globale stijl g.attr(rankdir="LR", fontname="Segoe UI") # ---------- WAN / Internet ---------- with g.subgraph(name="cluster_wan") as wan: wan.attr( label="🌐 Internet / Cloud", style="rounded", color="lightgrey", fontsize="16", ) wan.node("extDNS", "📡 Public DNS", shape="rectangle") wan.node("extGit", "☁️ Externe registries / Git\n(GitHub / Docker Hub)", shape="rectangle") # ---------- LAN 192.168.1.0/24 ---------- with g.subgraph(name="cluster_lan") as lan: lan.attr( label="🏠 LAN 192.168.1.0/24", style="rounded", color="lightgrey", fontsize="16", ) # Router / gateway lan.node( "hub", "🛜 Router / Gateway\nhub.lan\n192.168.1.1", shape="rectangle", style="filled", fillcolor="#f0f0ff", ) # ---- Core server / desktop ---- with lan.subgraph(name="cluster_core") as core: core.attr( label="💻 Hoofdserver / Desktop\nTour / hephaestus / ollama / dokku.lan\n192.168.1.159", style="rounded", color="#aaccee", ) core.node("traefik", "🚦 Traefik\nReverse Proxy", shape="rectangle") core.node("gitea", "📚 Gitea\ngit.appmodel.nl", shape="rectangle") core.node("dokku", "🐳 Dokku\nPaaS / build", shape="rectangle") core.node("auctionFE", "🧱 Auction Frontend\nauction.appmodel.nl", shape="rectangle") core.node("aupiAPI", "🧱 Auction Backend API\naupi.appmodel.nl", shape="rectangle") core.node("mi50", "🧠 MI50 / Ollama\nAI workloads", shape="rectangle") # Aanvulling: monitoring / logging core.node("monitoring", "📈 Monitoring / Logging\nPrometheus / Loki / Grafana", shape="rectangle") # ---- Infra & DNS ---- with lan.subgraph(name="cluster_infra_dns") as infra: infra.attr( label="🧭 Infra & DNS\nodroid / dns.lan\n192.168.1.163", style="rounded", color="#aaddaa", ) infra.node("adguard", "🧭 AdGuard Home\nDNS / *.lan / *.appmodel.nl", shape="rectangle") infra.node("artifactory", "📦 Artifactory", shape="rectangle") infra.node("runner", "⚙️ Build runners\nCI/CD", shape="rectangle") # ---- Home Automation ---- with lan.subgraph(name="cluster_ha") as ha: ha.attr( label="🏡 Home Automation\nha.lan\n192.168.1.193", style="rounded", color="#ffddaa", ) ha.node("hass", "🏠 Home Assistant", shape="rectangle") # Overige LAN-hosts / IoT lan.node("atlas", "🧱 atlas.lan\n192.168.1.100", shape="rectangle") lan.node("iot1", "📺 hof-E402NA\n192.168.1.214", shape="rectangle") lan.node("iot2", "🎧 S380HB\n192.168.1.59", shape="rectangle") lan.node("iot3", "📟 ecb5faa56c90\n192.168.1.49", shape="rectangle") lan.node("iot4", "❓ Unknown\n192.168.1.240", shape="rectangle") # ---------- Tether subnet ---------- with g.subgraph(name="cluster_tether") as tether: tether.attr( label="📶 Tether subnet 192.168.137.0/24", style="rounded", color="lightgrey", fontsize="16", ) tether.node("hermes", "🛰️ hermes.lan\n192.168.137.239\nworker / node", shape="rectangle") tether.node("plato", "🛰️ plato.lan\n192.168.137.163\nworker / node", shape="rectangle") # ---------- Externe gebruikers (aanvulling) ---------- g.node( "users", "👨‍💻 Developers / Users\nlaptops / mobiel", shape="rectangle", style="dashed", ) # ==================== VERBINDINGEN ==================== # Basis LAN connecties (ongeveer jouw '---' links) for target in ["core", "infraDNS", "ha", "atlas", "iot1", "iot2", "iot3", "iot4"]: # We linken naar representatieve node binnen subgraph if target == "core": g.edge("hub", "traefik", dir="both", label="LAN") elif target == "infraDNS": g.edge("hub", "adguard", dir="both", label="LAN") elif target == "ha": g.edge("hub", "hass", dir="both", label="LAN") else: g.edge("hub", target, dir="both", label="LAN") # WAN koppeling g.edge("hub", "extDNS", label="📶 Internet") g.edge("adguard", "extDNS", label="Upstream DNS") # DNS-resolutie (core / ha / atlas / tether -> AdGuard) for client in ["traefik", "hass", "atlas", "hermes", "plato"]: g.edge(client, "adguard", label="DNS", style="dashed") # Websites / reverse proxy g.edge("extDNS", "traefik", label="DNS → Traefik") g.edge("traefik", "gitea", label="HTTP(S)") g.edge("traefik", "auctionFE", label="HTTP(S)") g.edge("traefik", "aupiAPI", label="HTTP(S)") g.edge("traefik", "dokku", label="Apps / Deploy") # App flow g.edge("auctionFE", "aupiAPI", label="API calls") g.edge("aupiAPI", "adguard", label="DNS lookups", style="dashed") # AI workloads g.edge("traefik", "mi50", label="AI / inference", style="dotted") # Tether workers g.edge("traefik", "hermes", dir="both", label="Jobs / tasks") g.edge("traefik", "plato", dir="both", label="Jobs / tasks") # Monitoring / logging (aanvulling) for observed in ["traefik", "gitea", "dokku", "auctionFE", "aupiAPI", "mi50", "adguard", "atlas", "hass"]: g.edge(observed, "monitoring", style="dotted", label="metrics / logs") # Developers / gebruikers g.edge("users", "traefik", label="HTTPS") g.edge("users", "gitea", style="dashed", label="Git / HTTP") # Genereer bestanden (PNG + .gv) g.render(cleanup=True) print(f"Diagram gegenereerd als {output_name}.png") if __name__ == "__main__": make_network_diagram()