Skip to content

feat(server): expose host disk usage in /_hawser/info (Standard mode) - #92

Open
strausmann wants to merge 2 commits into
Finsys:mainfrom
strausmann:feat/hawser-standard-disk-info
Open

feat(server): expose host disk usage in /_hawser/info (Standard mode)#92
strausmann wants to merge 2 commits into
Finsys:mainfrom
strausmann:feat/hawser-standard-disk-info

Conversation

@strausmann

Copy link
Copy Markdown

Stacked on #91 — this branch builds on fix/disk-metrics-omitempty (it reuses the
metrics.DiskUsage() export introduced there). Please merge / rebase after #91; until then the
diff here includes #91's commit.

Problem

Standard mode's /_hawser/info only ever reported uptime -- no CPU, memory, or disk -- because
metrics.Collector (the thing that gathers all of that for Edge mode's periodic metrics push) is
never instantiated in the Standard-mode server. Disk space running out unnoticed is a real,
distinct problem for single-node Standard deployments, independent of the Edge-mode metrics
channel (see Finsys/dockhand#976, Finsys/dockhand#1397).

Change

Add a one-shot diskTotal/diskUsed/diskFree (bytes) to the /_hawser/info response, using
the same field names Edge mode sends on the metrics wire. Reuses metrics.DiskUsage(path)
(exported in #91) rather than duplicating the statfs logic or instantiating a full Collector
-- Standard mode already holds a *docker.Client (s.dockerClient), so resolving the data root
and statting it is a cheap, stateless per-request call.

On a stat failure the three keys are simply left out of the response, matching the
"absent means unavailable" convention from #91 -- not a misleading 0. Respects
SKIP_DF_COLLECTION for the same reason Edge mode does (hosts with many mounted volumes can
make statfs slow).

Out of scope (deliberately)

CPU and memory are not added here. Doing so would mean either duplicating Collector's
CPU-delta/mutex state per HTTP request, or instantiating a long-lived Collector inside the
Standard-mode server -- both larger design decisions (does Standard mode get a periodic metrics
loop of its own? does /_hawser/info become a snapshot of that, or stay request-driven?) that
are better made as their own change/issue rather than folded into a disk-only fix. Disk is
uniquely simple here because a single statfs call is stateless; CPU usage needs two samples
over time.

Tests

New internal/server/http_test.go (package had no tests before):

  • addDiskInfo() success path: real temp dir, used + free == total, unrelated map keys
    untouched
  • addDiskInfo() error path: missing path → all three disk* keys absent, not 0

go build ./..., go vet ./..., go test ./... -race all pass.

Collect() reported DiskTotal/DiskUsed/DiskFree as a plain 0 whenever the
Docker data-root statfs call failed (e.g. the path isn't visible in the
agent's mount namespace), because HostMetrics used bare uint64 fields with
no omitempty. On the wire, "disk stat failed" was indistinguishable from
"disk is full" or "0 bytes total".

Change the three fields to *uint64 with omitempty: a nil pointer omits the
field entirely on a stat failure, a non-nil pointer marshals the real value
-- including a legitimate 0 -- so success and failure no longer look alike.
This is wire-additive: an unchanged JSON consumer that still expects a
plain "number" gets undefined/absent instead of 0, which is a strictly more
useful signal and does not break decoding.

collectDisk() is split into a standalone, exported DiskUsage(path) that no
longer resolves the data root itself, so the statfs call is unit-testable
without a live Docker client. Collect() now resolves the data root and
calls DiskUsage() directly, applying the result via a small
applyDiskMetrics() helper that is also independently tested.
Standard mode's /_hawser/info previously reported only uptime -- no CPU,
memory, or disk -- because it has no running metrics.Collector; Edge mode's
periodic disk/CPU/memory push simply never applies here. Disk space
running out unnoticed is a real, distinct problem for single-node Standard
deployments (see Finsys/dockhand#976, #1397), so this adds a one-shot
diskTotal/diskUsed/diskFree to the info response using the same field
names Edge mode sends on the metrics wire, without pulling in the full
Collector (its CPU-delta state and periodic push loop are Edge-specific and
not needed here).

Reuses metrics.DiskUsage(path), exported for this purpose in the prior
commit. addDiskInfo() is split out from handleInfo() so the disk lookup is
unit-testable directly against a real and a deliberately missing path,
without a live Docker client or an HTTP round trip. On a stat failure the
disk* keys are simply left out of the response, matching the
"absent means unavailable" convention HostMetrics uses on the Edge wire
format -- not a misleading 0. Respects SKIP_DF_COLLECTION for the same
reason Edge mode does (statfs can be slow on hosts with many mounts).

CPU and memory are out of scope here: adding them would mean either
duplicating Collector's CPU-delta/mutex state per-request or instantiating
a long-lived Collector in the Standard-mode server, which is a larger
design decision left for a separate change.
Copilot AI lite review requested due to automatic review settings August 11, 2026 13:37

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants