Files
felhom-controller/REPORT.md
T

84 lines
5.9 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.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.