restore-test: verdict is liveness, not start-task exitstatus (v0.7.0)

Fixes the crying-wolf false-fail surfaced by the live hub-enrollment runbook:
PVE's guest-start task exits "WARNINGS: 1" for the benign systemd-nesting
advisory, and WaitTask treated any non-OK exitstatus as failure, so the verdict
was decided by an advisory exit code before the real boot check ran. Every
modern-distro restore-test reported pass:false.

- proxmox.WaitOptions.AllowWarnings (opt-in; default keeps all callers strict)
- restore-test start step accepts warnings, surfaces them, verdict stays waitRunning
- RestoreTestResult.StartWarnings/.WarningsRecognized + version-free "enable
  nesting" recognizer (can't rot back at systemd 258+); GuestAPI.TaskLogTail
- hub.RestoreTest.warnings/.warnings_recognized wire fields (consumed by hub v0.7.5)
- scheduler logs clean / passed-with-recognized / passed-with-unrecognized warnings
- tests: WaitTask warnings matrix; restore-test pass/fail-on-liveness; version-free
  regression guard (systemd 256-300)

Single agent bump 0.6.0 -> 0.7.0 covering the agent half of both task phases.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-09 19:30:03 +02:00
parent 7eea638b92
commit 6e86483185
13 changed files with 395 additions and 126 deletions
+15
View File
@@ -3,6 +3,7 @@ package proxmox
import (
"context"
"fmt"
"strings"
"time"
)
@@ -42,6 +43,14 @@ type WaitOptions struct {
// Timeout bounds the whole wait (default 10m). Restore/vzdump can be slow;
// callers may raise it. A zero/elapsed context deadline also stops the wait.
Timeout time.Duration
// AllowWarnings accepts a task that completes with a "WARNINGS: N" exitstatus as
// success (returning the TaskStatus with ExitStatus intact, nil error), instead of
// the default hard failure. Opt-in PER CALL — the default (false) keeps every existing
// caller strict, because vzdump/restore/destroy warnings can be meaningful. Only the
// restore-test's guest-start step opts in (a start advisory like the systemd-nesting
// notice must not false-fail a guest that actually boots; doc 03 §8). A non-WARNINGS
// non-OK exit is still a *TaskError regardless of this flag.
AllowWarnings bool
}
func (o WaitOptions) withDefaults() WaitOptions {
@@ -135,6 +144,12 @@ func (c *Client) WaitTask(ctx context.Context, upid string, opts WaitOptions) (T
if st.ExitStatus == "OK" {
return st, nil
}
// Warnings-accepted path (opt-in): a "WARNINGS: N" exit is returned as success with
// ExitStatus intact, so the caller can fetch/surface the warning text from the log
// without the test/op failing on an advisory. Any other non-OK exit still fails.
if opts.AllowWarnings && strings.HasPrefix(st.ExitStatus, "WARNINGS") {
return st, nil
}
tail, _ := c.TaskLogTail(ctx, upid, 20) // best-effort
return st, newTaskError(upid, st.ExitStatus, tail)
}