2026-06-29 21:32:32 +02:00
|
|
|
|
---
|
|
|
|
|
|
title: Editing the hardware docs
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
# Editing the hardware docs
|
|
|
|
|
|
|
|
|
|
|
|
The hardware inventory is **one Markdown file per device** under
|
|
|
|
|
|
`docs/hardware/`. The YAML frontmatter at the top of each file is the single
|
|
|
|
|
|
source of truth. Everything you see rendered — the
|
|
|
|
|
|
[Hardware Overview](../hardware/index.md) table, the per-device **Specs** box,
|
|
|
|
|
|
the [rack elevation](../infrastructure/racks/rack01.md) SVG, and the network
|
|
|
|
|
|
graph — is **generated** from that frontmatter.
|
|
|
|
|
|
|
|
|
|
|
|
!!! warning "The golden rule"
|
|
|
|
|
|
After editing any file in `docs/hardware/`, run **`make docs-index`** and
|
|
|
|
|
|
commit the regenerated files. CI rebuilds the indices and fails the build if
|
|
|
|
|
|
they differ from what you committed. This is the single most common reason a
|
|
|
|
|
|
push goes red.
|
|
|
|
|
|
|
|
|
|
|
|
## Quick start: add a device
|
|
|
|
|
|
|
2026-06-29 21:40:09 +02:00
|
|
|
|
1. Pick a hostname following the [naming scheme](hardware-naming-scheme.md):
|
|
|
|
|
|
`<kind-abbrev><NN>` — a 2-digit number, unique per kind (`srv`, `sw`, `pp`,
|
|
|
|
|
|
`pdu`, `ups`, `shf`, …). Example: `srv06`.
|
2026-06-29 21:32:32 +02:00
|
|
|
|
2. Create `docs/hardware/<hostname>.md`. **The filename stem must equal the
|
|
|
|
|
|
`hostname` field** — `srv06.md` must contain `hostname: srv06`.
|
|
|
|
|
|
3. Fill in the frontmatter (see the reference below). Write any free-text under
|
|
|
|
|
|
`## Notes`.
|
|
|
|
|
|
4. Run `make docs-index` and commit **both** your new file and the regenerated
|
|
|
|
|
|
index / rack files.
|
|
|
|
|
|
|
|
|
|
|
|
```markdown
|
|
|
|
|
|
---
|
|
|
|
|
|
hostname: srv06
|
|
|
|
|
|
kind: server
|
|
|
|
|
|
status: staging
|
|
|
|
|
|
location: The pile
|
|
|
|
|
|
cpu: Intel Core i5-3570K @ 3.40GHz
|
|
|
|
|
|
cpu_cores: 4
|
|
|
|
|
|
cpu_threads: 4
|
|
|
|
|
|
ram_gb: 8
|
|
|
|
|
|
storage_gb: 500
|
|
|
|
|
|
storage_type: hdd
|
|
|
|
|
|
nic_gbps: 1
|
|
|
|
|
|
rack: rack01
|
|
|
|
|
|
rack_u: 7
|
|
|
|
|
|
u_height: 2
|
|
|
|
|
|
rack_face: front
|
|
|
|
|
|
power:
|
|
|
|
|
|
- { pdu: pdu01, outlet: 5 }
|
|
|
|
|
|
links:
|
|
|
|
|
|
- { local: eth0, peer: sw01, peer_port: 6, speed_gbps: 1 }
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Notes
|
|
|
|
|
|
|
|
|
|
|
|
Donated tower; PSU replaced 2026-06.
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Frontmatter reference
|
|
|
|
|
|
|
|
|
|
|
|
### Required on every device
|
|
|
|
|
|
|
|
|
|
|
|
| Field | Notes |
|
|
|
|
|
|
|---|---|
|
|
|
|
|
|
| `hostname` | Must equal the filename stem. |
|
|
|
|
|
|
| `kind` | One of the enum below. |
|
|
|
|
|
|
| `status` | One of the enum below. |
|
|
|
|
|
|
|
|
|
|
|
|
**`kind`** — `server`, `laptop`, `sbc`, `switch`, `ap`, `desktop`, `pdu`,
|
|
|
|
|
|
`patch-panel`, `shelf`, `blank`, `ups`, `kvm`.
|
|
|
|
|
|
|
|
|
|
|
|
**`status`** — `in-use`, `staging`, `spare`, `broken`, `donated`.
|
|
|
|
|
|
|
|
|
|
|
|
### Specs (optional, shown in the table and Specs box)
|
|
|
|
|
|
|
|
|
|
|
|
| Field | Example | Notes |
|
|
|
|
|
|
|---|---|---|
|
|
|
|
|
|
| `location` | `The pile` | Free text. |
|
|
|
|
|
|
| `cpu` | `Intel Core i5-3570K @ 3.40GHz` | Model string. |
|
|
|
|
|
|
| `cpu_cores` / `cpu_threads` | `4` / `8` | Integers; threads shown only if they differ from cores. |
|
|
|
|
|
|
| `ram_gb` | `8` | Integer (rendered as `8 GB`). |
|
|
|
|
|
|
| `storage_gb` + `storage_type` | `500` + `hdd` | `storage_type` ∈ `nvme`, `ssd`, `hdd`, `mixed`. |
|
|
|
|
|
|
| `storage` | `[{gb: 500, type: ssd}, {gb: 2000, type: hdd}]` | List form for multiple drives (alternative to the two fields above). |
|
|
|
|
|
|
| `nic_gbps` | `1` or `[1, 10]` | Number or list (rendered as `GbE`). |
|
|
|
|
|
|
|
|
|
|
|
|
### Placement in a rack
|
|
|
|
|
|
|
|
|
|
|
|
Only files that declare a `rack:` appear in a rack elevation. The rack is 48U.
|
|
|
|
|
|
|
|
|
|
|
|
=== "Front / rear (U-mounted)"
|
|
|
|
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
|
|
rack: rack01
|
|
|
|
|
|
rack_face: front # front | rear | both
|
|
|
|
|
|
rack_u: 7 # starting U (1–48)
|
|
|
|
|
|
u_height: 2 # height in U (≥1)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
`both` occupies the same U range on **front and rear**. Two U-mounted
|
|
|
|
|
|
devices may not overlap on the same face.
|
|
|
|
|
|
|
|
|
|
|
|
=== "0U side rail (e.g. vertical PDU)"
|
|
|
|
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
|
|
rack: rack01
|
|
|
|
|
|
rack_face: left # left | right
|
|
|
|
|
|
# no rack_u / u_height
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Side-rail (`left`/`right`) items are 0U and **must omit** `rack_u` and
|
|
|
|
|
|
`u_height`.
|
|
|
|
|
|
|
|
|
|
|
|
=== "Shelf-mounted"
|
|
|
|
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
|
|
rack: rack01
|
|
|
|
|
|
mounted_on: shf01 # an existing kind:shelf in the same rack
|
|
|
|
|
|
shelf_face: front # front | rear
|
|
|
|
|
|
shelf_slot: 2 # integer ≥1
|
2026-06-30 22:11:19 +02:00
|
|
|
|
chassis_u: 6 # optional: device height in U (how tall it stands)
|
2026-06-29 21:32:32 +02:00
|
|
|
|
# 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)`.
|
|
|
|
|
|
|
2026-06-30 22:11:19 +02:00
|
|
|
|
`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.
|
|
|
|
|
|
|
2026-06-29 21:32:32 +02:00
|
|
|
|
### Power feeds
|
|
|
|
|
|
|
|
|
|
|
|
A device draws power by listing feeds. Each feed must point at a real `kind:pdu`
|
|
|
|
|
|
file, and the outlet must be within that PDU's `outlets` count.
|
|
|
|
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
|
|
power:
|
|
|
|
|
|
- { pdu: pdu01, outlet: 5 }
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
A `pdu` device must declare a positive integer `outlets:` (e.g. `outlets: 8`).
|
|
|
|
|
|
|
|
|
|
|
|
### Network links
|
|
|
|
|
|
|
|
|
|
|
|
Links feed the network graph. `peer` is the hostname of a switch / patch-panel
|
|
|
|
|
|
/ peer device.
|
|
|
|
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
|
|
links:
|
|
|
|
|
|
- { local: eth0, peer: sw01, peer_port: 6, speed_gbps: 1 }
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## The make process
|
|
|
|
|
|
|
|
|
|
|
|
| Command | What it does |
|
|
|
|
|
|
|---|---|
|
|
|
|
|
|
| `make docs-index` | Regenerate the hardware/services indices and rack elevations from frontmatter. **Run this after every edit.** |
|
|
|
|
|
|
| `make docs-check` | Regenerate, then fail if the result differs from the committed copies — exactly what CI runs. |
|
|
|
|
|
|
| `make docs-build` | Build the static site with `mkdocs build --strict`. |
|
|
|
|
|
|
| `make docs-serve` | Live-reload local preview at `http://127.0.0.1:8000`. |
|
|
|
|
|
|
| `make test` | Run the Python unit tests (`pytest`). |
|
|
|
|
|
|
|
|
|
|
|
|
A typical edit loop:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
$EDITOR docs/hardware/srv06.md
|
|
|
|
|
|
make docs-index # regenerate
|
|
|
|
|
|
make docs-check # confirm no drift (optional sanity check)
|
|
|
|
|
|
git add docs/hardware/srv06.md docs/hardware/index.md docs/infrastructure/racks/
|
|
|
|
|
|
git commit -m "hardware: add srv06"
|
|
|
|
|
|
git push # CI builds and publishes to docs.makerfloss.eu
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
On push to `main`, CI regenerates the indices, runs the drift check, builds the
|
|
|
|
|
|
site strictly, and publishes it. If you forgot `make docs-index`, the drift
|
|
|
|
|
|
check fails and nothing is published.
|
|
|
|
|
|
|
|
|
|
|
|
## Dos and don'ts
|
|
|
|
|
|
|
|
|
|
|
|
!!! success "Do"
|
|
|
|
|
|
- **Do** run `make docs-index` and commit the regenerated files with your change.
|
|
|
|
|
|
- **Do** keep the filename equal to the `hostname`.
|
2026-06-29 21:40:09 +02:00
|
|
|
|
- **Do** use the [`<kind-abbrev><NN>` naming scheme](hardware-naming-scheme.md),
|
|
|
|
|
|
2 digits, unique per kind.
|
2026-06-29 21:32:32 +02:00
|
|
|
|
- **Do** mark unknown values as provisional placeholders and ask before
|
|
|
|
|
|
inventing rack/power/network numbers.
|
|
|
|
|
|
- **Do** preview locally with `make docs-serve` before pushing.
|
|
|
|
|
|
|
|
|
|
|
|
!!! danger "Don't"
|
|
|
|
|
|
- **Don't** hand-edit generated files — `docs/hardware/index.md`,
|
|
|
|
|
|
`docs/services/index.md`, `docs/infrastructure/racks/*.md`, and the
|
|
|
|
|
|
`*-elevation.svg` files all carry a *"do not edit by hand"* banner and will
|
|
|
|
|
|
be overwritten.
|
|
|
|
|
|
- **Don't** put non-device Markdown into `docs/hardware/` — the generators
|
|
|
|
|
|
scan that folder and expect host frontmatter. Guides like this one live in
|
|
|
|
|
|
`docs/guides/`.
|
|
|
|
|
|
- **Don't** give a 0U side-rail item (`left`/`right`) a `rack_u`/`u_height`,
|
|
|
|
|
|
and don't give a U-mounted item a side-rail face — the generator rejects
|
|
|
|
|
|
both.
|
|
|
|
|
|
- **Don't** point `power` at a non-PDU, or use an outlet number beyond the
|
|
|
|
|
|
PDU's `outlets` count.
|
|
|
|
|
|
- **Don't** rename a file without renaming the `hostname` to match.
|