Files
felhom-controller/REPORT.md
T

5.9 KiB
Raw Blame History

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.goBackupWindowStart 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.