Commit Graph
3 Commits
Author SHA1 Message Date
Mitchell-JohnsonandClaude Opus 5 2f59a54678 A Network tab, with an internet speed test
Per machine like every other tab: the interfaces as the kernel has them
(addresses, MAC, MTU, negotiated link speed, carrier, totals, live rates from
the sampler's own sensors), the default route and resolvers, what the internet
sees of this connection, and a speed test with the last fifty results kept.

The test runs in the daemon, not the browser, so the figure is the line of the
machine in the switcher — the router's, if you switch to gate — and it carries
on when the phone locks. It measures against Cloudflare's public speed
endpoints, so there is nothing to install on any host, which is what makes it
work the same on Debian and on OpenWrt where flash is scarce.

What the measurement does and does not count:

  - Several streams, HTTP/2 deliberately off. One stream over one connection
    measures a congestion window, and HTTP/2 would put every stream back onto
    one connection and measure the same thing.
  - The first second of each phase is thrown away as the ramp.
  - A phase ends on 64 MiB as well as on four seconds, so a fast line says what
    it is without moving a gigabyte. A minimum window keeps a very fast line
    from filling the cap before there is anything to divide by.
  - Latency is the round trip less the far end's own Server-Timing. A zero-byte
    response is mostly Cloudflare's worker thinking: left in, it reported 31 ms
    for a line the edge itself measures at 3.5. Jitter is the mean change
    between consecutive probes, so one slow probe cannot run away with it.
  - The far end rate-limits by volume. So: a 20 s cooldown counted from the last
    attempt rather than the last success, streams that retry twice, the rate
    computed over the window in which bytes were actually still arriving, and a
    plain sentence when it was refused. Coasting to the end of the clock with
    nothing arriving reported a third of the truth.

The last result is published as net.internet.* sensors, each stamped with when
the test ran, so the line can be a widget, a graph, an alert or a Prometheus
series like anything else. The public address is refreshed on its own quarter
hour, which is worth having here: it is a DHCP lease and it moves.

Tests are offline — the window, the byte cap, the refusal and the cancellation
run against a local server; the route parser's byte order is pinned by a case
that would have caught the bug it did. The live measurement is behind
HAMLAB_NET_TEST=1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-27 20:11:03 -07:00
Mitchell-JohnsonandClaude Opus 5 192504ead3 docker: the eight things Dockhand did that Ham Lab did not
Dockhand is being retired, so the Docker tab has to cover what it actually
earned its keep doing. Eight pieces, all per container or per machine:

- Stats: CPU, memory and IO over time, from sensors already collected.
- Health: the container's own healthcheck, with the last few probe outputs —
  which is where a failing check says why.
- Events: `docker events` keeps a minute of backlog and nothing more, so Ham
  Lab follows the stream and keeps a ring of its own. A restart at 4am is
  still there at 9.
- Shell: `docker exec` into a container, in the terminal already here.
- Limits: memory, CPU and restart policy changed live, without hand-editing
  the compose file for a number you want to try.
- Updates: what the registry has that this machine does not, for every image
  at once rather than one stack at a time.
- The same across every machine, asked of the hub — which is the only thing
  that can reach them all.
- Schedules: a real line in /etc/cron.d/hamlab-docker calling the binary,
  in the same shape as the ZFS snapshot schedules. Dockhand updated DNS and
  ingress nightly from a ticker inside a web app; a cron line keeps running
  when the console does not, and is visible to anyone reading the machine the
  normal way.

internal/compose is new and shared, so a deploy from the console and a deploy
from cron invoke compose identically — including the case where compose has to
run inside the orchestrator's own container, where the paths are that
container's and not the host's.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 20:11:36 -07:00
Mitchell-JohnsonandClaude Opus 5 a70f3e2ed2 Container events are Ham Lab's own record, not Docker's short memory
docker events is a live stream with a small in-memory backlog: ask for thirty days and you
get a few minutes, and a daemon restart loses the lot. That is why Dockhand kept its own
copy. A watcher now follows the stream and appends lifecycle events to a ring beside the
config, flushed every thirty seconds, so the question of what happened to a container last
week has an answer. Health-check exec events are excluded — three per probe, thousands a
day, and the health panel says it better.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-24 19:55:36 -07:00