hub v0.130.0: OS updates, guest fast lane — rings, per-box switch, OS releases approved from ring 0, os-report, os_update desired block
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
@@ -25,6 +25,7 @@ import (
|
||||
"gitea.dooplex.hu/admin/felhom-hub/internal/offsite"
|
||||
"gitea.dooplex.hu/admin/felhom-hub/internal/offsiteheal"
|
||||
"gitea.dooplex.hu/admin/felhom-hub/internal/offsitekeys"
|
||||
"gitea.dooplex.hu/admin/felhom-hub/internal/osupdates"
|
||||
"gitea.dooplex.hu/admin/felhom-hub/internal/pbsdrheal"
|
||||
"gitea.dooplex.hu/admin/felhom-hub/internal/poke"
|
||||
"gitea.dooplex.hu/admin/felhom-hub/internal/store"
|
||||
@@ -384,6 +385,57 @@ func main() {
|
||||
// unconfigured or the customer has no offsite tier.
|
||||
apiHandler.SetOffsiteReissuer(webServer.ReissueOffsiteForCustomer)
|
||||
|
||||
// OS updates, guest fast lane (hub v0.130.0, `11` §8 step 2). A release is approved when every ring-0 box runs the
|
||||
// set, healthy, for OS_APPROVE_AFTER (default 24h) and through OS_APPROVE_NIGHTS night runs (default 1) — the
|
||||
// ruled "1–2 day wait". Either override is a TEST configuration and is logged loudly.
|
||||
osSvc := &osupdates.Service{Store: dataStore, Emit: dispatcher.ProcessEvent, Logger: logger,
|
||||
ApproveAfter: 24 * time.Hour, NightsRequired: 1,
|
||||
Bump: func(hostID string) {
|
||||
if _, err := dataStore.BumpHostDesired(hostID); err != nil {
|
||||
logger.Printf("[WARN] osupdates: bump desired for %s: %v", hostID, err)
|
||||
}
|
||||
}}
|
||||
if v := os.Getenv("OS_APPROVE_AFTER"); v != "" {
|
||||
if d, derr := time.ParseDuration(v); derr == nil && d >= 0 {
|
||||
osSvc.ApproveAfter = d
|
||||
logger.Printf("[WARN] OS_APPROVE_AFTER=%s — OS releases approve after %s instead of 24h (TEST CONFIGURATION)", v, d)
|
||||
} else {
|
||||
logger.Printf("[ERROR] OS_APPROVE_AFTER=%q invalid — keeping 24h", v)
|
||||
}
|
||||
}
|
||||
if v := os.Getenv("OS_APPROVE_NIGHTS"); v != "" {
|
||||
if n, nerr := strconv.Atoi(v); nerr == nil && n >= 0 {
|
||||
osSvc.NightsRequired = n
|
||||
logger.Printf("[WARN] OS_APPROVE_NIGHTS=%s — OS releases need %d night run(s) instead of 1 (TEST CONFIGURATION)", v, n)
|
||||
} else {
|
||||
logger.Printf("[ERROR] OS_APPROVE_NIGHTS=%q invalid — keeping 1", v)
|
||||
}
|
||||
}
|
||||
logger.Printf("[INFO] osupdates: approval rule = every ring-0 box healthy for %s and %d night run(s)", osSvc.ApproveAfter, osSvc.NightsRequired)
|
||||
apiHandler.SetOSUpdateService(osSvc)
|
||||
webServer.SetOSUpdateAdmin(osSvc)
|
||||
go func() {
|
||||
tk := time.NewTicker(60 * time.Second)
|
||||
defer tk.Stop()
|
||||
last := ""
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-tk.C:
|
||||
st, err := osSvc.Evaluate()
|
||||
if err != nil {
|
||||
logger.Printf("[WARN] osupdates: evaluate: %v", err)
|
||||
continue
|
||||
}
|
||||
if msg := st.Fingerprint + "|" + st.Waiting; msg != last {
|
||||
last = msg
|
||||
logger.Printf("[INFO] osupdates: candidate %s (%d packages, first seen %s): %s", st.Fingerprint, st.Packages, st.FirstSeen.UTC().Format(time.RFC3339), map[bool]string{true: "approved / nothing to wait for", false: "waiting — " + st.Waiting}[st.Waiting == ""])
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Decision 69 (v0.127.0): the off-site KEY REGISTRAR. The box sends its public key; the hub writes it
|
||||
// into the sub-account's authorized_keys pinned append-only; the daily check reads every file.
|
||||
if offsiteKeyReady {
|
||||
|
||||
Reference in New Issue
Block a user