feat(rack): draw shelf-mounted tower heights in the elevation
Add an optional `chassis_u` field for shelf-mounted devices (their height in U where they stand on the shelf) and render it: - gen_rack draws each tower chassis_u U's tall, rising above the 1U shelf line; rail-mounted devices now paint on top so a PDU within a tower's span (e.g. pdu03 over srv05/06) stays visible - occupancy table shows each tower's real U-span (e.g. srv01 U37-U46) - validate_item checks chassis_u is a positive integer; absent chassis_u renders byte-identically to before - set chassis_u for srv01-07 (10/8/6/6/7/7/6U); document the field in the editing guide; regenerate rack01 artifacts Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4dc975062a
commit
4153c8d1d9
14 changed files with 228 additions and 148 deletions
|
|
@ -118,12 +118,18 @@ Only files that declare a `rack:` appear in a rack elevation. The rack is 48U.
|
|||
mounted_on: shf01 # an existing kind:shelf in the same rack
|
||||
shelf_face: front # front | rear
|
||||
shelf_slot: 2 # integer ≥1
|
||||
chassis_u: 6 # optional: device height in U (how tall it stands)
|
||||
# no rack_u / u_height / rack_face
|
||||
```
|
||||
|
||||
The shelf itself must be placed (have `rack_u` + `u_height`). Two devices
|
||||
can't share the same `(shelf, face, slot)`.
|
||||
|
||||
`chassis_u` is optional. Shelves are typically 1U trays; a device sitting on
|
||||
one (e.g. a tower PC) stands `chassis_u` U's tall, rising above the shelf
|
||||
line in the elevation without consuming those rack U's (so rail-mounted gear
|
||||
may still occupy them). Omit it and the device just fills the shelf block.
|
||||
|
||||
### Power feeds
|
||||
|
||||
A device draws power by listing feeds. Each feed must point at a real `kind:pdu`
|
||||
|
|
|
|||
|
|
@ -13,5 +13,5 @@ cluster: tappaas
|
|||
|
||||
- 1U full-depth tray at U46. Tower PCs stand on it and rise above U46; they are
|
||||
not rail-mounted, so the U's above are not consumed in the rack model.
|
||||
- Front: srv01 (stands ~U37–U46), srv02 (~U39–U46).
|
||||
- Rear: srv03 (~U40–U46).
|
||||
- Front: srv01 (10U, U37–U46), srv02 (8U, U39–U46).
|
||||
- Rear: srv03 (6U, U41–U46).
|
||||
|
|
|
|||
|
|
@ -13,5 +13,5 @@ rack_face: both
|
|||
- 1U full-depth tray at U35. Tower PCs stand on it and rise above U35; they are
|
||||
not rail-mounted, so the U's above are not consumed in the rack model
|
||||
(e.g. pdu03 sits at U34, just above this shelf).
|
||||
- Front: srv07 (stands ~U29–U35), srv04 (~U27–U35).
|
||||
- Rear: srv05 (~U27–U35), srv06 (~U27–U35).
|
||||
- Front: srv07 (6U, U30–U35), srv04 (6U, U30–U35).
|
||||
- Rear: srv05 (7U, U29–U35), srv06 (7U, U29–U35).
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ rack: rack01
|
|||
mounted_on: shf01
|
||||
shelf_face: front
|
||||
shelf_slot: 1
|
||||
chassis_u: 10
|
||||
power:
|
||||
- { pdu: pdu01, outlet: 1 }
|
||||
links:
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ rack: rack01
|
|||
mounted_on: shf01
|
||||
shelf_face: front
|
||||
shelf_slot: 2
|
||||
chassis_u: 8
|
||||
power:
|
||||
- { pdu: pdu01, outlet: 2 }
|
||||
links:
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ rack: rack01
|
|||
mounted_on: shf01
|
||||
shelf_face: rear
|
||||
shelf_slot: 1
|
||||
chassis_u: 6
|
||||
power:
|
||||
- { pdu: pdu01, outlet: 3 }
|
||||
links:
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ rack: rack01
|
|||
mounted_on: shf02
|
||||
shelf_face: front
|
||||
shelf_slot: 2
|
||||
chassis_u: 6
|
||||
power:
|
||||
- { pdu: pdu01, outlet: 4 }
|
||||
links:
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ rack: rack01
|
|||
mounted_on: shf02
|
||||
shelf_face: rear
|
||||
shelf_slot: 1
|
||||
chassis_u: 7
|
||||
power:
|
||||
- { pdu: pdu01, outlet: 5 }
|
||||
links:
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ rack: rack01
|
|||
mounted_on: shf02
|
||||
shelf_face: rear
|
||||
shelf_slot: 2
|
||||
chassis_u: 7
|
||||
power:
|
||||
- { pdu: pdu01, outlet: 1 }
|
||||
- { pdu: pdu02, outlet: 1 }
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ rack: rack01
|
|||
mounted_on: shf02
|
||||
shelf_face: front
|
||||
shelf_slot: 1
|
||||
chassis_u: 6
|
||||
power:
|
||||
- { pdu: pdu01, outlet: 1 }
|
||||
- { pdu: pdu02, outlet: 1 }
|
||||
|
|
|
|||
|
|
@ -197,6 +197,65 @@
|
|||
<text x="576" y="994" text-anchor="start" fill="#999">48</text>
|
||||
<rect x="42" y="40" width="240" height="960" fill="none" stroke="#999" stroke-width="1.5"/>
|
||||
<rect x="332" y="40" width="240" height="960" fill="none" stroke="#999" stroke-width="1.5"/>
|
||||
<a href="/hardware/srv01/">
|
||||
<title>srv01 · server · in-use · cluster: tappaas · shf01/front/slot 1</title>
|
||||
<rect x="43" y="761" width="118" height="192" rx="3" fill="#4c78a8" stroke="#333333" stroke-width="1.5"/>
|
||||
<text x="102" y="861" text-anchor="middle" fill="#ffffff">srv01</text>
|
||||
</a>
|
||||
<a href="/hardware/srv02/">
|
||||
<title>srv02 · server · staging · cluster: tappaas · shf01/front/slot 2</title>
|
||||
<rect x="163" y="801" width="118" height="152" rx="3" fill="#4c78a8" stroke="#333333" stroke-width="1.5" stroke-dasharray="4 2"/>
|
||||
<text x="222" y="881" text-anchor="middle" fill="#ffffff">srv02</text>
|
||||
</a>
|
||||
<a href="/hardware/srv03/">
|
||||
<title>srv03 · server · staging · cluster: tappaas · shf01/rear/slot 1</title>
|
||||
<rect x="333" y="841" width="238" height="112" rx="3" fill="#4c78a8" stroke="#333333" stroke-width="1.5" stroke-dasharray="4 2"/>
|
||||
<text x="452" y="901" text-anchor="middle" fill="#ffffff">srv03</text>
|
||||
</a>
|
||||
<a href="/hardware/shf01/">
|
||||
<title>shf01 · shelf · in-use · cluster: tappaas · U46</title>
|
||||
<rect x="42" y="954" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<rect x="332" y="954" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<text x="162" y="959" text-anchor="middle" fill="#333" font-size="9">shf01</text>
|
||||
</a>
|
||||
<a href="/hardware/srv07/">
|
||||
<title>srv07 · server · staging · cluster: tappaas · shf02/front/slot 1</title>
|
||||
<rect x="43" y="621" width="118" height="112" rx="3" fill="#4c78a8" stroke="#333333" stroke-width="1.5" stroke-dasharray="4 2"/>
|
||||
<text x="102" y="681" text-anchor="middle" fill="#ffffff">srv07</text>
|
||||
</a>
|
||||
<a href="/hardware/srv04/">
|
||||
<title>srv04 · server · staging · cluster: — · shf02/front/slot 2</title>
|
||||
<rect x="163" y="621" width="118" height="112" rx="3" fill="#4c78a8" stroke="#333333" stroke-width="1.5" stroke-dasharray="4 2"/>
|
||||
<text x="222" y="681" text-anchor="middle" fill="#ffffff">srv04</text>
|
||||
</a>
|
||||
<a href="/hardware/srv05/">
|
||||
<title>srv05 · server · staging · cluster: — · shf02/rear/slot 1</title>
|
||||
<rect x="333" y="601" width="118" height="132" rx="3" fill="#4c78a8" stroke="#333333" stroke-width="1.5" stroke-dasharray="4 2"/>
|
||||
<text x="392" y="671" text-anchor="middle" fill="#ffffff">srv05</text>
|
||||
</a>
|
||||
<a href="/hardware/srv06/">
|
||||
<title>srv06 · server · staging · cluster: tappaas · shf02/rear/slot 2</title>
|
||||
<rect x="453" y="601" width="118" height="132" rx="3" fill="#4c78a8" stroke="#333333" stroke-width="1.5" stroke-dasharray="4 2"/>
|
||||
<text x="512" y="671" text-anchor="middle" fill="#ffffff">srv06</text>
|
||||
</a>
|
||||
<a href="/hardware/shf02/">
|
||||
<title>shf02 · shelf · in-use · cluster: — · U35</title>
|
||||
<rect x="42" y="734" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<rect x="332" y="734" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<text x="162" y="739" text-anchor="middle" fill="#333" font-size="9">shf02</text>
|
||||
</a>
|
||||
<a href="/hardware/shf03/">
|
||||
<title>shf03 · shelf · in-use · cluster: — · U21</title>
|
||||
<rect x="42" y="454" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<rect x="332" y="454" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<text x="162" y="459" text-anchor="middle" fill="#333" font-size="9">shf03</text>
|
||||
</a>
|
||||
<a href="/hardware/shf04/">
|
||||
<title>shf04 · shelf · in-use · cluster: — · U21</title>
|
||||
<rect x="42" y="454" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<rect x="332" y="454" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<text x="162" y="459" text-anchor="middle" fill="#333" font-size="9">shf04</text>
|
||||
</a>
|
||||
<a href="/hardware/pdu01/">
|
||||
<title>pdu01 · pdu · in-use · cluster: — · U1</title>
|
||||
<rect x="333" y="41" width="238" height="18" rx="3" fill="#e15759" stroke="#333333" stroke-width="1.5"/>
|
||||
|
|
@ -272,65 +331,6 @@
|
|||
<rect x="333" y="701" width="238" height="18" rx="3" fill="#e15759" stroke="#333333" stroke-width="1.5"/>
|
||||
<text x="452" y="714" text-anchor="middle" fill="#ffffff">pdu03 (U34)</text>
|
||||
</a>
|
||||
<a href="/hardware/srv01/">
|
||||
<title>srv01 · server · in-use · cluster: tappaas · shf01/front/slot 1</title>
|
||||
<rect x="43" y="941" width="118" height="12" rx="3" fill="#4c78a8" stroke="#333333" stroke-width="1.5"/>
|
||||
<text x="102" y="951" text-anchor="middle" fill="#ffffff">srv01</text>
|
||||
</a>
|
||||
<a href="/hardware/srv02/">
|
||||
<title>srv02 · server · staging · cluster: tappaas · shf01/front/slot 2</title>
|
||||
<rect x="163" y="941" width="118" height="12" rx="3" fill="#4c78a8" stroke="#333333" stroke-width="1.5" stroke-dasharray="4 2"/>
|
||||
<text x="222" y="951" text-anchor="middle" fill="#ffffff">srv02</text>
|
||||
</a>
|
||||
<a href="/hardware/srv03/">
|
||||
<title>srv03 · server · staging · cluster: tappaas · shf01/rear/slot 1</title>
|
||||
<rect x="333" y="941" width="238" height="12" rx="3" fill="#4c78a8" stroke="#333333" stroke-width="1.5" stroke-dasharray="4 2"/>
|
||||
<text x="452" y="951" text-anchor="middle" fill="#ffffff">srv03</text>
|
||||
</a>
|
||||
<a href="/hardware/shf01/">
|
||||
<title>shf01 · shelf · in-use · cluster: tappaas · U46</title>
|
||||
<rect x="42" y="954" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<rect x="332" y="954" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<text x="162" y="959" text-anchor="middle" fill="#333" font-size="9">shf01</text>
|
||||
</a>
|
||||
<a href="/hardware/srv07/">
|
||||
<title>srv07 · server · staging · cluster: tappaas · shf02/front/slot 1</title>
|
||||
<rect x="43" y="721" width="118" height="12" rx="3" fill="#4c78a8" stroke="#333333" stroke-width="1.5" stroke-dasharray="4 2"/>
|
||||
<text x="102" y="731" text-anchor="middle" fill="#ffffff">srv07</text>
|
||||
</a>
|
||||
<a href="/hardware/srv04/">
|
||||
<title>srv04 · server · staging · cluster: — · shf02/front/slot 2</title>
|
||||
<rect x="163" y="721" width="118" height="12" rx="3" fill="#4c78a8" stroke="#333333" stroke-width="1.5" stroke-dasharray="4 2"/>
|
||||
<text x="222" y="731" text-anchor="middle" fill="#ffffff">srv04</text>
|
||||
</a>
|
||||
<a href="/hardware/srv05/">
|
||||
<title>srv05 · server · staging · cluster: — · shf02/rear/slot 1</title>
|
||||
<rect x="333" y="721" width="118" height="12" rx="3" fill="#4c78a8" stroke="#333333" stroke-width="1.5" stroke-dasharray="4 2"/>
|
||||
<text x="392" y="731" text-anchor="middle" fill="#ffffff">srv05</text>
|
||||
</a>
|
||||
<a href="/hardware/srv06/">
|
||||
<title>srv06 · server · staging · cluster: tappaas · shf02/rear/slot 2</title>
|
||||
<rect x="453" y="721" width="118" height="12" rx="3" fill="#4c78a8" stroke="#333333" stroke-width="1.5" stroke-dasharray="4 2"/>
|
||||
<text x="512" y="731" text-anchor="middle" fill="#ffffff">srv06</text>
|
||||
</a>
|
||||
<a href="/hardware/shf02/">
|
||||
<title>shf02 · shelf · in-use · cluster: — · U35</title>
|
||||
<rect x="42" y="734" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<rect x="332" y="734" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<text x="162" y="739" text-anchor="middle" fill="#333" font-size="9">shf02</text>
|
||||
</a>
|
||||
<a href="/hardware/shf03/">
|
||||
<title>shf03 · shelf · in-use · cluster: — · U21</title>
|
||||
<rect x="42" y="454" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<rect x="332" y="454" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<text x="162" y="459" text-anchor="middle" fill="#333" font-size="9">shf03</text>
|
||||
</a>
|
||||
<a href="/hardware/shf04/">
|
||||
<title>shf04 · shelf · in-use · cluster: — · U21</title>
|
||||
<rect x="42" y="454" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<rect x="332" y="454" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<text x="162" y="459" text-anchor="middle" fill="#333" font-size="9">shf04</text>
|
||||
</a>
|
||||
<text x="42" y="1020" font-weight="bold">Legend</text>
|
||||
<rect x="42" y="1028" width="12" height="12" fill="#9c755f" stroke="#333"/>
|
||||
<text x="58" y="1038">patch-panel</text>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
|
@ -204,6 +204,65 @@ _Auto-generated from `docs/hardware/*.md` (items with `rack: rack01`) — do not
|
|||
<text x="576" y="994" text-anchor="start" fill="#999">48</text>
|
||||
<rect x="42" y="40" width="240" height="960" fill="none" stroke="#999" stroke-width="1.5"/>
|
||||
<rect x="332" y="40" width="240" height="960" fill="none" stroke="#999" stroke-width="1.5"/>
|
||||
<a href="/hardware/srv01/">
|
||||
<title>srv01 · server · in-use · cluster: tappaas · shf01/front/slot 1</title>
|
||||
<rect x="43" y="761" width="118" height="192" rx="3" fill="#4c78a8" stroke="#333333" stroke-width="1.5"/>
|
||||
<text x="102" y="861" text-anchor="middle" fill="#ffffff">srv01</text>
|
||||
</a>
|
||||
<a href="/hardware/srv02/">
|
||||
<title>srv02 · server · staging · cluster: tappaas · shf01/front/slot 2</title>
|
||||
<rect x="163" y="801" width="118" height="152" rx="3" fill="#4c78a8" stroke="#333333" stroke-width="1.5" stroke-dasharray="4 2"/>
|
||||
<text x="222" y="881" text-anchor="middle" fill="#ffffff">srv02</text>
|
||||
</a>
|
||||
<a href="/hardware/srv03/">
|
||||
<title>srv03 · server · staging · cluster: tappaas · shf01/rear/slot 1</title>
|
||||
<rect x="333" y="841" width="238" height="112" rx="3" fill="#4c78a8" stroke="#333333" stroke-width="1.5" stroke-dasharray="4 2"/>
|
||||
<text x="452" y="901" text-anchor="middle" fill="#ffffff">srv03</text>
|
||||
</a>
|
||||
<a href="/hardware/shf01/">
|
||||
<title>shf01 · shelf · in-use · cluster: tappaas · U46</title>
|
||||
<rect x="42" y="954" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<rect x="332" y="954" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<text x="162" y="959" text-anchor="middle" fill="#333" font-size="9">shf01</text>
|
||||
</a>
|
||||
<a href="/hardware/srv07/">
|
||||
<title>srv07 · server · staging · cluster: tappaas · shf02/front/slot 1</title>
|
||||
<rect x="43" y="621" width="118" height="112" rx="3" fill="#4c78a8" stroke="#333333" stroke-width="1.5" stroke-dasharray="4 2"/>
|
||||
<text x="102" y="681" text-anchor="middle" fill="#ffffff">srv07</text>
|
||||
</a>
|
||||
<a href="/hardware/srv04/">
|
||||
<title>srv04 · server · staging · cluster: — · shf02/front/slot 2</title>
|
||||
<rect x="163" y="621" width="118" height="112" rx="3" fill="#4c78a8" stroke="#333333" stroke-width="1.5" stroke-dasharray="4 2"/>
|
||||
<text x="222" y="681" text-anchor="middle" fill="#ffffff">srv04</text>
|
||||
</a>
|
||||
<a href="/hardware/srv05/">
|
||||
<title>srv05 · server · staging · cluster: — · shf02/rear/slot 1</title>
|
||||
<rect x="333" y="601" width="118" height="132" rx="3" fill="#4c78a8" stroke="#333333" stroke-width="1.5" stroke-dasharray="4 2"/>
|
||||
<text x="392" y="671" text-anchor="middle" fill="#ffffff">srv05</text>
|
||||
</a>
|
||||
<a href="/hardware/srv06/">
|
||||
<title>srv06 · server · staging · cluster: tappaas · shf02/rear/slot 2</title>
|
||||
<rect x="453" y="601" width="118" height="132" rx="3" fill="#4c78a8" stroke="#333333" stroke-width="1.5" stroke-dasharray="4 2"/>
|
||||
<text x="512" y="671" text-anchor="middle" fill="#ffffff">srv06</text>
|
||||
</a>
|
||||
<a href="/hardware/shf02/">
|
||||
<title>shf02 · shelf · in-use · cluster: — · U35</title>
|
||||
<rect x="42" y="734" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<rect x="332" y="734" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<text x="162" y="739" text-anchor="middle" fill="#333" font-size="9">shf02</text>
|
||||
</a>
|
||||
<a href="/hardware/shf03/">
|
||||
<title>shf03 · shelf · in-use · cluster: — · U21</title>
|
||||
<rect x="42" y="454" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<rect x="332" y="454" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<text x="162" y="459" text-anchor="middle" fill="#333" font-size="9">shf03</text>
|
||||
</a>
|
||||
<a href="/hardware/shf04/">
|
||||
<title>shf04 · shelf · in-use · cluster: — · U21</title>
|
||||
<rect x="42" y="454" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<rect x="332" y="454" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<text x="162" y="459" text-anchor="middle" fill="#333" font-size="9">shf04</text>
|
||||
</a>
|
||||
<a href="/hardware/pdu01/">
|
||||
<title>pdu01 · pdu · in-use · cluster: — · U1</title>
|
||||
<rect x="333" y="41" width="238" height="18" rx="3" fill="#e15759" stroke="#333333" stroke-width="1.5"/>
|
||||
|
|
@ -279,65 +338,6 @@ _Auto-generated from `docs/hardware/*.md` (items with `rack: rack01`) — do not
|
|||
<rect x="333" y="701" width="238" height="18" rx="3" fill="#e15759" stroke="#333333" stroke-width="1.5"/>
|
||||
<text x="452" y="714" text-anchor="middle" fill="#ffffff">pdu03 (U34)</text>
|
||||
</a>
|
||||
<a href="/hardware/srv01/">
|
||||
<title>srv01 · server · in-use · cluster: tappaas · shf01/front/slot 1</title>
|
||||
<rect x="43" y="941" width="118" height="12" rx="3" fill="#4c78a8" stroke="#333333" stroke-width="1.5"/>
|
||||
<text x="102" y="951" text-anchor="middle" fill="#ffffff">srv01</text>
|
||||
</a>
|
||||
<a href="/hardware/srv02/">
|
||||
<title>srv02 · server · staging · cluster: tappaas · shf01/front/slot 2</title>
|
||||
<rect x="163" y="941" width="118" height="12" rx="3" fill="#4c78a8" stroke="#333333" stroke-width="1.5" stroke-dasharray="4 2"/>
|
||||
<text x="222" y="951" text-anchor="middle" fill="#ffffff">srv02</text>
|
||||
</a>
|
||||
<a href="/hardware/srv03/">
|
||||
<title>srv03 · server · staging · cluster: tappaas · shf01/rear/slot 1</title>
|
||||
<rect x="333" y="941" width="238" height="12" rx="3" fill="#4c78a8" stroke="#333333" stroke-width="1.5" stroke-dasharray="4 2"/>
|
||||
<text x="452" y="951" text-anchor="middle" fill="#ffffff">srv03</text>
|
||||
</a>
|
||||
<a href="/hardware/shf01/">
|
||||
<title>shf01 · shelf · in-use · cluster: tappaas · U46</title>
|
||||
<rect x="42" y="954" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<rect x="332" y="954" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<text x="162" y="959" text-anchor="middle" fill="#333" font-size="9">shf01</text>
|
||||
</a>
|
||||
<a href="/hardware/srv07/">
|
||||
<title>srv07 · server · staging · cluster: tappaas · shf02/front/slot 1</title>
|
||||
<rect x="43" y="721" width="118" height="12" rx="3" fill="#4c78a8" stroke="#333333" stroke-width="1.5" stroke-dasharray="4 2"/>
|
||||
<text x="102" y="731" text-anchor="middle" fill="#ffffff">srv07</text>
|
||||
</a>
|
||||
<a href="/hardware/srv04/">
|
||||
<title>srv04 · server · staging · cluster: — · shf02/front/slot 2</title>
|
||||
<rect x="163" y="721" width="118" height="12" rx="3" fill="#4c78a8" stroke="#333333" stroke-width="1.5" stroke-dasharray="4 2"/>
|
||||
<text x="222" y="731" text-anchor="middle" fill="#ffffff">srv04</text>
|
||||
</a>
|
||||
<a href="/hardware/srv05/">
|
||||
<title>srv05 · server · staging · cluster: — · shf02/rear/slot 1</title>
|
||||
<rect x="333" y="721" width="118" height="12" rx="3" fill="#4c78a8" stroke="#333333" stroke-width="1.5" stroke-dasharray="4 2"/>
|
||||
<text x="392" y="731" text-anchor="middle" fill="#ffffff">srv05</text>
|
||||
</a>
|
||||
<a href="/hardware/srv06/">
|
||||
<title>srv06 · server · staging · cluster: tappaas · shf02/rear/slot 2</title>
|
||||
<rect x="453" y="721" width="118" height="12" rx="3" fill="#4c78a8" stroke="#333333" stroke-width="1.5" stroke-dasharray="4 2"/>
|
||||
<text x="512" y="731" text-anchor="middle" fill="#ffffff">srv06</text>
|
||||
</a>
|
||||
<a href="/hardware/shf02/">
|
||||
<title>shf02 · shelf · in-use · cluster: — · U35</title>
|
||||
<rect x="42" y="734" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<rect x="332" y="734" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<text x="162" y="739" text-anchor="middle" fill="#333" font-size="9">shf02</text>
|
||||
</a>
|
||||
<a href="/hardware/shf03/">
|
||||
<title>shf03 · shelf · in-use · cluster: — · U21</title>
|
||||
<rect x="42" y="454" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<rect x="332" y="454" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<text x="162" y="459" text-anchor="middle" fill="#333" font-size="9">shf03</text>
|
||||
</a>
|
||||
<a href="/hardware/shf04/">
|
||||
<title>shf04 · shelf · in-use · cluster: — · U21</title>
|
||||
<rect x="42" y="454" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<rect x="332" y="454" width="240" height="6" fill="#bab0ac" stroke="#333"/>
|
||||
<text x="162" y="459" text-anchor="middle" fill="#333" font-size="9">shf04</text>
|
||||
</a>
|
||||
<text x="42" y="1020" font-weight="bold">Legend</text>
|
||||
<rect x="42" y="1028" width="12" height="12" fill="#9c755f" stroke="#333"/>
|
||||
<text x="58" y="1038">patch-panel</text>
|
||||
|
|
@ -499,11 +499,11 @@ flowchart LR
|
|||
| U25 | [pp02](../../hardware/pp02.md) | patch-panel | front | in-use |
|
||||
| U34 | [pdu03](../../hardware/pdu03.md) | pdu | rear | in-use |
|
||||
| U35 | [shf02](../../hardware/shf02.md) | shelf | both | in-use |
|
||||
| U35 | [srv07](../../hardware/srv07.md) | server | front · shf02/1 | staging |
|
||||
| U35 | [srv04](../../hardware/srv04.md) | server | front · shf02/2 | staging |
|
||||
| U35 | [srv05](../../hardware/srv05.md) | server | rear · shf02/1 | staging |
|
||||
| U35 | [srv06](../../hardware/srv06.md) | server | rear · shf02/2 | staging |
|
||||
| U30–U35 | [srv07](../../hardware/srv07.md) | server | front · shf02/1 | staging |
|
||||
| U30–U35 | [srv04](../../hardware/srv04.md) | server | front · shf02/2 | staging |
|
||||
| U29–U35 | [srv05](../../hardware/srv05.md) | server | rear · shf02/1 | staging |
|
||||
| U29–U35 | [srv06](../../hardware/srv06.md) | server | rear · shf02/2 | staging |
|
||||
| U46 | [shf01](../../hardware/shf01.md) | shelf | both | in-use |
|
||||
| U46 | [srv01](../../hardware/srv01.md) | server | front · shf01/1 | in-use |
|
||||
| U46 | [srv02](../../hardware/srv02.md) | server | front · shf01/2 | staging |
|
||||
| U46 | [srv03](../../hardware/srv03.md) | server | rear · shf01/1 | staging |
|
||||
| U37–U46 | [srv01](../../hardware/srv01.md) | server | front · shf01/1 | in-use |
|
||||
| U39–U46 | [srv02](../../hardware/srv02.md) | server | front · shf01/2 | staging |
|
||||
| U41–U46 | [srv03](../../hardware/srv03.md) | server | rear · shf01/1 | staging |
|
||||
|
|
|
|||
|
|
@ -105,6 +105,14 @@ def validate_item(fm: dict) -> None:
|
|||
f"{name}: 'shelf_slot' must be a whole number 1 or higher "
|
||||
f"(got {slot!r})."
|
||||
)
|
||||
if "chassis_u" in fm:
|
||||
cu = fm.get("chassis_u")
|
||||
if isinstance(cu, bool) or not isinstance(cu, int) or cu < 1:
|
||||
raise SchemaError(
|
||||
f"{name}: 'chassis_u' is the device's height in U where it "
|
||||
f"stands on the shelf — it must be a whole number 1 or "
|
||||
f"higher (got {cu!r})."
|
||||
)
|
||||
return
|
||||
face = fm.get("rack_face")
|
||||
if face not in FACES:
|
||||
|
|
@ -495,15 +503,6 @@ def render_svg(rack: str, items: list[dict]) -> str:
|
|||
)
|
||||
p.append("</a>")
|
||||
|
||||
for fm in items:
|
||||
if fm.get("kind") == "shelf" or "mounted_on" in fm:
|
||||
continue
|
||||
face = fm.get("rack_face")
|
||||
if face in ("front", "both"):
|
||||
draw_device(fm, front_x)
|
||||
if face in ("rear", "both"):
|
||||
draw_device(fm, rear_x)
|
||||
|
||||
def draw_rail(fm: dict, x: int) -> None:
|
||||
color = KIND_COLORS.get(fm.get("kind", ""), DEFAULT_COLOR)
|
||||
name = fm.get("hostname", "?")
|
||||
|
|
@ -522,11 +521,6 @@ def render_svg(rack: str, items: list[dict]) -> str:
|
|||
)
|
||||
p.append("</a>")
|
||||
|
||||
for idx, fm in enumerate(left_items):
|
||||
draw_rail(fm, PAD + idx * RAIL_W)
|
||||
for idx, fm in enumerate(right_items):
|
||||
draw_rail(fm, right_gutter_x + LABEL_W + idx * RAIL_W)
|
||||
|
||||
SHELF_STRIP_H = 6
|
||||
shelves = [i for i in items if i.get("kind") == "shelf"]
|
||||
mounted = [i for i in items if "mounted_on" in i]
|
||||
|
|
@ -537,7 +531,6 @@ def render_svg(rack: str, items: list[dict]) -> str:
|
|||
y = u_y(u)
|
||||
block_h = h * U_H
|
||||
strip_y = y + block_h - SHELF_STRIP_H
|
||||
avail_h = block_h - SHELF_STRIP_H
|
||||
shelf_color = KIND_COLORS.get("shelf", DEFAULT_COLOR)
|
||||
sname = fm.get("hostname", "?")
|
||||
for col_x, sface in ((front_x, "front"), (rear_x, "rear")):
|
||||
|
|
@ -554,15 +547,22 @@ def render_svg(rack: str, items: list[dict]) -> str:
|
|||
bw = (COL_W - idx * sub_w) if idx == n - 1 else sub_w
|
||||
mcolor = KIND_COLORS.get(m.get("kind", ""), DEFAULT_COLOR)
|
||||
mname = m.get("hostname", "?")
|
||||
# The device stands on the shelf strip and rises chassis_u U's
|
||||
# upward; without chassis_u it fills the shelf block (legacy).
|
||||
dev_u = m.get("chassis_u")
|
||||
if not isinstance(dev_u, int) or isinstance(dev_u, bool) or dev_u < 1:
|
||||
dev_u = h
|
||||
dev_h = dev_u * U_H - SHELF_STRIP_H
|
||||
by = strip_y - dev_h
|
||||
p.append(f'<a href="{_host_url(mname)}">')
|
||||
p.append(f"<title>{_tooltip(m)}</title>")
|
||||
p.append(
|
||||
f'<rect x="{bx + 1}" y="{y + 1}" width="{bw - 2}" '
|
||||
f'height="{avail_h - 2}" rx="3" fill="{mcolor}" '
|
||||
f'<rect x="{bx + 1}" y="{by + 1}" width="{bw - 2}" '
|
||||
f'height="{dev_h - 2}" rx="3" fill="{mcolor}" '
|
||||
f"{_stroke_attrs(m.get('status'))}/>"
|
||||
)
|
||||
p.append(
|
||||
f'<text x="{bx + bw // 2}" y="{y + avail_h // 2 + 4}" '
|
||||
f'<text x="{bx + bw // 2}" y="{by + dev_h // 2 + 4}" '
|
||||
f'text-anchor="middle" fill="#ffffff">{_esc(mname)}</text>'
|
||||
)
|
||||
p.append("</a>")
|
||||
|
|
@ -579,9 +579,26 @@ def render_svg(rack: str, items: list[dict]) -> str:
|
|||
)
|
||||
p.append("</a>")
|
||||
|
||||
# Paint order (bottom → top): shelves and their towers first, then
|
||||
# U-mounted devices (so a rail-mounted PDU stays visible over a tower),
|
||||
# then 0U side rails.
|
||||
for fm in sorted(shelves, key=lambda s: s.get("hostname", "")):
|
||||
draw_shelf(fm)
|
||||
|
||||
for fm in items:
|
||||
if fm.get("kind") == "shelf" or "mounted_on" in fm:
|
||||
continue
|
||||
face = fm.get("rack_face")
|
||||
if face in ("front", "both"):
|
||||
draw_device(fm, front_x)
|
||||
if face in ("rear", "both"):
|
||||
draw_device(fm, rear_x)
|
||||
|
||||
for idx, fm in enumerate(left_items):
|
||||
draw_rail(fm, PAD + idx * RAIL_W)
|
||||
for idx, fm in enumerate(right_items):
|
||||
draw_rail(fm, right_gutter_x + LABEL_W + idx * RAIL_W)
|
||||
|
||||
legend_y = top + body_h + PAD + 8
|
||||
p.append(
|
||||
f'<text x="{front_x}" y="{legend_y}" font-weight="bold">Legend</text>'
|
||||
|
|
@ -773,6 +790,12 @@ def render_page(rack: str, items: list[dict]) -> str:
|
|||
if target and isinstance(target.get("rack_u"), int):
|
||||
su = target["rack_u"]
|
||||
sh = target["u_height"]
|
||||
cu = fm.get("chassis_u")
|
||||
if isinstance(cu, int) and not isinstance(cu, bool) and cu >= 1:
|
||||
base = su + sh - 1 # the shelf's bottom U; towers rise from it
|
||||
top = base - cu + 1
|
||||
urange = f"U{base}" if cu == 1 else f"U{top}–U{base}"
|
||||
else:
|
||||
urange = f"U{su}" if sh == 1 else f"U{su}–U{su + sh - 1}"
|
||||
else:
|
||||
urange = "—"
|
||||
|
|
|
|||
|
|
@ -623,6 +623,50 @@ def test_render_svg_draws_shelf_and_occupants():
|
|||
assert "shf01 (U37" not in svg
|
||||
|
||||
|
||||
def test_validate_accepts_chassis_u():
|
||||
gen_rack.validate_item(item(hostname="srv01", mounted_on="shf01",
|
||||
shelf_face="front", shelf_slot=1, chassis_u=10))
|
||||
|
||||
|
||||
def test_validate_rejects_bad_chassis_u():
|
||||
with pytest.raises(gen_rack.SchemaError):
|
||||
gen_rack.validate_item(item(hostname="srv01", mounted_on="shf01",
|
||||
shelf_face="front", shelf_slot=1, chassis_u=0))
|
||||
|
||||
|
||||
def test_render_svg_tower_height_reflects_chassis_u():
|
||||
items = [
|
||||
shelf(hostname="shf01", rack_u=46, u_height=1),
|
||||
item(hostname="srv01", mounted_on="shf01", shelf_face="front",
|
||||
shelf_slot=1, chassis_u=10),
|
||||
]
|
||||
svg = gen_rack.render_svg("rack01", items)
|
||||
# 10U tower drawn as 10*U_H - SHELF_STRIP_H - 2 px tall
|
||||
assert 'height="192"' in svg
|
||||
|
||||
|
||||
def test_render_svg_paints_rail_device_over_shelf_tower():
|
||||
# A PDU rail-mounted within a tower's span must be painted after the tower
|
||||
# (later in the SVG = on top) so it stays visible.
|
||||
items = [
|
||||
shelf(hostname="shf02", rack_u=35, u_height=1),
|
||||
item(hostname="srv05", mounted_on="shf02", shelf_face="rear",
|
||||
shelf_slot=1, chassis_u=7),
|
||||
item(hostname="pdu03", kind="pdu", rack_u=34, u_height=1,
|
||||
rack_face="rear"),
|
||||
]
|
||||
svg = gen_rack.render_svg("rack01", items)
|
||||
assert svg.index("srv05") < svg.index("pdu03")
|
||||
|
||||
|
||||
def test_render_page_mounted_shows_chassis_span():
|
||||
items = [shelf(hostname="shf01", rack_u=46, u_height=1),
|
||||
item(hostname="srv01", mounted_on="shf01", shelf_face="front",
|
||||
shelf_slot=1, chassis_u=10)]
|
||||
page = gen_rack.render_page("rack01", items)
|
||||
assert "U37–U46" in page
|
||||
|
||||
|
||||
def test_render_svg_shelf_is_deterministic():
|
||||
base = [
|
||||
shelf(),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue