hub v0.72.0 — R-70 + R-71c: offsite delivery-state detector, card, stuck event, R-39(a)-guarded self-heal restage
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NKSN3gSg4TKVBBqkwW2djR
This commit is contained in:
@@ -306,6 +306,11 @@ func main() {
|
||||
// still renders, but saving with offsite enabled returns "not configured".
|
||||
var offsiteBoxChecker *monitor.OffsiteBoxChecker
|
||||
var pbsdrBoxChecker *monitor.PBSDRBoxChecker // R-5 v0.65.0: PBS-DR datastore fill (constructed with the tenantsync client below)
|
||||
// R-71c: the delivery checker's self-heal invokes the SAME Re-issue path the operator button
|
||||
// uses (webServer satisfies monitor.OffsiteReissuer). Wired ONLY when the provisioner exists —
|
||||
// a heal that cannot actually restage must never run (it would emit a restaged event for a
|
||||
// silent no-op: ReissueOffsiteForCustomer returns nil when offsite is unconfigured).
|
||||
var offsiteHealReissuer monitor.OffsiteReissuer
|
||||
if tok := os.Getenv("HETZNER_TOKEN"); tok != "" {
|
||||
poolBoxID, _ := strconv.ParseInt(os.Getenv("HETZNER_POOL_BOX_ID"), 10, 64)
|
||||
location := os.Getenv("HETZNER_LOCATION")
|
||||
@@ -317,6 +322,7 @@ func main() {
|
||||
API: client, Store: dataStore, Scanner: offsite.SSHHostKeyScanner{}, PoolBoxID: poolBoxID, Location: location, Logger: logger,
|
||||
})
|
||||
logger.Printf("[INFO] Offsite provisioning enabled (pool_box=%d, location=%s)", poolBoxID, location)
|
||||
offsiteHealReissuer = webServer // R-71c heal armed (provisioner present)
|
||||
// R-5 (v0.64.0): the pool-box aggregate checker shares the SAME client + pool box id (GET-only).
|
||||
// It needs a valid box id to poll; without one, the aggregate stays unconfigured.
|
||||
if poolBoxID != 0 {
|
||||
@@ -544,6 +550,11 @@ func main() {
|
||||
// (90/95% of quota_gb) + staleness (enabled+escrowed but no run >48h — the silently-stuck detector;
|
||||
// run FAILURES already alert via backup_failed). Nil-safe on pre-v0.109 reports. Same sweep.
|
||||
offsiteChecker := monitor.NewOffsiteChecker(dataStore, 0, dispatcher.ProcessEvent, logger)
|
||||
// R-70 + R-71c: the delivery-state checker — surfaces the burned-credential shape as
|
||||
// offsite_delivery_stuck (warning, 24h/customer) and self-heals it via the Re-issue path
|
||||
// (offsite_credential_restaged, one restage/customer/24h, R-39(a)-guarded). Cooldowns are
|
||||
// durable (events table), so a hub restart neither floods nor silently re-heals.
|
||||
offsiteDeliveryChecker := monitor.NewOffsiteDeliveryChecker(dataStore, offsiteHealReissuer, dispatcher.ProcessEvent, logger)
|
||||
go func() {
|
||||
ticker := time.NewTicker(60 * time.Second)
|
||||
defer ticker.Stop()
|
||||
@@ -561,6 +572,7 @@ func main() {
|
||||
hostMgmtPlaneChecker.Check()
|
||||
hostOOBChecker.Check()
|
||||
offsiteChecker.Check()
|
||||
offsiteDeliveryChecker.Check()
|
||||
if offsiteBoxChecker != nil {
|
||||
offsiteBoxChecker.Check() // R-5: restic pool-box aggregate (fetch-throttled internally)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user