v0.6.0-rc1: slice 6 Phase A — backup + the self-restore-test (local target)
The guest-level backup layer + the journaled self-restore-test (restore→boot→verify→ teardown) that closes "a backup you haven't restored isn't a backup". All benign (reuses the slice-4 classifier/gate/journal; no new destructive class/crypto). Local target only; PBS = Phase B. Restore to a NEW guest only. Backups crash-consistent. - proxmox: DestroyLXC, VzdumpOptions.Notes (notes-template), LatestBackupVolID. - reconcile: Engine.RunRestoreTest (journal Scratch entry BEFORE mutation; net link-down pre-boot; defer teardown always; benign gated destroy) + Recover extended to reap a leaked scratch guest (Scratch flag, special-cased before the UPID path; idempotent). - internal/backup: runner (vzdump + archive resolve + bulk-gap = backup!=1) + cadence scheduler (4th daemon goroutine, default 24h) + in-memory report store. - hub: Backup/RestoreTest filled; collector seams; cross-repo golden byte-identical + bidirectional key-set tests; hub handler logs a FAILED restore-test prominently. - config BackupConfig (band 990000-990009 default); --selftest=backup / restore-test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,57 @@
|
||||
All notable changes to **felhom-agent** are recorded here. Update on every code
|
||||
change that gets pushed.
|
||||
|
||||
## v0.6.0-rc1 — slice 6 Phase A: backup + the self-restore-test (local target) (2026-06-09)
|
||||
|
||||
Phase A of the backup/restore slice (doc 03 §8) — the agent's guest-level backup layer and
|
||||
the **self-restore-test**, which closes "a backup you haven't restored isn't a backup".
|
||||
Everything here is BENIGN (backup, restore-to-NEW, scratch teardown): reuses the slice-4
|
||||
classifier/gate/journal — no new destructive class, no new crypto. Local target only; PBS is
|
||||
Phase B. Restore is to a NEW guest only (no overwrite). Backups are crash-consistent only
|
||||
(app-consistency needs the controller quiesce, slice 8) — marked so in the report.
|
||||
|
||||
### Added
|
||||
- **proxmox** (`mutate.go`/`query.go`): `DestroyLXC` (DELETE …/lxc/{vmid}?purge=1&destroy-
|
||||
unreferenced-disks=1 → UPID; the scratch-teardown primitive); `VzdumpOptions.Notes` →
|
||||
`notes-template` (verified on PVE 9.2.2); `LatestBackupVolID` (resolve a produced archive
|
||||
from the backup-storage listing — the task status carries no result volid).
|
||||
- **reconcile self-restore-test** (`restoretest.go`) — `Engine.RunRestoreTest`: pick a free
|
||||
scratch VMID (configured band, excludes 9999; full band → skip, never out-of-band) →
|
||||
**journal a Scratch-owned entry BEFORE any mutation** → restore-to-new → benign net
|
||||
**link-down** SetConfig (so the clone can't conflict with a running source's MAC/IP; this
|
||||
is test-safety, NOT slice-7 identity reset) → boot → verify **reaches `running`** → ALWAYS
|
||||
teardown (defer; benign `ClassGuestDestroy` + agent-tagged-scratch provenance, gated). Runs
|
||||
on the scratch VMID's queue lane. Reuses the journal/gate; result feeds the report.
|
||||
- **Crash-safe recovery** (`recover.go`): a Scratch journal entry is resolved by TEARDOWN,
|
||||
not by re-checking the restore sub-task's UPID — special-cased BEFORE the generic path
|
||||
(else the restore task's OK would mark it succeeded while the guest leaks). `Recover` now
|
||||
destroys a leaked scratch guest (idempotent: already-gone → clean; list-unreadable → left
|
||||
in-flight for a later pass). `JournalEntry.Scratch` flag; `RecoverResult.ScratchClean/
|
||||
ScratchDestroyed`. GuestAPI gains `RestoreLXC`/`DestroyLXC`/`GuestStatus`.
|
||||
- **`internal/backup` package**: `BackupRunner.Backup` (vzdump + archive/size resolve +
|
||||
bulk-volume gap — a mountpoint is UNCOVERED unless it carries an explicit `backup=1`, so
|
||||
an unset `backup=` is reported uncovered too, the safe DR direction); `PickRestoreCandidate`
|
||||
(newest backup); an in-memory `Store` (latest-backup-per-target + latest-restore-test)
|
||||
implementing the hub `BackupReporter`/`RestoreTestReporter` seams; a cadence `Scheduler`
|
||||
(default 24h; the fourth daemon goroutine; disabled cleanly when off/misconfigured).
|
||||
- **hub report** (`report.go`): filled the `Backup` + `RestoreTest` stubs (`PBSSnapshot`
|
||||
stays a Phase-B stub); collector `BackupReporter`/`RestoreTestReporter` seams. Cross-repo
|
||||
golden updated in BOTH repos (byte-identical) + bidirectional key-set tests for
|
||||
`backups[0]`/`restore_tests[0]`. Hub `handler.go` parses + persists them (report_json; no
|
||||
new columns) and logs a **FAILED restore-test prominently** (the loudest DR signal).
|
||||
- **config** `BackupConfig` (local target, restore storage, restore-test cadence, scratch
|
||||
VMID band 990000–990009 default) + accessors + env overlay + cadence-gated validation.
|
||||
- **`--selftest=backup -vmid N`** (one-shot backup → print the Backup record) and
|
||||
**`--selftest=restore-test [-archive volid]`** (Recover-then restore→boot→verify→teardown,
|
||||
print the RestoreTest record). Standalone on the Proxmox host.
|
||||
|
||||
### Notes
|
||||
- The daemon runs cleanly with the cadence off or misconfigured (logs + disables, never
|
||||
crashes); a leaked scratch guest from a mid-test crash is reaped by `engine.Recover` on
|
||||
restart. `go test -race` covers the new scheduler goroutine.
|
||||
- Slice-3/4/5 exported surfaces, goldens, and adversarial tests intact. Version bumps to
|
||||
**v0.6.0** when Phase B (PBS) lands.
|
||||
|
||||
## v0.5.1 — slice 5 live-validation prep: durable_id mis-id fix + re-mount UUID memory (2026-06-09)
|
||||
|
||||
Two correctness fixes surfaced while preparing the live USB validation on `demo-felhom`
|
||||
|
||||
Reference in New Issue
Block a user