v0.39.0 — DR-recipe completion: live PBS coord + drop role/restic_repo_coord from v1 drive shape
Live PBS coord: new internal/pbs/live_reporter.go (LiveSnapshotReporter implements
hub.PBSReporter via the cheap Client.Snapshots() list with last-known-good fallback,
bounded by an 8s timeout, list-only — never triggers a verify). Closes the gap where
the recipe's pbs block was omitted whenever the verify-loop SnapshotStore was empty
(one-shot collect + the first ~6h after a daemon restart). SnapshotStore.Get added
(per-datastore LKG). Wired into the collector in both runDaemon and runSelftestHub;
the verify loop keeps Recording into the SAME shared store via one hoisted pbsTargets.
v1 host-half drive shape: dropped drives[].role (hub/operator-owned manifest concept,
not host-derivable) and drives[].restic_repo_coord (named a backup tier that doesn't
exist). Drive shape is now {durable_id, mount_path, intent, fs_type?, total_bytes}.
Hub reads drives as json.RawMessage → no hub struct change; goldens re-pinned
byte-identical (agent + hub copies).
Tests: live_reporter_test.go (T1 load-bearing coord-without-verify + T2..T6),
TestDRRecipeHostHalf_V1DriveShape; each companion demonstrated to fail pre-fix then
reverted. go build/vet/test green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -54,7 +54,7 @@ func TestBuildDRRecipeHostHalf(t *testing.T) {
|
||||
t.Errorf("drive %s intent=%q, want enrolled", d.DurableID, d.Intent)
|
||||
}
|
||||
}
|
||||
if d, ok := byDur["uuid:da9e7089"]; !ok || d.Role != "bulk-data" || d.MountPath != "/mnt/felhom-usb" || d.TotalBytes != 931<<30 {
|
||||
if d, ok := byDur["uuid:da9e7089"]; !ok || d.MountPath != "/mnt/felhom-usb" || d.TotalBytes != 931<<30 {
|
||||
t.Errorf("felhom-usb drive wrong: %+v", d)
|
||||
}
|
||||
if _, ok := byDur["uuid:81a26531"]; !ok {
|
||||
@@ -77,6 +77,42 @@ func TestBuildDRRecipeHostHalf_NoPBS(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestDRRecipeHostHalf_V1DriveShape pins the v1 host-half drive shape: a drive object carries ONLY
|
||||
// {durable_id, mount_path, intent, total_bytes} (fs_type is omitempty) — and specifically NEITHER the
|
||||
// dropped "role" NOR "restic_repo_coord" keys. Re-adding either field to DRDrive makes this fail
|
||||
// (the companion: `Role string \`json:"role"\`` reintroduces the "role" key → caught here).
|
||||
func TestDRRecipeHostHalf_V1DriveShape(t *testing.T) {
|
||||
h := BuildDRRecipeHostHalf(
|
||||
nil,
|
||||
[]StorageTarget{
|
||||
{Name: "felhom-usb", Type: StorageTypeUSB, DurableID: "uuid:da9e7089", Role: "bulk-data",
|
||||
MountPath: "/mnt/felhom-usb", TotalBytes: 931 << 30},
|
||||
},
|
||||
nil,
|
||||
)
|
||||
if len(h.Drives) != 1 {
|
||||
t.Fatalf("want 1 drive, got %d", len(h.Drives))
|
||||
}
|
||||
b, err := json.Marshal(h.Drives[0])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var keys map[string]json.RawMessage
|
||||
if err := json.Unmarshal(b, &keys); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, banned := range []string{"role", "restic_repo_coord"} {
|
||||
if _, ok := keys[banned]; ok {
|
||||
t.Errorf("v1 drive must NOT carry %q key (it was dropped); got %s", banned, b)
|
||||
}
|
||||
}
|
||||
for _, want := range []string{"durable_id", "mount_path", "intent", "total_bytes"} {
|
||||
if _, ok := keys[want]; !ok {
|
||||
t.Errorf("v1 drive missing required key %q; got %s", want, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestDRRecipeHostHalf_NoSecrets is the agent-side boundary assertion (the lighter mirror of the
|
||||
// controller's load-bearing boundary test): a fully-populated host-half must carry NO field whose
|
||||
// name smells like a credential. If a future field leaks a key/token/hash in, this fails.
|
||||
@@ -97,8 +133,8 @@ func TestDRRecipeHostHalf_NoSecrets(t *testing.T) {
|
||||
}
|
||||
|
||||
// assertNoSecretKeys walks decoded JSON and fails on any object key matching secretNameRe. Shared by
|
||||
// the agent boundary assertions. (durable_id/repo_id/latest_snapshot_id/restic_repo_coord are
|
||||
// identifiers/coordinates — none match the credential regex.)
|
||||
// the agent boundary assertions. (durable_id/repo_id/latest_snapshot_id are identifiers/coordinates —
|
||||
// none match the credential regex.)
|
||||
func assertNoSecretKeys(t *testing.T, jsonBytes []byte) {
|
||||
t.Helper()
|
||||
var v any
|
||||
|
||||
Reference in New Issue
Block a user