feat(reconcile): re-assert pool membership after restore-over-existing (campaign-2 R2, v0.74.0)
Pool membership is what lets the pool-scoped token reach a guest; pct restore --pool sets it only at CREATE, so a restore over an existing VMID drops the guest from the felhom pool and 403s the next restore-test/DR on VM.Audit. This empty-pool state is the true root cause of the campaign's "R1" (bind-mount restore failing was a symptom — restore-test's existing bind neutralization never ran without config-read). Add Client.PoolAddVMID (PUT /pools, additive+idempotent, Pool.Allocate) and call it in bring-up after liveness when spec.Pool!="" — warn-not-fail on a hiccup (liveness wins). B3 scratch-teardown 403 diagnosed as a cascade (restoretest already passes Pool). Role/ACL untouched. Tests + red-proof. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
@@ -344,6 +344,22 @@ func (e *Engine) runBringUp(ctx context.Context, spec BringUpSpec, res *BringUpR
|
||||
return
|
||||
}
|
||||
|
||||
// 6b. Re-assert pool membership (campaign-2 R2). `pct restore --pool` sets membership only at
|
||||
// CREATE; a restore OVER AN EXISTING VMID (host-loss finale) does not re-apply it, silently
|
||||
// dropping the guest from the pool and 403-ing the NEXT restore-test/DR. Idempotent on a
|
||||
// fresh-VMID restore that already got membership. This runs AFTER liveness is proven: a
|
||||
// pool-add hiccup is surfaced LOUD as a warning but must NOT flip a healthy, running guest's
|
||||
// verdict to fail (membership matters for the next op, not this guest's boot).
|
||||
if spec.Pool != "" {
|
||||
if err := e.api.PoolAddVMID(ctx, spec.Pool, spec.VMID); err != nil {
|
||||
e.logger.Error("bring-up: pool membership re-assert FAILED (next restore-test/DR may 403); guest is healthy",
|
||||
"vmid", spec.VMID, "pool", spec.Pool, "err", err)
|
||||
res.StartWarnings = append(res.StartWarnings, fmt.Sprintf("pool re-assert failed (pool=%s): %v", spec.Pool, err))
|
||||
} else {
|
||||
e.logger.Info("bring-up: pool membership re-asserted", "vmid", spec.VMID, "pool", spec.Pool)
|
||||
}
|
||||
}
|
||||
|
||||
// 7. Success — KEEP the guest; mark the owning entry terminal so Recover ignores it.
|
||||
res.Pass = true
|
||||
res.Verified = "boot+running"
|
||||
|
||||
Reference in New Issue
Block a user