From d3d5e9c69e4fbcf0bb992f2b7a88e98c8ed3ee72 Mon Sep 17 00:00:00 2001 From: sjat Date: Wed, 24 Jun 2026 18:43:52 +0200 Subject: [PATCH] feat(rack): colour and link mermaid power/network nodes by kind --- docs/infrastructure/racks/rack01.md | 28 ++++++++++++++++++++++++++++ scripts/gen_rack.py | 19 +++++++++++++++++++ tests/test_gen_rack.py | 25 +++++++++++++++++++++++++ 3 files changed, 72 insertions(+) diff --git a/docs/infrastructure/racks/rack01.md b/docs/infrastructure/racks/rack01.md index 798beac..93a5b09 100644 --- a/docs/infrastructure/racks/rack01.md +++ b/docs/infrastructure/racks/rack01.md @@ -296,6 +296,20 @@ flowchart LR pdu01 -->|outlet 4| srv04 pdu01 -->|outlet 5| srv05 pdu02 -->|outlet 1| srv01 + style pdu01 fill:#e15759,stroke:#333,color:#ffffff + click pdu01 "/hardware/pdu01/" + style pdu02 fill:#e15759,stroke:#333,color:#ffffff + click pdu02 "/hardware/pdu02/" + style srv01 fill:#4c78a8,stroke:#333,color:#ffffff + click srv01 "/hardware/srv01/" + style srv02 fill:#4c78a8,stroke:#333,color:#ffffff + click srv02 "/hardware/srv02/" + style srv03 fill:#4c78a8,stroke:#333,color:#ffffff + click srv03 "/hardware/srv03/" + style srv04 fill:#4c78a8,stroke:#333,color:#ffffff + click srv04 "/hardware/srv04/" + style srv05 fill:#4c78a8,stroke:#333,color:#ffffff + click srv05 "/hardware/srv05/" ``` ## Network @@ -315,6 +329,20 @@ flowchart LR srv03 -->|eth0 → p2 · 1G| pp01 srv04 -->|eth0 → p3 · 1G| pp01 srv05 -->|eth0 → p4 · 1G| pp01 + style pp01 fill:#9c755f,stroke:#333,color:#ffffff + click pp01 "/hardware/pp01/" + style srv01 fill:#4c78a8,stroke:#333,color:#ffffff + click srv01 "/hardware/srv01/" + style srv02 fill:#4c78a8,stroke:#333,color:#ffffff + click srv02 "/hardware/srv02/" + style srv03 fill:#4c78a8,stroke:#333,color:#ffffff + click srv03 "/hardware/srv03/" + style srv04 fill:#4c78a8,stroke:#333,color:#ffffff + click srv04 "/hardware/srv04/" + style srv05 fill:#4c78a8,stroke:#333,color:#ffffff + click srv05 "/hardware/srv05/" + style sw01 fill:#59a14f,stroke:#333,color:#ffffff + click sw01 "/hardware/sw01/" ``` ## Occupancy diff --git a/scripts/gen_rack.py b/scripts/gen_rack.py index d2a9e48..71d26b5 100644 --- a/scripts/gen_rack.py +++ b/scripts/gen_rack.py @@ -600,6 +600,16 @@ def render_power(rack: str, items: list[dict]) -> str: lines.append( f" {_node_id(pdu)} -->|outlet {outlet}| {_node_id(device)}" ) + by_host = {fm.get("hostname"): fm for fm in items} + node_hosts = sorted(set(pdus) | {fm.get("hostname", "?") for fm in powered}) + for host in node_hosts: + kind = by_host.get(host, {}).get("kind", "") + color = KIND_COLORS.get(kind, DEFAULT_COLOR) + nid = _node_id(host) + lines.append( + f" style {nid} fill:{color},stroke:#333,color:#ffffff" + ) + lines.append(f' click {nid} "{_host_url(host)}"') lines.append("```") return "\n".join(lines) + "\n" @@ -646,6 +656,15 @@ def render_network(rack: str, items: list[dict]) -> str: if speed is not None: label += f" · {speed}G" lines.append(f" {_node_id(source)} -->|{label}| {_node_id(peer)}") + for host in sorted(nodes): + kind = by_host.get(host, {}).get("kind", "") + color = KIND_COLORS.get(kind, DEFAULT_COLOR) + nid = _node_id(host) + lines.append( + f" style {nid} fill:{color},stroke:#333,color:#ffffff" + ) + if host in by_host: + lines.append(f' click {nid} "{_host_url(host)}"') lines.append("```") return "\n".join(lines) + "\n" diff --git a/tests/test_gen_rack.py b/tests/test_gen_rack.py index 268ec87..914133b 100644 --- a/tests/test_gen_rack.py +++ b/tests/test_gen_rack.py @@ -700,3 +700,28 @@ def test_svg_u_numbers_in_both_gutters(): def test_svg_has_column_frames(): svg = gen_rack.render_svg("rack01", []) assert svg.count('fill="none"') >= 2 # one frame per column + + +def test_power_graph_colors_and_links_nodes(): + items = [ + item(hostname="pdu01", kind="pdu", rack_face="left", outlets=8), + item(hostname="srv01", rack_u=1, u_height=1, rack_face="front", + power=[{"pdu": "pdu01", "outlet": 1}]), + ] + out = gen_rack.render_power("rack01", items) + assert "style srv01 fill:" in out + assert "style pdu01 fill:" in out + assert 'click srv01 "/hardware/srv01/"' in out + + +def test_network_graph_colors_and_links_nodes(): + items = [ + item(hostname="sw01", kind="switch", rack_u=10, u_height=1, + rack_face="front", ports=24), + item(hostname="srv01", rack_u=1, u_height=1, rack_face="front", + links=[{"local": "eth0", "peer": "sw01", "peer_port": 1}]), + ] + out = gen_rack.render_network("rack01", items) + assert "style sw01 fill:" in out + assert 'click sw01 "/hardware/sw01/"' in out + assert 'click srv01 "/hardware/srv01/"' in out