carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package host
2
3import (
4 "errors"
5 "fmt"
6 "github.com/carlosframework/platform/internal/registry"
7 "log"
8 "path/filepath"
9 "time"
10)
11
12// Frozen from origin/main 34a4328f, internal/host/agent.go. Only names,
13// clock and readiness injection differ, so the oracle cannot drift with
14// the production legacy helpers.
15func fix5MainCheckedRestart(sys unitSystem, optDir string, getenv func(string) string, settled func(rt registry.Route), c rootRestartChecks) func(rt registry.Route) error {
16 return func(rt registry.Route) error {
17 before, err := sys.Show(rt.Unit)
18 if err != nil {
19 log.Printf("adopt: %s: cannot read %s (%v); restart not checked", rt.Host, rt.Unit, err)
20 return sys.TryRestart(rt.Unit)
21 }
22 link := filepath.Join(optDir, "live", rt.Host)
23 if before.ExecPath != link {
24 log.Printf("adopt: binding: %s runs %s, but the unit stamp is on %s; restart not checked", rt.Unit, before.ExecPath, rt.Host)
25 return sys.TryRestart(rt.Unit)
26 }
27 if before.ActiveState != "active" {
28 return sys.TryRestart(rt.Unit) // stopped by an operator: stays a no-op
29 }
30 want, err := filepath.EvalSymlinks(link)
31 if err != nil {
32 return sys.TryRestart(rt.Unit)
33 }
34 if err := sys.TryRestart(rt.Unit); err != nil {
35 return err
36 }
37 timeout := unitSettleTimeout(getenv)
38 err = settleUnit(sys, rt.Unit, before.InvocationID, settleOpts{
39 Timeout: timeout, Poll: 500 * time.Millisecond, Hold: 5 * time.Second,
40 WantDir: filepath.Dir(want), Ready: c.legacyReady(rt),
41 Now: c.now, Sleep: c.sleep})
42 if errors.Is(err, errUnitStopped) {
43 // An operator stopped it between the read above and now. Not a
44 // verdict on the build, and a rollback restart would undo their
45 // stop: same as a unit that was stopped before the restart.
46 log.Printf("adopt: %s: %s was stopped during settle; not judged, not restarted", rt.Host, rt.Unit)
47 return nil
48 }
49 if err == nil {
50 log.Printf("adopt: %s: %s settled on %s", rt.Host, rt.Unit, filepath.Dir(want))
51 // D3 (proofobserve.go): a build that passed the settle check is a
52 // build this box has run well.
53 if settled != nil {
54 settled(rt)
55 }
56 }
57 return err
58 }
59}
60
61// rollbackUnitRestart is D1's rollback restart (release.WithRollbackRestart):
62// the live link already names the restored build; replace whatever is
63// running (a deadline failure can leave the rejected build up) and check
64// the restored build comes up too.
65func fix5MainRollbackRestart(reg *registry.Registry, sys unitSystem, optDir string, getenv func(string) string, c rootRestartChecks) func(host string) error {
66 return func(host string) error {
67 rt, err := reg.Get(host)
68 if err != nil || rt == nil || rt.Unit == "" {
69 return nil
70 }
71 before, _ := sys.Show(rt.Unit)
72 if err := sys.ResetFailed(rt.Unit); err != nil {
73 log.Printf("adopt: %s: reset-failed %s: %v (continuing)", host, rt.Unit, err)
74 }
75 if err := sys.Restart(rt.Unit); err != nil {
76 return err
77 }
78 want, err := filepath.EvalSymlinks(filepath.Join(optDir, "live", host))
79 if err != nil {
80 return err
81 }
82 err = settleUnit(sys, rt.Unit, before.InvocationID, settleOpts{
83 Timeout: unitSettleTimeout(getenv), Poll: 500 * time.Millisecond, Hold: 5 * time.Second,
84 WantDir: filepath.Dir(want), Ready: c.legacyReady(*rt),
85 Now: c.now, Sleep: c.sleep})
86 if errors.Is(err, errUnitStopped) {
87 // The restored build is what the link names; a stop an operator
88 // made while it settled is theirs to keep, not a failed recovery.
89 log.Printf("adopt: %s: %s was stopped during the rollback's settle; not judged, not restarted", host, rt.Unit)
90 return nil
91 }
92 if err != nil {
93 return fmt.Errorf("rollback did not come up either: %w", err)
94 }
95 return nil
96 }
97}
98