6e38e2f921
F2-b: at startup, recover a guest left with a stale vzdump lock by a reboot-during-backup — pct unlock -> delete dangling vzdump snapshot -> start iff onboot, guarded by a no-vzdump-running invariant (fail-safe). New internal/localapi/stalelock.go; proxmox GuestConfig.Lock()/OnBoot(), ListSnapshots, ListRunningTasks, Snapshot type. New narrow sudoers grant FELHOM_STALELOCK (pct unlock) + Critical capability stalelock-unlock. F2-a: EnsureSharedParent only redeployed the boot script when the UNIT differed, so the v0.36.6 make-private fix never reached hosts whose unit was current -> /mnt/felhom-drives stayed in root's shared:1 and doubled every drive bind. New sharedParentInstallStale compares BOTH script and unit. Boot-time-only; never churns the live mount. Both root causes confirmed live on felhom-pve before fixing. Green gate (build/vet/test) all pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0162BnMpUXscPsUB1cU8Tr6K
78 lines
3.1 KiB
Go
78 lines
3.1 KiB
Go
package localapi
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// TestSharedParentInstallStale_ScriptOnlyChangeRedeploys is the F2-a regression proof: when the on-disk
|
|
// UNIT is current but the SCRIPT differs (exactly the v0.36.6 make-private situation), the gate MUST
|
|
// report stale so the corrected script redeploys. The earlier unit-only gate returned false here and
|
|
// left hosts running the pre-fix script that doubled drive binds.
|
|
func TestSharedParentInstallStale_ScriptOnlyChangeRedeploys(t *testing.T) {
|
|
dir := t.TempDir()
|
|
unitPath := filepath.Join(dir, "felhom-shared-parent.service")
|
|
scriptPath := filepath.Join(dir, "felhom-shared-parent.sh")
|
|
|
|
// Unit current, script STALE (a pre-make-private body).
|
|
if err := os.WriteFile(unitPath, []byte(sharedParentUnit), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
staleScript := "#!/bin/sh\nset -e\nmkdir -p /mnt/felhom-drives\nmount --make-shared /mnt/felhom-drives\n"
|
|
if err := os.WriteFile(scriptPath, []byte(staleScript), 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !sharedParentInstallStale(unitPath, scriptPath) {
|
|
t.Fatal("a stale SCRIPT with a current unit must trigger reinstall (F2-a) — gate returned not-stale")
|
|
}
|
|
}
|
|
|
|
// TestSharedParentInstallStale_BothCurrentIsNoop: when both files match what we ship, the gate reports
|
|
// not-stale (the cheap common case — no churn on every reconcile).
|
|
func TestSharedParentInstallStale_BothCurrentIsNoop(t *testing.T) {
|
|
dir := t.TempDir()
|
|
unitPath := filepath.Join(dir, "felhom-shared-parent.service")
|
|
scriptPath := filepath.Join(dir, "felhom-shared-parent.sh")
|
|
if err := os.WriteFile(unitPath, []byte(sharedParentUnit), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(scriptPath, []byte(sharedParentScript), 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if sharedParentInstallStale(unitPath, scriptPath) {
|
|
t.Fatal("both files current must be a no-op; gate reported stale")
|
|
}
|
|
}
|
|
|
|
// TestSharedParentInstallStale_MissingFilesAreStale: a missing unit or script (fresh host) is stale.
|
|
func TestSharedParentInstallStale_MissingFilesAreStale(t *testing.T) {
|
|
dir := t.TempDir()
|
|
unitPath := filepath.Join(dir, "felhom-shared-parent.service")
|
|
scriptPath := filepath.Join(dir, "felhom-shared-parent.sh")
|
|
|
|
if !sharedParentInstallStale(unitPath, scriptPath) {
|
|
t.Fatal("missing files must be stale (fresh install)")
|
|
}
|
|
|
|
// Unit present + current, script missing → still stale.
|
|
if err := os.WriteFile(unitPath, []byte(sharedParentUnit), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !sharedParentInstallStale(unitPath, scriptPath) {
|
|
t.Fatal("a missing script with a current unit must be stale (F2-a)")
|
|
}
|
|
}
|
|
|
|
// TestSharedParentScript_HasMakePrivate is a content guard: the shipped boot script MUST contain the
|
|
// make-private step (the actual fix for the doubling). If a refactor drops it, the parent re-joins
|
|
// root's shared group on boot and binds double again.
|
|
func TestSharedParentScript_HasMakePrivate(t *testing.T) {
|
|
if want := "mount --make-private " + StableParentDir; !strings.Contains(sharedParentScript, want) {
|
|
t.Fatalf("shipped boot script missing %q — the doubling fix would regress", want)
|
|
}
|
|
}
|