summaryrefslogtreecommitdiff
path: root/statuspage/README.md
blob: 3c2ae85806cc9ab74bd3a5e2c4af76164fa438f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
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).