| 1 | package host |
| 2 | |
| 3 | import ( |
| 4 | "strings" |
| 5 | |
| 6 | "github.com/carlosframework/platform/internal/release" |
| 7 | "github.com/carlosframework/platform/internal/status" |
| 8 | ) |
| 9 | |
| 10 | // systemChannelEnv is the box's platform channel: canary or stable. Set in |
| 11 | // host.env, read through the getenv seam like every other CARLOS_* value; |
| 12 | // the ROOT apply reads it from its own unit environment, never from the |
| 13 | // agent's request (spec §6 step 2). |
| 14 | const systemChannelEnv = "CARLOS_SYSTEM_CHANNEL" |
| 15 | |
| 16 | // A value that is not a channel at all — a typo, a shell that expanded to |
| 17 | // nothing useful, a name with a slash too many — falls back to stable |
| 18 | // rather than travelling into a bucket key and an on-box state file to ask |
| 19 | // for a pointer nobody publishes. It comes back as invalid so the caller |
| 20 | // can say so ONCE: this is read per tick, and a line per tick is a line |
| 21 | // nobody reads. |
| 22 | func systemChannel(getenv func(string) string) (channel, invalid string) { |
| 23 | c := strings.TrimSpace(getenv(systemChannelEnv)) |
| 24 | switch { |
| 25 | case c == "": |
| 26 | return "stable", "" |
| 27 | case !release.ValidChannel(c): |
| 28 | return "stable", c |
| 29 | } |
| 30 | return c, "" |
| 31 | } |
| 32 | |
| 33 | // boxSystemChannel is systemChannel for the caller that has nowhere to log: |
| 34 | // the status tick, which publishes this every five minutes. |
| 35 | func boxSystemChannel(getenv func(string) string) string { |
| 36 | c, _ := systemChannel(getenv) |
| 37 | return c |
| 38 | } |
| 39 | |
| 40 | // systemStateProbe is root's result.json as the heartbeat carries it, or nil |
| 41 | // when this box has never been asked to update. |
| 42 | func systemStateProbe(optDir string) *status.SystemState { |
| 43 | r, err := readSystemResult(optDir) |
| 44 | if err != nil || r == nil { |
| 45 | return nil |
| 46 | } |
| 47 | return &status.SystemState{Channel: r.Channel, Version: r.Version, PromotedAt: r.PromotedAt, Outcome: r.Outcome, Reason: r.Reason, At: r.At} |
| 48 | } |
| 49 | |