# dandokmang status console Static status page for the dandokmang homelab server. A cron job runs `render.sh`, which runs every check script in `checks/`, collects their output, and writes a static `index.html` served by Caddy on the WireGuard interface only. ## Layout ``` statuspage/ checks/ one script per metric or group of related metrics lib/ common.sh shared helpers (svc_status, port_check, jail_status, json_line) render.sh orchestrator + HTML renderer README.md ``` ## The check-script contract This is the part to remember when you come back in six months to add a metric: **every script in `checks/` is independent. `render.sh` never changes to support a new check.** A check script must: - Be executable (`chmod +x`). - Emit **one JSON object per line** (JSONL) to stdout, and nothing else. - Emit no output to stdout on failure (send diagnostics to stderr if you want them, but they're discarded by the renderer). Each JSON object has exactly these fields: | field | meaning | |-----------|-------------------------------------------------------------------| | `section` | groups rows under a heading: `hardware`, `host services`, `jails` (or a new section name - unrecognized sections are rendered after the known ones, in the order first seen) | | `label` | display name for the row | | `value` | display value; use `""` for a plain up/down check with no value | | `status` | one of `ok`, `warn`, `down` - maps to a green/yellow/red square | Example (`checks/wireguard.sh`): ```json {"section": "host services", "label": "wireguard (wg0)", "value": "", "status": "ok"} ``` A script can emit multiple lines - `hw.sh` emits one line each for load avg, uptime, free mem, zroot usage, and zpool health. Use `json_line SECTION LABEL VALUE STATUS` from `lib/common.sh` instead of hand-rolling the JSON - it escapes backslashes, quotes, and embedded newlines (e.g. a multi-line `zpool status -x` when a pool is degraded) so the JSONL stays one object per line no matter what a command prints. ### Adding a new check 1. Create `checks/
-.sh` (or reuse an existing section script if the metric belongs with it). 2. `. "$(dirname "$0")/../lib/common.sh"` and call `json_line` for each row. 3. `chmod +x` it. That's it - no changes to `render.sh`, no template edits. It picks up any executable `checks/*.sh` file automatically and renders whatever sections it finds. ## Failure isolation `render.sh` runs each check script and handles three failure modes without aborting the whole render: - **Non-zero exit** -> a `down` row labeled with the script's filename under a synthetic `checks` section. - **No output** -> a `warn` row, same treatment. - **Output that doesn't look like our JSONL** -> a `warn` row, same treatment. So a broken check shows up as a visible red/yellow row on the page instead of silently disappearing or crashing the render. ## Dependencies Parsing is done with plain `awk`/`sed`/`grep` against the constrained JSONL shape our own `json_line` helper produces - no `jq` dependency. If checks ever need to emit richer JSON (nested objects, arrays), the awk parser in `render.sh` (`jsonval()`) will need to grow or be swapped for `jq`. ## Deployment Cron (as root): ``` * * * * * /usr/local/etc/statuspage/render.sh ``` Caddyfile (bind to the WireGuard interface IP only): ``` 172.16.0.1:8080 { root * /usr/local/www/status file_server } ``` Reload Caddy after editing: `service caddy reload`. Access from a WireGuard peer: `http://172.16.0.1:8080`. `render.sh` writes to `/usr/local/www/status/index.html` by default; override with the `STATUSPAGE_OUT` environment variable (useful for local testing without root).