feat(rack): colour and link mermaid power/network nodes by kind

This commit is contained in:
sjat 2026-06-24 18:43:52 +02:00
parent 08862fde51
commit d3d5e9c69e
3 changed files with 72 additions and 0 deletions

View file

@ -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

View file

@ -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"

View file

@ -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