summaryrefslogtreecommitdiff
path: root/statuspage/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'statuspage/README.md')
-rw-r--r--statuspage/README.md109
1 files changed, 109 insertions, 0 deletions
diff --git a/statuspage/README.md b/statuspage/README.md
new file mode 100644
index 0000000..3c2ae85
--- /dev/null
+++ b/statuspage/README.md
@@ -0,0 +1,109 @@
+# 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/<section>-<name>.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).