Files
felhom-controller/REPORT.md
T

123 lines
8.5 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.
# REPORT — v0.169.0/.1: Disk-health card + degradation notification ("Lemezek állapota")
Part of the disk-health train (agent v0.94.0 + controller v0.169.0/.1 + hub v0.73.1). Appended above
the previous report (kept below).
**Baselines:** controller `e164fef` (v0.168.0) → `c97975c` (v0.169.0) → `dbf6313` (v0.169.1). Clean at start.
**What shipped:**
- `agentapi`: `SmartSummary` extended to the full counter set; `DiskInfo.Smart *SmartSummary`; pure
`DiskVerdictFor` (shared by card + check) + `Label` + `DegradedAttributes`. Verdicts: FAILING→Hiba;
PASSED+any(reallocated/pending/offline/critical/media >0 or percentage_used ≥90)→Figyelmeztetés;
PASSED clean→Rendben; nil/UNKNOWN→Nincs adat (never alarms).
- `web`: dashboard "Lemezek állapota" card (physical disks only — pbs/lvm/nfs/cifs excluded in v0.169.1)
via a 60s /disks TTL cache; unreachable agent → "Nincs adat", page never blocks. 6h `disk-health-check`
emits `disk_health_degraded` on a degradation only (in-memory baseline; first run silent; recovery/
UNKNOWN never notify; multi-attr → one event). `notify.NotifyDiskHealthDegraded` (warn/critical).
**No global banner** (deliberate).
**Tests + red-proofs (all recorded):** verdict table (red-proof: ≥90→>90 → boundary FAIL); notifier
emit (type/severity/subject); check first-run-silent (red-proof: disable the guard → first run notifies
FAIL); degradation-once; recovery-silent; UNKNOWN-excluded; FAILING→critical; nil-smart card graceful;
TTL cache. Full controller suite: 27 packages pass, 0 fail; build + vet clean; template/emoji/mojibake
gates OK.
**Deploy + live validation (guest 9201):** built + deployed 0.169.0 → Up (healthy); dashboard rendered
the card. **§13(2):** first render showed 4 rows (pbs/lvm carried a default UNKNOWN SMART) → shipped
**v0.169.1** to exclude logical/network types; re-verified the card now shows exactly **2 physical rows**
(`local`, USB), both "Nincs adat" — the correct real verdict on the virtualized demo hardware.
**§13(3) notification path** (proven with the hub, see hub REPORT): a `disk_health_degraded` POST — the
exact wire call `notify.PushEvent` makes — was **400-rejected by hub v0.73.0** and **200-accepted +
emailed by hub v0.73.1**. Method: direct endpoint POST via curl (no fixture code committed → nothing to
revert; the demo's real disks stay "Nincs adat" so normal operation is quiet).
**Awaiting operator:** browser visual check of the card layout (rendered HTML strings confirmed). A real
FAILING/Figyelmeztetés verdict can't occur on the virtualized demo hardware (no real SMART) — the verdict
logic + transitions are covered by unit tests + the live event-pipeline proof.
---
# REPORT — v0.168.0: Customer-configurable backup window ("Mentési időablak")
**Date:** 2026-07-24 · **Deployed & verified live on guest 9201; box left configured at 02:30.**
## 1. Baseline
| Repo | `main` @ start | version | → |
|------|----------------|---------|---|
| felhom-controller | `e33c1ae` | v0.167.1 | **v0.168.0** (committed `82c67e3`) |
Verified against live Gitea at task start (HEAD == origin == live). No agent coupling; MinAgent unchanged.
## 2. What shipped
ONE customer setting — **"Mentési időablak kezdete"** (window start W) — drives every nightly leg at
FIXED, never-stored offsets so misordering is impossible: DB dump at **W**, tier-2 at **W+60m**, off-box
at **W+105m** (wrap-safe). The whole-guest (agent PBS/vzdump) cycle is gated to **[W+2h, W+6h)** with a
safety valve. Precedence: settings > controller.yaml `db_dump_schedule` > "02:30". Changes apply
**without restart**.
## 3. Files
- **New** `internal/backupwindow/` (backupwindow.go + _test.go) — pure time math: `ParseHHMM`/`FmtHHMM`/
`LegTimes`/`GateWindow`/`EffectiveWindow`/`Valid`; offsets are constants (derived, never stored).
- `internal/scheduler/scheduler.go` (+ new _test.go) — `UpdateDaily(name,timeStr) bool`, per-daily-job
buffered `resched` chan, a `case <-job.resched` in `runDailyJob`, Schedule read under the mutex.
- `internal/settings/settings.go``BackupWindowStart` field + Get/Set.
- `internal/quiesce/quiesce.go` (+ new quiesce_window_test.go; fakes updated in quiesce_test.go /
quiesce_8b2_test.go) — `Backend.Due` now returns the backup age; `Options.WindowStartFn`/`Cadence`;
`scheduledRunAllowed` predicate + Budapest helper; gate on the scheduled path in `runOnce`.
- `internal/web/backup_handlers.go` (+ new backup_window_test.go), `handlers.go`, `server.go` route,
`templates/backups.html` — the "Mentési időablak" card + POST `/backups/window`.
- `cmd/controller/main.go` — the three Daily legs + backup-cache + initial-cache + quiesce loop wired
from the effective window.
- Docs: `CHANGELOG.md`, `CONTEXT.md`, `controller/README.md`, `REUSE.md` (UpdateDaily + backupwindow +
3rd Budapest-loader duplication note), this `REPORT.md`.
> Note: a stray `gofmt -w internal/ cmd/` reformatted ~46 unrelated (non-gofmt-clean) files; all were
> restored to `origin/main` so the commit is surgical — only the files above are in the diff.
## 4. Tests + red-proofs (all recorded)
`go build ./... && go vet ./... && go test ./...`**27 packages pass, 0 fail.** Template/design gates
(template_id / emoji / mojibake / native-confirm) all OK.
| Group | Test(s) | Red-proof (mutate → FAIL → restore) |
|-------|---------|--------------------------------------|
| A | `LegTimes` (02:30/23:30/22:00/00:00, wrap), `LegTimes_InvalidRejected`, `GateWindow` | drop the FmtHHMM modulo → `LegTimes("23:30")` yields "24:30"/"25:15" → **FAIL confirmed** |
| B | `EffectiveWindow` precedence table (settings>yaml>"02:30", corrupt falls through) | — |
| C | `UpdateDaily_MutatesAndSignals`, `_UnknownAndInvalid`, `_GoroutineConsumesReschedule` | remove `case <-job.resched` → signal stays buffered → immediacy test **FAIL confirmed** |
| D | `scheduledRunAllowed` truth table (inside/boundary/outside/valve/wrap/nil-age) + Loop integration (defer outside / run inside / valve runs / **manual TriggerNow never gated**) | invert the valve `>``<` → starving-box + no-valve cases **FAIL confirmed** |
| E | `BackupWindowSave_Valid` (settings + 3× UpdateDaily + flash), `_Invalid` (nothing stored + error flash) | skip the `Valid()` check → invalid value gets stored → **FAIL confirmed** |
Existing quiesce/scheduler/web suites still pass unchanged.
## 5. Deploy + live validation (guest 9201)
Built `felhom-controller:0.168.0` (145M) from the clean pushed tree; deployed via bootstrap →
`Up (healthy)`, `Controller elindult (0.168.0)`. Startup registered the legs at the default window:
`db-dump 02:30 · tier2-backup 03:30 · offbox-backup 04:15` (CEST). Method: endpoint-level (in-guest
curl to `172.17.0.2:8080`, `Host: felhom.demo-felhom.eu`; login 302 + scraped session CSRF).
**Save a window (POST `/backups/window`, window_start=22:00) → 303:**
- Page re-rendered: input `value="22:00"`, derived rows `22:00 / 23:00 / 23:45`, rendszermentés
`kb. 00:0004:00 között` (W+2h..W+6h, wrap-safe).
- Logs (NO restart): `db-dump rescheduled 02:30 → 22:00`, `tier2-backup 03:30 → 23:00`,
`offbox-backup 04:15 → 23:45`, `backup window set to 22:00 (legs 22:00/23:00/23:45)`.
**Restore (window_start=02:30) → 303:** page shows `02:30 / 03:30 / 04:15` + `kb. 04:3008:30 között`;
logs show the three legs rescheduled back. **Box left at 02:30.**
## 6. NOT live-exercised on 9201 (stated method)
- **The disk-tier window-gate DEBUG denial** could not be triggered live: the demo host agent is DOWN
for the remote-site window (its `localapi` binds `192.168.0.162`, which doesn't exist there), so the
quiesce loop's `/backup/due` call errors before the gate is reached. The gate + safety valve + the
manual-never-gated property are fully covered by Group D (truth table + Loop integration). Re-verify
the live DEBUG line once the agent is reachable again.
- Browser visual check of the "Mentési időablak" card layout is Viktor's acceptance step (the rendered
HTML strings are confirmed; the pixels are not).
## 7. Observations (out of scope — documented only)
- Saving explicitly writes `backup_window_start:"02:30"` — functionally identical to the empty/default
state, so the box is correctly "at 02:30" either way.
- Cadence for the safety valve defaults to 24h **controller-side** (the agent's `/backup/due` response
carries no cadence field); if cadence policy ever becomes hub/agent-driven, thread it through instead
of the constant.
- Three Budapest-timezone loaders now exist (scheduler, web, quiesce) — noted in REUSE.md §6; kept
local to avoid a scheduler↔quiesce import edge.