hub v0.65.0 — PBS DR storage visibility (ep0 usage op) + Offsite tab split + dual dashboard gauges (R-5)
Makes PBS DR storage visible like the restic pool box (v0.64.0), differentiated. Scoping
correction: restic = subaccounts on the shared Hetzner Storage Box (Hetzner API); PBS DR =
the felhom-offsite PBS datastore on the ep0 endpoint VM (NO Hetzner API). Option A
(Viktor-ruled): a read-only `usage` op on the felhom-tenantsync ep0 forced command (twin of
fingerprint), polled by a new hub checker on the 15-min throttle. READ-ONLY throughout.
Phase-0 (gate PASSED): on ep0 (PBS 4.2.3), df -B1 --output=size,used,avail <datastore path>
yields bytes (39990112256/7627939840/... ~19%), read-only, existing sudo context, no admin token.
- scripts/felhom-tenantsync.sh -> v1.2.0: read-only `usage` short-circuit (df on the datastore
path), no customer_id, no admin token, NO mutation. + a bash harness proving zero mutation.
- tenantsync.Client.Usage() + BoxUsage; unknown-op -> typed ErrUsageUnsupported (graceful).
- monitor.PBSDRBoxChecker: OffsiteBoxChecker clone over a usageReader seam; 15-min throttle,
cached PBSBoxSnapshot, escalation-only pbsdr_box_fill on the "pbsdr-box" scope (operator only,
no SaveEvent), recovery re-arm. Fill only. THREE states: ok / unavailable (ep0 <=v1.1.0,
neutral no-alert) / degraded (exec failed, keep last).
- config: Alerting.PBSDRBoxFill{Warn,Crit}Percent (80/90); built with the tenantsync client,
60s sweep, SetPBSDRBox. Hub deploy INDEPENDENT of the ep0 update (graceful degradation).
- web: /offsite splits into Restic + PBS DR hash tabs (endpoint cards under PBS DR); PBS panel;
the single dashboard tile becomes two gauges (RESTIC pct.ratio, PBS DR pct / n/a).
- runbook offsite-endpoint.md 10: v1.2.0 update steps (no sudoers/authorized_keys change).
Tests: 10 Go + the harness; 3 red-proofs (usage mutation, escalation-only, unavailable-drives-band)
confirmed red then restored. go build/vet/test + bash -n + hub confirm gate all pass.
This commit is contained in:
@@ -208,6 +208,38 @@ func TestFingerprint_Op(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestUsage_Op (v0.65.0): the read-only usage op parses total/used/avail (bytes).
|
||||
func TestUsage_Op(t *testing.T) {
|
||||
clientPEM, clientSigner := testKeys(t)
|
||||
_, hostSigner := testKeys(t)
|
||||
srv := startTestServer(t, hostSigner, clientSigner,
|
||||
`{"status":"ok","total":39990112256,"used":7628091392,"avail":30686175232}`, "", 0)
|
||||
c := newTestClient(t, srv.addr, hostKeyLine(t, hostSigner), clientPEM)
|
||||
|
||||
u, err := c.Usage(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("Usage: %v", err)
|
||||
}
|
||||
if u.Total != 39990112256 || u.Used != 7628091392 || u.Avail != 30686175232 {
|
||||
t.Errorf("usage = %+v, want total/used/avail 39990112256/7628091392/30686175232", u)
|
||||
}
|
||||
}
|
||||
|
||||
// TestUsage_UnknownOpTypedUnsupported (v0.65.0, graceful degradation): an ep0 still on tenantsync
|
||||
// ≤ v1.1.0 answers `{"op":"usage"}` with its generic `bad_request "unknown op"` (exit 1). That must
|
||||
// map to the typed ErrUsageUnsupported so the PBS checker records "unavailable", not an error.
|
||||
func TestUsage_UnknownOpTypedUnsupported(t *testing.T) {
|
||||
clientPEM, clientSigner := testKeys(t)
|
||||
_, hostSigner := testKeys(t)
|
||||
srv := startTestServer(t, hostSigner, clientSigner,
|
||||
`{"status":"error","code":"bad_request","error":"unknown op"}`, "", 1)
|
||||
c := newTestClient(t, srv.addr, hostKeyLine(t, hostSigner), clientPEM)
|
||||
|
||||
if _, err := c.Usage(context.Background()); !errors.Is(err, ErrUsageUnsupported) {
|
||||
t.Fatalf("an ep0 without the usage op must map to ErrUsageUnsupported, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestErrors_NeverEmbedStdout is the secret-hygiene contract: stdout may carry the token secret,
|
||||
// so NO error path may quote it. A malformed-but-secret-bearing stdout must yield an error that
|
||||
// does not contain the marker bytes. (wgsync quotes stdout in its malformed error — this package
|
||||
|
||||
Reference in New Issue
Block a user