v0.28.0: backup re-target → felhom-pbs (offsite DR) + operator-signed decommission
- 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>
This commit is contained in:
@@ -48,7 +48,7 @@ func run() error {
|
||||
guest = flag.String("guest", "", "target guest_id (\"\" = host-scoped op)")
|
||||
keyID = flag.String("key-id", "", "key id of the signing key (must match a pinned agent signer)")
|
||||
paramsRaw = flag.String("params", "", "op params as JSON (overrides -durable-id/-fstype)")
|
||||
durableID = flag.String("durable-id", "", "for storage_wipe: the DURABLE device id (byid:…|byuuid:…)")
|
||||
durableID = flag.String("durable-id", "", "storage_wipe: the DURABLE device id (byid:…|byuuid:…); decommission: the drive's STORAGE durable-id (e.g. uuid:<fs-uuid>)")
|
||||
fstype = flag.String("fstype", "ext4", "for storage_wipe: the filesystem to mkfs after wipe")
|
||||
keyFile = flag.String("key", "", "operator signing key (ssh private key / sk- key handle) for ssh-keygen -Y sign")
|
||||
ttl = flag.Duration("ttl", 30*time.Minute, "validity window from now (issued_at..expires_at)")
|
||||
@@ -63,16 +63,26 @@ func run() error {
|
||||
return fmt.Errorf("-op, -host, -key-id and -key are required")
|
||||
}
|
||||
|
||||
// Params: explicit JSON, or built from the wipe convenience flags.
|
||||
// Params: explicit JSON, or built from the convenience flags.
|
||||
params := strings.TrimSpace(*paramsRaw)
|
||||
if params == "" {
|
||||
if *op == "storage_wipe" {
|
||||
switch *op {
|
||||
case "storage_wipe":
|
||||
if *durableID == "" {
|
||||
return fmt.Errorf("storage_wipe needs -durable-id (byid:…|byuuid:…) — a path-only binding is refused by the agent")
|
||||
}
|
||||
pj, _ := json.Marshal(map[string]string{"durable_id": *durableID, "fstype": *fstype})
|
||||
params = string(pj)
|
||||
} else {
|
||||
case "decommission":
|
||||
// Decommission binds to the drive's STORAGE durable-id (the watchdog's key, e.g.
|
||||
// "uuid:<fs-uuid>"), NOT the device-level byid:/byuuid: scheme. The agent records this
|
||||
// id into the intent map, so it must match what the storage observer reports.
|
||||
if *durableID == "" {
|
||||
return fmt.Errorf("decommission needs -durable-id (the drive's storage durable-id, e.g. uuid:<fs-uuid>)")
|
||||
}
|
||||
pj, _ := json.Marshal(map[string]string{"durable_id": *durableID})
|
||||
params = string(pj)
|
||||
default:
|
||||
params = "{}"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user