Skip to content

Overview: show the host and its live stats — CPU, memory, microVMs, disk (closes #205) - #229

Merged
ParallelEntrepreneur merged 2 commits into
mainfrom
colonizer/issue-205-c9166599
Sep 21, 2026
Merged

ParallelEntrepreneur merged 2 commits into
mainfrom
colonizer/issue-205-c9166599

Conversation

@ParallelEntrepreneur

Copy link
Copy Markdown
Collaborator

What changed

GET /api/status now returns a top-level host object, and the overview renders it.

Backend (crates/colonizer/src/runtime.rs, main.rs, sessions.rs)

  • New Host facts probe in runtime.rs: id (stable per-install uuid), hostname, cpu_cores, memory_total_bytes/memory_used_bytes, load (1/5/15 min), uptime_secs, disk_total_bytes/disk_used_bytes/disk_free_bytes (of the data dir), and checked_at. Measurements come from /proc/meminfo, /proc/loadavg, /proc/uptime, /proc/sys/kernel/hostname (fallback: bounded hostname exec), std::thread::available_parallelism(), and one bounded df -kP <data_dir> exec. No new crate dependencies.
  • Cached exactly like Runtime: same 10 s TTL constant, ?fresh=1 honoured, lock held across the probe so concurrent polls share one run, new host_cache slot on App (initialized in both the real and test constructors). A warm cache spawns nothing per request; the probe joins the existing status() tokio::join!.
  • Omit-don't-fake: every measurable field is Option with skip_serializing_if, so a machine that can't measure something (e.g. macOS has no /proc) omits the key rather than zero-filling it.
  • host_json() (pure, unit-tested) merges in the request-time facts: microvms_live (sessions matching the same busy predicate as queue admission — is_live() || Publishing, factored as SessionStatus::busy()), microvms_ceiling (orgs::global_max_parallel, the exact value admission uses), and kvm_ok (rides runtime.kvm, omitted off-Linux) — so a host that cannot boot colonies is visibly broken, not idle.
  • Host id: persisted at <config_dir>/host_id (0600, created once). Deliberately not telemetry's install_id, which is ephemeral by design (forgotten when the live map is switched off). Everything is keyed by that id so a second machine can be aggregated later without an API rewrite — the single-host host object becomes a list entry, not a reshape.
  • Session gains boot_cpus/boot_memory, recorded from the actual BootSpec in boot_inner right after it is built (so they survive a later boot-phase failure). The container-level #[serde(default)] keeps existing sessions.json loadable. Guest CPU %/RSS are not shipped: microsandbox/agentd expose no such metrics (agentd serves only health/events/pty/shutdown) — noted in a code comment next to the fields rather than faked.

Frontend (web/src)

  • types.ts: new HostInfo interface matching the wire shape exactly; HarnessStatus.host; Session.boot_cpus/boot_memory (and boot_timing, already on the wire, now typed for rendering).
  • New cockpit/host.ts: pure formatters (formatBytes re-exports the existing diskSize, formatUptime, formatLoad, formatBootMs) plus hostFacts()/colonyFacts() which drop any segment whose inputs are missing — the strip never renders zeros or undefined.
  • OverviewView.tsx: a compact host strip above the org grid — hostname · IconServer live/ceiling · IconCpu cores+load · IconMemory used/total · disk free/total · uptime · checked <ago> — flex flex-wrap at font-mono text-[11px]/text-faint, degrades cleanly at the 300 px minimum card width; warns when kvm_ok === false. Colony rows gained a second meta line with only the facts that exist (boot cpus/memory, boot total, mesh ip, agent); pre-change colonies render exactly as before.
  • Prop threaded from App.tsx's existing 30 s /api/status poll through Cockpit.tsx — no new fetch or poll.
  • mock.ts: mockHost() so ?mock=1 exercises the strip; ?runtime=mac omits kvm_ok, ?runtime=kvm reports it false.

Docs: docs/protocol.md §4 documents the host contract (always-present id/checked_at/microVM counts; every other key omitted when unmeasurable) and the new Session fields.

Size — over the soft ceiling, deliberately

git diff --stat: 10 tracked files, +706/−24, plus 2 new files (web/src/cockpit/host.ts 102 lines, host.test.ts 155) — ≈963 changed lines across 12 files. The task is inherently full-stack (new probe + cache + wire contract + Session persistence + UI + mock + protocol docs), and roughly 40 % of the Rust diff is tests the repo's conventions call for (parser unit tests, cache TTL/fresh tests, host_json shape, host_id persistence, old-sessions.json round-trip, a real status-handler assertion). Trimming tests to hit 400 would have meant shipping unmeasured parsers.

Sibling-overlap heads-up: hot shared files touched here are crates/colonizer/src/main.rs (App struct + status()), crates/colonizer/src/sessions.rs (Session struct/Default/create + SessionStatus::busy()), web/src/types.ts, web/src/mock.ts, web/src/cockpit/OverviewView.tsx, web/src/cockpit/Cockpit.tsx (1 line), docs/protocol.md. New scaffolding kept minimal: no new crate or module registration — the only new files are the two web/src/cockpit/host.*, and the only new persisted state is <config_dir>/host_id. usage.rs moved by 2 lines (mechanical: new fields in a test Session literal).

Verification

  • cargo fmt --all --check, cargo clippy --workspace --all-targets -- -D warnings: clean.
  • cargo test --workspace: 447 passed, 0 failed — includes a real end-to-end status-handler test producing a genuine host payload on this machine.
  • npm test (web): 306 passed (15 files), including the new host.test.ts suite.
  • npm run build: tsc --noEmit + vite clean (only the pre-existing >900 kB chunk warning).
  • An independent review pass re-ran everything and fixed one doc bug (the protocol.md example had shown raw df 1K-block counts instead of bytes).

Reviewer pointers

  • status() computes the host value before the json! literal, because the literal moves runtime while host_json borrows runtime.kvm — easy to regress.
  • Confirm the live count matches admission: SessionStatus::busy() (sessions.rs) vs the predicate in queue::has_room.
  • Unit scaling in the parsers: meminfo kB ×1024, df -kP 1K-blocks ×1024, used = total − available guarded against available > total.
  • Known nits (accepted, not fixed): df -P output would garble if the filesystem device name contains spaces (all-None fallback, no crash); /proc reads are blocking inside the async probe, matching the existing probe_kvm precedent; ?runtime=old in the mock still includes a host object (mock-only realism gap).

Closes #205


🤖 Generated by Colonizer in a microVM

…isk (closes #205)

Refs #205

Co-Authored-By: Colonizer <noreply@colonizer.dev>
…9166599

# Conflicts:
#	crates/colonizer/src/runtime.rs
#	web/src/cockpit/OverviewView.tsx
@ParallelEntrepreneur
ParallelEntrepreneur merged commit 98f5faf into main Sep 21, 2026
9 checks passed
@ParallelEntrepreneur
ParallelEntrepreneur deleted the colonizer/issue-205-c9166599 branch September 21, 2026 02:00
ParallelEntrepreneur added a commit that referenced this pull request Sep 23, 2026
…isk (closes #205) (#229)

Refs #205

Co-Authored-By: Colonizer Settlers <331648616+colonizer-settlers@users.noreply.github.com>
Co-authored-by: Nick <40026523+Nick-CHI@users.noreply.github.com>
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.

Overview: show each colony's host and its live stats - CPU, memory, microVMs, disk

1 participant