Commit Graph
5 Commits
Author SHA1 Message Date
osobhandClaude Sonnet 5 4ea1cbed2e Add shutdown-prep button to dashboard-v2 NodeDetail
Build with clawstor cache / Cargo build (clawstor-cached) (pull_request) Failing after 3s
Wires safe-shutdown-prep.sh into the dashboard so an operator can
prep a node for hardware maintenance from a browser instead of SSH.

New RPC methods (0x20/0x21):
- ShutdownPrepCheck runs `--dry-run` to completion and returns the
  full report. Never stops anything, safe to call repeatedly.
- ShutdownPrepExecute starts the real run detached (`systemd-run
  --user --scope --collect`), placing it in a cgroup outside
  claw-store.service's own -- the script's own step 6 stops that
  service, i.e. the process that would otherwise be running it, so
  it has to survive its own parent dying. Returns immediately with
  a "started" message; full output lands in
  /var/lib/claw-store/shutdown-prep.log for whoever's at the machine
  once it's gone dark, since there's no way to stream a live result
  past the point the daemon stops itself.
- Execute double-checks confirm_node_name against the peer's own
  configured name server-side, on top of the aggregator's own path
  match -- defense in depth for a highly consequential action.

Aggregator endpoints (admin-token gated, AuthedCaller::require_admin):
  POST /api/v2/node/:name/shutdown-prep/check
  POST /api/v2/node/:name/shutdown-prep/execute

Frontend: ShutdownPrepPanel on NodeDetail. Check button always
enabled; the real "stop services" button only unlocks after a ready
check, and additionally requires typing the exact node name to
confirm before it's clickable.

Also fixes a script bug found while testing this against the live
daemon process (not caught in manual interactive-shell testing): the
zpool-detection line parsed raw `mount` output positionally, which
returned the wrong field under the daemon's process context for
reasons that didn't reproduce interactively. Switched to
`df --output=source`, which is stable across both.

Verified end-to-end against tank, architect, and morpheus, including
cross-node targeting (tank's dashboard successfully triggered a
check on morpheus over the fleet RPC layer).

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-07-31 14:46:57 -07:00
osobhandClaude Sonnet 5 334cd068d2 dashboard-v2: fix asset base path to match backend /v2 mount
Build with clawstor cache / Cargo build (clawstor-cached) (pull_request) Failing after 6s
Console errors on the live dashboard (architect:7700) turned out to
be two separate problems layered together:

1. The deployed static bundle wasn't built from this repo at all --
   it called /api/v2/hot-refs, /api/v2/anomalies, and
   /api/v2/node/*/metrics-history, none of which exist anywhere in
   this codebase on any branch (checked via `git log --all -S`).
   Someone built and shipped a frontend straight to
   /usr/share/claw-store/v2 without ever committing the source.

2. Separately, this repo's own committed vite.config.ts had a latent
   bug: `base: '/clawstor/'`, contradicting its own comment ("served
   by claw-store serve under /v2/*") and the actual backend mount in
   serve.rs (`nest_service("/v2", ...)`). Checked `tailscale serve
   status` on tank + architect -- neither has ever proxied a
   /clawstor path, so that base would have 404'd every asset the
   moment anyone rebuilt and redeployed from source.

Fix: base = '/v2/', matching the real mount. Rebuilt and redeployed
to tank + architect (orphaned build backed up to
/usr/share/claw-store/v2.bak-orphaned on both).

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-07-31 13:16:53 -07:00
Omar Sobh f31c94607a FleetHealth PR 3: 'Projects' panel — which repos live where
Build with clawstor cache / Cargo build (clawstor-cached) (pull_request) Successful in 34s
Backend:
* New DashboardProject { repo, cache_bytes, fingerprint_count,
  refs, first_seen_unix, last_seen_unix, tier }.
* Handler build_projects() joins ref-tracking with the ref-store
  and blob-store: for each recorded fp, resolve fp → blob-id via
  RefStore::{get_stamped, get} then sum blob sizes per repo.
* Tier is a wall-clock function of last_seen_unix:
    active < 24h, recent < 7d, else idle.
* DashboardStorageReply gains `projects: Vec<DashboardProject>`
  (serde-default so older clients still parse).

Aggregator:
* New /api/v2/projects endpoint. Fans out DashboardStorage to
  every peer, tags each project row with its originating node,
  returns hottest-first.

Frontend:
* New ProjectsPanel component appended to the FleetHealth
  landing. Groups by repo, one row per project with tier badge
  (active/recent/idle), per-node pill badges, cache-size sum,
  ref list, last-activity age.
* Empty state explains how to populate: claw-cargo build with
  --repo + --git-ref (or CLAWSTOR_REPO/CLAWSTOR_GIT_REF env
  vars in CI).

Data populates automatically as each cache-put runs. Existing
demo entry on tank (clawverse/clawstor · main · c384a4...) will
surface after redeploy.
2026-07-14 19:06:40 -07:00
Omar Sobh 22af481c3e FleetHealth PR 2 (frontend): human-oriented landing + advanced menu
Build with clawstor cache / Cargo build (clawstor-cached) (pull_request) Successful in 18s
Reworks the SPA around the new DashboardStatus fields. The
landing is now a fleet-health dashboard aimed at a layperson —
disk gauges, mount ✓/✗, cache hit rate, next scheduled job.
No hex, no primitives.

Nav restructure:
* Primary: 'Fleet health' (just the landing).
* 'View Advanced ▾' dropdown reveals: Blobs / Tags / Refs /
  Snapshots / Ref-tracking. Routes moved under /advanced/*.

New components:
* StorageBar — horizontal used/total bar with pinned/evictable
  split, health-color threshold at 60/85%.
* NodeCard — traffic-light dot + disk + hot tier bars + mount
  state + cache hit rate + next-timer countdown. Whole card
  is a link into node detail.

New CommandCenter:
* Fleet-wide storage roll-up card (sum of every node's disk).
* Grid of NodeCards.
* 10s poll cadence retained from previous version.

Existing StorageBrowser + RefTrackingPage moved behind
/advanced/* routes; internal component code untouched.
2026-07-14 17:23:25 -07:00
Omar Sobh f33468b7c2 dashboard-v2 PR 2: frontend SPA + serve integration
Build with clawstor cache / Cargo build (clawstor-cached) (pull_request) Successful in 16s
React 19 + Vite + Tailwind + wouter (tiny router, no external
state library). Consumes the /api/v2/* endpoints shipped in PR 1.
Serves under /v2/* so the legacy dashboard at / stays live.

Pages:
* CommandCenter (/)      — fleet strip + this-node stat tiles
* NodeDetail (/nodes/:name) — per-node deep dive
* StorageBrowser (/storage/{blobs,tags,refs,snapshots}) — tables
  with prefix filter
* RefTrackingPage (/refs/tracking) — grouped by repo

Backend changes:
* claw-store serve grows --v2-static-dir <path>
* build_app split into build_app_with_v2 for the extra static
  mount
* /v2/* falls through to index.html so wouter client routing works

New systemd unit: clawstor-dashboard.service. Points at both
static dirs; installs on any node.

dashboard/ (legacy) untouched. dashboard-v2/ built to
target/dashboard-v2/dist for deploy.

Deploy sequence per node:
1. cp target/release/claw-store  ~/clawstor-deploy/
2. rsync dashboard-v2/dist/      ~/clawstor-deploy/dashboard-v2/
3. cp deploy/systemd/clawstor-dashboard.service ~/.config/systemd/user/
4. systemctl --user daemon-reload && enable --now clawstor-dashboard.service

Cross-node fan-out for /api/v2/node/:name/status is PR 3.
Action POSTs (scrub/gc/snapshot/pin) are PR 4.
2026-07-14 15:59:47 -07:00