Files
diskless-workstation/serving/fleet-manager/ui
Audiobuzz df7dad81b7 fleet-manager: host uptime metric + reboot-pending status
The manager lets an admin schedule a reboot (desired.reboot_at) but never showed
whether it had happened. Add host uptime to the health snapshot and derive a
reboot status from it.

- proto: HealthSnapshot.uptime_seconds (15); regenerated pb.go (manager + agent copy).
- agent: probe /proc/uptime -> uptime_seconds (with parser + test).
- manager: Health.UptimeSeconds cached in inventory; snapshotToHealth maps it;
  influx writes + whitelists uptime_seconds as a queryable field.
- UI: fmt.js dur() + rebootStatus() — boot_time = last_seen - uptime (manager clock
  frame, no host/manager sync needed), compared to reboot_at. Monitor host detail
  shows an "uptime" row and a "reboot" row: pending in X / overdue by X / rebooted.

Observability-only — works before the reboot ACTUATOR lands (deferred). Once a host
boots after the scheduled time (BMC/manual now, agent later), the badge flips to
"rebooted" automatically.
2026-07-10 06:41:09 +00:00
..

fleet-manager UI — the fleet command deck

The admin SPA for fleet-manager. Svelte 5 + Tailwind 4 + Vite, themed LYSANDRA / restricted-violet (a high-security evolution of the kiosk-app's LYSANDRA flight-deck: amber deck, violet reserved for privileged/destructive + auth surfaces, teal telemetry, red alert, clearance chrome). A sibling of serving/kiosk-app, kept in-repo for now (may graduate to its own submodule).

Three pillars over the manager's JSON API, plus the passkey gate:

  • Login / Enrol — WebAuthn ceremonies (navigator.credentials). Enrol is reached via the one-time link from fleet-manager register-admin.
  • Monitor — fleet roster (online / version-drift / health) + per-host detail with bespoke SVG telemetry charts (from /api/hosts/{serial}/metrics).
  • Authorise — pending-enrolment queue: cross-check the fingerprint, approve (violet) + bind, or deny.
  • Lifecycle — per-host desired-state (version pin, kiosk URL, reboot, drain); destructive changes are confirm-gated.

Build / embed

The built SPA is embedded into the fleet-manager binary via go:embed and served same-origin over the admin plane.

npm ci
npm run build          # -> dist/ (gitignored)
cd .. && go build -tags embedspa   # embeds dist/ into the binary

The default go build (no tag) ships a stub instead, so Go builds/tests don't require dist/. The Dockerfile does the two-stage build (npm → dist → go build -tags embedspa).

Dev

npm run dev            # Vite on :5173, proxies /api + /auth to :9500

Point it at a locally-running manager. Against an insecure+seeded manager (FLEET_MGR_ADMIN_INSECURE=true FLEET_MGR_SEED=true), /api/whoami returns dev-insecure, so the SPA renders the pillars without a passkey — handy for theme/layout work. Passkey login/enrol need the manager in secure mode with a valid RP origin + a WebAuthn authenticator.