runs: add non-destructive flag + operator Cancel button
CI / Lint + build + test (push) Successful in 2m5s
Release / release (push) Successful in 3m5s

Non-destructive pre-declares "don't touch the disks" on Start: the
Storage stage skips wipe-probe, badblocks -w, and write-mode fio,
and reports a read-only summary. Runs a new non_destructive column;
threaded through Claim → agent tests.Deps → Storage stage.

Cancel halts an in-flight run. The orchestrator transitions to a
new StateCancelled via TriggerOperatorCancelled (valid from any
active state); the agent's next heartbeat returns cmd=cancel_stage,
which fires a stored CancelFunc on the per-stage context. Stage
subprocesses spawned with exec.CommandContext die with the context,
the agent posts a cancelled outcome, then powers the host off.

Destructive stages mid-run may leave the host in an intermediate
state — the UI confirm dialog warns the operator; recovery is
manual for now.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-04-18 13:01:42 -04:00
parent 2c440fce8a
commit 4524ab8dc0
22 changed files with 434 additions and 230 deletions
+3 -3
View File
@@ -103,7 +103,7 @@ func TestDispatcher_TransitionsToWaitingRebootNoWoL(t *testing.T) {
d, _, runs, hostID, cleanup := setupPickNext(t)
defer cleanup()
ctx := context.Background()
runID, err := runs.Create(ctx, hostID, "deadbeef")
runID, err := runs.Create(ctx, hostID, "deadbeef", false)
if err != nil {
t.Fatalf("create run: %v", err)
}
@@ -141,7 +141,7 @@ func TestDispatcher_FailsStaleHeartbeat(t *testing.T) {
if err := hosts.UpdateLastSeen(ctx, "aa:bb:cc:dd:ee:50", time.Now().UTC().Add(-5*time.Minute)); err != nil {
t.Fatalf("stamp stale: %v", err)
}
runID, err := runs.Create(ctx, hostID, "deadbeef")
runID, err := runs.Create(ctx, hostID, "deadbeef", false)
if err != nil {
t.Fatalf("create run: %v", err)
}
@@ -181,7 +181,7 @@ func TestDispatcher_FailsNeverSeenHost(t *testing.T) {
if err != nil {
t.Fatalf("create host: %v", err)
}
runID, err := runs.Create(ctx, neverID, "deadbeef")
runID, err := runs.Create(ctx, neverID, "deadbeef", false)
if err != nil {
t.Fatalf("create run: %v", err)
}