109dd853a3
- BackupConfig.BackupTarget() defaults whole-guest backup to felhom-pbs (separate hardware = real DR), configurable via backup.local_backup_target; all NewBackupRunner sites route through it. PBS round-trip proven live (snapshot marker + restore-test + pct-restore) before the re-point. - signedjobs DecommissionExecutor + ExecutorChain: makes IntentDecommissioned reachable ONLY via a verified operator signature (keyed by the watchdog's storage durable-id); felhom-opsign builds decommission params from -durable-id. Runner wiring moved below the intent-store open. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
26 lines
1017 B
Go
26 lines
1017 B
Go
package signedjobs
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
)
|
|
|
|
// ExecutorChain dispatches a verified signed op to the first sub-executor that OWNS it. A sub-
|
|
// executor returns ErrNoExecutor for an op class it does not handle; the chain then tries the next.
|
|
// If no sub-executor owns the op, the chain returns ErrNoExecutor so the runner leaves the job
|
|
// queued for a later slice (the same contract a single executor has). The chain adds no policy — the
|
|
// gate has already verified+bound the op before any Execute runs.
|
|
type ExecutorChain []Executor
|
|
|
|
// Execute implements Executor by trying each sub-executor in order.
|
|
func (c ExecutorChain) Execute(ctx context.Context, op string, params json.RawMessage) error {
|
|
for _, e := range c {
|
|
err := e.Execute(ctx, op, params)
|
|
if errorsIs(err, ErrNoExecutor) {
|
|
continue // this sub-executor doesn't own the op — try the next
|
|
}
|
|
return err // owned (handled or failed) — done
|
|
}
|
|
return ErrNoExecutor // no sub-executor owns this op class in this build
|
|
}
|