carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package console
2
3import (
4 "context"
5 "sort"
6 "time"
7
8 "github.com/carlosframework/platform/internal/status"
9)
10
11// updatesEnforced is §4.4's roll-order gate: pin, manual and major may be
12// turned on only while every box in the deployment reports a binary that
13// applies them and protects the builds they name from retention. The housekeeper
14// duty moves between boxes, so one old box anywhere could prune a pinned
15// build. Expected boxes are the edges records and active fleet members, as for
16// the GeoIP rollout verdict (geoipInventory); a box that is expected and has
17// no fresh heartbeat blocks, and so does an incomplete read. Unlike the GeoIP
18// verdict, an incomplete heartbeat read blocks here too, and so do an
19// inventory that found no box at all and a fleet registry that was never
20// read (unset, absent, or failing): a gate that has not seen every box
21// cannot vouch for every box.
22//
23// The blocking lines name platform box labels and fleet names. They are
24// operator detail, logged by the doors and never shown to app members.
25func (s *Server) updatesEnforced(ctx context.Context) (ok bool, blocking []string, err error) {
26 inv, err := s.geoipInventory(ctx)
27 if err != nil {
28 return false, nil, err
29 }
30 now := time.Now()
31 keys := map[geoipBoxKey]bool{}
32 for k := range inv.expected {
33 keys[k] = true
34 }
35 for k, b := range inv.boxes {
36 if !status.BoxStale(b, now, status.SnapshotPeriod) {
37 keys[k] = true
38 }
39 }
40 for k := range keys {
41 b, seen := inv.boxes[k]
42 switch {
43 case !seen:
44 blocking = append(blocking, k.String()+": no heartbeat")
45 case status.BoxStale(b, now, status.SnapshotPeriod):
46 blocking = append(blocking, k.String()+": no heartbeat since "+b.GeneratedAt.UTC().Format(time.RFC3339))
47 case b.Metrics == nil || b.Metrics.UpdateSettings < status.UpdateSettingsProtocol:
48 blocking = append(blocking, k.String()+": runs a binary that does not apply update settings")
49 }
50 }
51 if len(keys) == 0 {
52 blocking = append(blocking, "no box was found to report a binary")
53 }
54 // An unset or absent registry is a fleet list nobody read, not an empty
55 // one (Astra r1 #1): the GeoIP verdict may read it as platform-only, but
56 // this gate cannot vouch for fleet boxes it never listed. A registry that
57 // failed to open or list also leaves expectedComplete false; this one
58 // line, with the reason, covers both.
59 if !inv.fleetsListed {
60 blocking = append(blocking, "the fleet registry could not be read ("+inv.fleetsUnread+"), so no fleet box was checked")
61 }
62 if (inv.fleetsListed && !inv.expectedComplete) || !inv.heartbeatsComplete {
63 blocking = append(blocking, "the list of boxes could not be read in full")
64 }
65 sort.Strings(blocking)
66 return len(blocking) == 0, blocking, nil
67}
68