Files
felhom-agent/REPORT.md
T

4.6 KiB

REPORT — agent v0.51.0: local vzdump retention default (--prune-backups keep-last=3)

Date: 2026-06-30 Task: TASK.md — local vzdump retention default. The preventive counterpart to the hub's host_disk (v0.23.0) + storage_fill (v0.25.0) detectors — completing the disk-pressure arc.

Baseline

value
felhom-agent v0.50.0 → v0.51.0
Commits 06e0bc9 (agent) · felhom.eu fdcbc04 (host-install seed)
Deployed felhom-agent 0.51.0 on felhom-pve (prior binary backed up .bak-0.50.0); clean restart 46/46 caps
VzdumpOptions prune passthrough addedVzdumpOptions.PruneBackups → PVE --prune-backups on the vzdump POST

What changed

The agent's periodic local whole-guest vzdump now prunes its own old archives, so a box can't refill its own root via its own backups (the felhom-pve incident's root cause — that vzdump carried no retention).

  • internal/proxmox/mutate.go: VzdumpOptions.PruneBackups--prune-backups (vmid+storage scoped, so PVE prunes only THIS guest's archives on THIS storage).
  • internal/backup/runner.go: NewBackupRunner gains retention; localPruneSpec applies it ONLY when the target is a non-PBS storage (resolved via ListStorage). Fail-safe: an unconfirmable target type (lookup error / not found) SKIPS pruning rather than risk pruning PBS. Only the periodic local-API runner sets retention; restore-test/selftest runners pass "".
  • internal/config/config.go: backup.local_backup_retention with KeepLast() clamped ≥1 (0/unset/negative → default 3) + PruneBackupsSpec()keep-last=N. Wired into the local-API runner.
  • Seeding: felhom.eu scripts/felhom-host-install.sh seeds local_backup_retention: 3; the code default also protects any box where it's unset (KeepLast → 3) from day 0.
  • F2-b stale-vzdump-lock recovery untouched.

Tests — go build ./... && go vet ./... && go test ./... GREEN (Linux build server)

  • flag-present — a local-target backup carries --prune-backups keep-last=3; companion: a no-retention runner emits NO prune option (dumps would accumulate).
  • PBS never pruned (scope) — a PBS target gets no prune; companion: the same retention on a local target IS applied (the gate keys on storage type, not luck). Plus fail-safe-on-unknown-target.
  • clampLocalBackupRetention 0/negative/unset → KeepLast() ≥1 (default 3); a no-clamp impl emitting keep-last=0 would prune the fresh backup → FAILS the ≥1 assertion.

Live validation (felhom-pve, real backups — demo dumps expendable)

Triggered the agent's local whole-guest backup of guest 9201 via the local-API POST /backup (the exact path the controller's periodic backup uses; the retention-enabled runner). Pre-state: local held 2 archives for 9201 (the host_disk task had already pruned the original ~13 to 2), PBS held 8 snapshots, root 24% used.

  • Backup #1 → local count 2 → 3 (no deletion yet; 3 ≤ keep-last=3 — the prune flag is exercised but retains all 3).
  • Each subsequent backup → prune fired, local count held at 3 while the retention window slid (the oldest rotates out as a new one lands):
    • after #1: …10_07_19, …11_22_20, …19_45_54
    • after #2: …11_22_20, …19_45_54, …19_51_07 (…10_07_19 pruned)
    • after a further: …19_45_54, …19_51_07, …19_57_03 (…11_22_20 pruned) Count never exceeded 3 despite repeated backups (the old no-retention behaviour grew to ~13/18).
  • The real PVE command carried the flag (from the vzdump task log): vzdump 9201 --mode snapshot --storage local --compress zstd --prune-backups 'keep-last=3' --notes-template 'felhom local-api'
  • PBS untouched: felhom-pbs still 8 snapshots for 9201 (the per-run flag never touched the offsite repo). Root stayed bounded (24% → 31%, not growing unbounded).

This demonstrates the retention working on real data: repeated local backups stay bounded at keep-last=3 (oldest rotates out) instead of accumulating, and PBS is never pruned.

Observations

  • The disk-pressure arc is now complete: detectors (hub host_disk v0.23.0 + storage_fill v0.25.0) + preventive (this agent-side local-vzdump retention). A box can no longer silently refill its own root via its own backups, and if any storage still fills, the operator is paged.
  • Remaining disk follow-ons (not blockers): thin-pool metadata exhaustion alerting and per-storage-type thresholds (both noted in the storage_fill report).

No secrets. Demo backup archives are expendable; PBS offsite retention is a separate lifecycle (untouched).