agent v0.33.0: C1 net — pre-start self-heal hook + decommission mp-delete

Pre-start PVE hookscript (internal/guesthook) creates host-root placeholders for
absent bind-mount sources so the guest always boots (fail-closed); decommission
now pct set --delete's the dead mp (GuestBinder.DetachBind) so a missing source
can't brick the next reboot (B3 C1 bug). Non-hollow tests + companions. Installed
+ registered per-guest by the provision back-half. Transitional ahead of the
intermediary-mount re-architecture which makes C1 structural.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-15 16:11:10 +02:00
parent 2a4affc3a8
commit 44cdf82631
11 changed files with 490 additions and 3 deletions
+31 -1
View File
@@ -29,6 +29,7 @@ import (
"gitea.dooplex.hu/admin/felhom-agent/internal/config"
"gitea.dooplex.hu/admin/felhom-agent/internal/desired"
"gitea.dooplex.hu/admin/felhom-agent/internal/escrow"
"gitea.dooplex.hu/admin/felhom-agent/internal/guesthook"
"gitea.dooplex.hu/admin/felhom-agent/internal/hub"
"gitea.dooplex.hu/admin/felhom-agent/internal/lanresolver"
"gitea.dooplex.hu/admin/felhom-agent/internal/localapi"
@@ -43,9 +44,38 @@ import (
// version is the agent version. Overridable at build time with
// -ldflags "-X main.version=<v>"; defaults to the in-repo CHANGELOG version.
var version = "0.32.0"
var version = "0.33.0"
// runGuestHook is the PVE pre-start hook body (`felhom-agent guest-hook <vmid> <phase>`). On the
// pre-start phase it creates placeholder dirs for any absent bind-mount source so the guest always boots
// (the C1 net). It ALWAYS returns cleanly (exit 0) — a hook must never block a guest start. Heal output
// is written to stderr (PVE captures hook output into the task log).
func runGuestHook(args []string) {
if len(args) < 2 {
return
}
vmid, phase := args[0], args[1]
if phase != guesthook.PhasePreStart {
return
}
created, err := guesthook.Heal("/etc/pve/lxc/" + vmid + ".conf")
if len(created) > 0 {
fmt.Fprintf(os.Stderr, "felhom-agent guest-hook: vmid %s pre-start — created %d placeholder(s) for absent drive(s): %v\n", vmid, len(created), created)
}
if err != nil {
fmt.Fprintf(os.Stderr, "felhom-agent guest-hook: vmid %s heal error (boot continues): %v\n", vmid, err)
}
}
func main() {
// Pre-start self-heal hook entrypoint. PVE invokes the registered hookscript as
// `<bin> guest-hook <vmid> <phase>`. Handled BEFORE flag parsing — it takes positional args, must be
// fast, needs no config/daemon/network, and must NEVER exit nonzero (a hook that fails would block
// the guest start). See internal/guesthook (the C1 net).
if len(os.Args) >= 2 && os.Args[1] == "guest-hook" {
runGuestHook(os.Args[2:])
return
}
var (
cfgPath string
selftest selftestFlag