Overview: show the host and its live stats — CPU, memory, microVMs, disk (closes #205) - #229
Merged
Merged
Conversation
…9166599 # Conflicts: # crates/colonizer/src/runtime.rs # web/src/cockpit/OverviewView.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
GET /api/statusnow returns a top-levelhostobject, and the overview renders it.Backend (
crates/colonizer/src/runtime.rs,main.rs,sessions.rs)Hostfacts probe inruntime.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), andchecked_at. Measurements come from/proc/meminfo,/proc/loadavg,/proc/uptime,/proc/sys/kernel/hostname(fallback: boundedhostnameexec),std::thread::available_parallelism(), and one boundeddf -kP <data_dir>exec. No new crate dependencies.Runtime: same 10 s TTL constant,?fresh=1honoured, lock held across the probe so concurrent polls share one run, newhost_cacheslot onApp(initialized in both the real and test constructors). A warm cache spawns nothing per request; the probe joins the existingstatus()tokio::join!.Optionwithskip_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 asSessionStatus::busy()),microvms_ceiling(orgs::global_max_parallel, the exact value admission uses), andkvm_ok(ridesruntime.kvm, omitted off-Linux) — so a host that cannot boot colonies is visibly broken, not idle.<config_dir>/host_id(0600, created once). Deliberately not telemetry'sinstall_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-hosthostobject becomes a list entry, not a reshape.Sessiongainsboot_cpus/boot_memory, recorded from the actualBootSpecinboot_innerright after it is built (so they survive a later boot-phase failure). The container-level#[serde(default)]keeps existingsessions.jsonloadable. 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: newHostInfointerface matching the wire shape exactly;HarnessStatus.host;Session.boot_cpus/boot_memory(andboot_timing, already on the wire, now typed for rendering).cockpit/host.ts: pure formatters (formatBytesre-exports the existingdiskSize,formatUptime,formatLoad,formatBootMs) plushostFacts()/colonyFacts()which drop any segment whose inputs are missing — the strip never renders zeros orundefined.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-wrapatfont-mono text-[11px]/text-faint, degrades cleanly at the 300 px minimum card width; warns whenkvm_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./api/statuspoll throughCockpit.tsx— no new fetch or poll.mock.ts:mockHost()so?mock=1exercises the strip;?runtime=macomitskvm_ok,?runtime=kvmreports it false.Docs:
docs/protocol.md§4 documents thehostcontract (always-presentid/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.ts102 lines,host.test.ts155) — ≈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_jsonshape, host_id persistence, old-sessions.jsonround-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 twoweb/src/cockpit/host.*, and the only new persisted state is<config_dir>/host_id.usage.rsmoved 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 genuinehostpayload on this machine.npm test(web): 306 passed (15 files), including the newhost.test.tssuite.npm run build:tsc --noEmit+ vite clean (only the pre-existing >900 kB chunk warning).df1K-block counts instead of bytes).Reviewer pointers
status()computes the host value before thejson!literal, because the literal movesruntimewhilehost_jsonborrowsruntime.kvm— easy to regress.SessionStatus::busy()(sessions.rs) vs the predicate inqueue::has_room.df -kP1K-blocks ×1024,used = total − availableguarded againstavailable > total.df -Poutput would garble if the filesystem device name contains spaces (all-Nonefallback, no crash);/procreads are blocking inside the async probe, matching the existingprobe_kvmprecedent;?runtime=oldin the mock still includes ahostobject (mock-only realism gap).Closes #205
🤖 Generated by Colonizer in a microVM