Files
felhom.eu/REPORT.md
T
2026-07-01 06:24:53 +02:00

88 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# felhom.eu — task reports
> **Overwrite** this file with a summary of the most recent task only (uniform with the other repos; not cumulative). The cumulative hub history lives in [hub/CHANGELOG.md](hub/CHANGELOG.md).
---
# REPORT — Hosts page: read-only fleet view (hub v0.27.0)
**Date:** 2026-07-01 · **Repo:** `felhom.eu` (`hub/`) · **Audit finding:** F-M1 (resolved)
## What & why
The agent enrolls as a **host** and the hub stores rich host state (identity, agent version, guests,
storage targets with SMART, DR/escrow, staleness) and **alerts** on it — but the entire host domain was
**invisible in the GUI** (email-only). This adds a **Hosts** nav section: a fleet **list** + a per-host
**detail** page. **Read-only** (GET only, no host actions/mutation routes) — this surfaces state the
pull/desired-state model demands; it does not reintroduce the inbound control retired in v0.26.0.
## Baseline
hub `v0.26.0` @ `73b3f6a` (clean tree) → **`v0.27.0`**. Trunk-based `main`; commits
`2289fc9` (code) + `f8b8730` (manifest bump).
## Files
**Created**
- `hub/internal/web/hosts.go``handleHostsList`, `handleHostDetail`, `hostStatus`/`hostStatusClass`/
`hostStatusLabel`, `parseHostVitals`, `parseHostStorageTargets`, `customerName`.
- `hub/internal/web/hosts_test.go` — 5 tests (incl. the no-secret assertion).
- `hub/internal/web/templates/hosts.html`, `hub/internal/web/templates/host_detail.html`.
**Modified**
- `hub/internal/store/store.go`**new** `ListGuestsForHost(hostID) ([]Guest, error)` + `scanGuest`
helper over `guestRealitySelectCols` (reality columns only; **omits** `api_key`, `desired_spec_json`).
- `hub/internal/store/host_test.go``TestListGuestsForHost`.
- `hub/internal/web/server.go``GET /hosts` (+`/hosts/`) and `GET /hosts/{id}` routes (modelled on
the `/apps` pair); new `timeAgoPtr` template helper for `*time.Time`.
- 7 existing templates (`dashboard`, `configs`, `apps`, `config_form`, `configuration`,
`customer_unified`, `app_detail`) — added the `Hosts` nav link (nav is duplicated per page, not a
shared partial).
- `hub/CHANGELOG.md` (newest-on-top), `manifests/hub.yaml` (`:0.26.0``:0.27.0`).
## Design decisions
- **Status badge reuses the alerting threshold.** `hostStatus()` reuses `s.staleThreshold` and the
`HostStalenessChecker`'s bands (stale after the threshold, down at 2×) — one definition, so the GUI
badge agrees with the emails. `nil` last-report → "waiting for first report".
- **No new ingestion path.** Vitals + rich storage (role/state/fill/thin-pool/SMART) are parsed from the
already-stored latest `report_json` (`GetLatestHostReportJSON`); worst-fill from `GetHostStorageTargets`.
Guest counts from `ListGuestsForHost` (per-host accurate).
- **No secrets.** The guests reader never selects `api_key`/`desired_spec_json`; DR/escrow are shown as
presence booleans only — never the opaque blobs. A test asserts the host `api_key` is absent from the
rendered detail body.
- **Nil-safe.** No report / no guests / no storage / no DR all render empty states, never a panic.
## Tests — `go build ./... && go vet ./... && go test ./...` all `ok`
- `TestListGuestsForHost` — none→empty; multiple→vmid-ordered; a foreign-host guest excluded; the
`api_key` column is not surfaced. **PASS**
- `TestHostStatus` — nil→pending, fresh→ok, 45m→stale, 3h→down. **PASS**
- `TestHandleHostsList` — 2 host rows, ONLINE + NO REPORT badges, worst-fill (73%) rendered, no `<button>`. **PASS**
- `TestHandleHostDetail` — identity/guest/controller-version/storage/SMART(41°C)/role/customer-link
present; DR + escrow both "present"; **`api_key` absent (no-secrets)**; no `<button>`. **PASS**
- `TestHandleHostDetail_Unknown` — unknown host → 404. **PASS**
- `TestHandleHostDetail_NoReport` — renders "waiting for first report", no panic. **PASS**
## Deploy (GitOps via ArgoCD — the `felhom` app; auto-sync off)
Image `gitea.dooplex.hu/admin/felhom-hub:0.27.0` built+pushed on the build server (180); `manifests/hub.yaml`
bumped + committed; ArgoCD `felhom` hard-refreshed → OutOfSync → synced → **Synced / Healthy**;
`deploy/hub` rolled out on image `:0.27.0`; logs show `[INFO] Listening on :8080`.
## Live validation (claude-in-chrome, operator-authed, hub.felhom.eu)
- **`/hosts`** — lists `demo-felhom-01` **ONLINE** (agent `0.51.0`, guests 11/15, CPU 3% / MEM 21% /
DISK 29%, worst storage 29% `local`) + two drill hosts **NO REPORT**. Hosts nav active; footer `0.27.0`.
- **`/hosts/demo-felhom-01`** — Identity (customer **Demo Ügyfél** cross-linked to `/customers/…`, agent
`0.51.0`, enrolled 21d ago, last report 8 min ago, desired generation 2), Vitals, **Guests** (15 rows,
VMID/name/status running=green/stopped=red/last-seen), **Storage Targets** (felhom-usb **SMART PASSED
33°C**; local-lvm lvmthin 11% fill / 11% thin-pool; others UNKNOWN/graceful "—"), **DR / Backup** DR
Recipe + Key Escrow both **present**. Confirmed: **no action buttons**, and the page text carries **no
`api_key`/secret**.
## Remaining audit follow-ups (not this slice)
Controller-side geo intent sync; a read-only reported-vs-desired "Show Diff"; the cosmetic `controllerURL`
cleanup in `configs.go`.