carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package rollout
2
3import (
4 "fmt"
5 "strings"
6 "time"
7
8 "github.com/carlosframework/platform/internal/activator"
9 "github.com/carlosframework/platform/internal/rolloutwords"
10 "github.com/carlosframework/platform/internal/status"
11)
12
13// EventCode is a rollout event's stable internal name (spec §9.4). The codes
14// are what the journal and tests key on. The member-facing texts below are
15// worded by internal/rolloutwords, and are approved copy.
16type EventCode string
17
18const (
19 EvSwapping EventCode = "swap.started"
20 EvSwapped EventCode = "swap.done"
21 EvSwapFailed EventCode = "swap.failed"
22 EvSwapDown EventCode = "swap.down"
23 EvCohortHalted EventCode = "cohort.halted"
24 EvFallbackServed EventCode = "fallback.served"
25 EvConfigPending EventCode = "config.pending"
26 EvStagingRefused EventCode = "staging.refused"
27)
28
29// reasonWord turns an attempt's diagnostic text (SwapResult.Reason, an error)
30// into one of status's reason words (status.Reason*, the one vocabulary the
31// events and the status report share), so no free text, which can name paths
32// and internals, reaches a member-facing surface. The raw text goes to the
33// operator log instead. Anything unrecognised is a failed health check: the
34// swap's checks are the health check, the settle and the exit watch, and the
35// health check is the one a spawn or start error also fails.
36func reasonWord(text string) string {
37 t := strings.ToLower(text)
38 switch {
39 case strings.Contains(t, "reused"):
40 return status.ReasonReused
41 case strings.Contains(t, "staging"), strings.Contains(t, "staged"), strings.Contains(t, "digest"):
42 return status.ReasonStaging
43 case strings.Contains(t, "settle"):
44 return status.ReasonSettle
45 case strings.Contains(t, "exited"):
46 return status.ReasonExit
47 }
48 return status.ReasonHealth
49}
50
51func textSwapping(build string, cause activator.Cause) string {
52 return fmt.Sprintf(rolloutwords.EventSwapping, build, rolloutwords.Cause(string(cause)))
53}
54
55// textSwapped carries the retiring generation's drain time (spec §9.4),
56// printed to a tenth of a second.
57func textSwapped(build string, drain time.Duration) string {
58 return fmt.Sprintf(rolloutwords.EventSwapped, build, drain.Round(100*time.Millisecond).String())
59}
60
61// textSwapFailed's reason is a reason word (reasonWord at the emit site),
62// never raw text. It is worded as it is given: mapping it again would fold
63// the closed words into one another (reasonWord("exit") is a health
64// failure).
65func textSwapFailed(build, serving, reason string) string {
66 return fmt.Sprintf(rolloutwords.EventSwapFailed, build, rolloutwords.Reason(reason), serving)
67}
68
69func textSwapDown(build string) string {
70 return fmt.Sprintf(rolloutwords.EventHoldDown, build)
71}
72
73// textCohortHalted names the box (spec §9.4); the event sink already
74// carries the account, the app and the host. reason is a reason word.
75func textCohortHalted(build, box, reason string) string {
76 return fmt.Sprintf(rolloutwords.EventCohortHalted, build, box, rolloutwords.Reason(reason))
77}
78
79func textFallback(failed, good string) string {
80 return fmt.Sprintf(rolloutwords.EventFallbackServed, failed, good)
81}
82
83// textConfigPending's reason is a reason word.
84func textConfigPending(reason string, wait time.Duration) string {
85 return fmt.Sprintf(rolloutwords.EventConfigPending, rolloutwords.Reason(reason), wait.String())
86}
87
88func textStagingRefused(build string) string {
89 return fmt.Sprintf(rolloutwords.EventStagingRefused, build)
90}
91