carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1//go:build linux && rootrunner
2
3package host
4
5import (
6 "bytes"
7 "context"
8 "errors"
9 "os"
10 "os/exec"
11 "path/filepath"
12 "testing"
13 "time"
14
15 "github.com/carlosframework/platform/internal/hostwrite"
16 "github.com/carlosframework/platform/internal/registry"
17 "github.com/carlosframework/platform/internal/release"
18 "github.com/carlosframework/platform/internal/rootparticipation"
19 "github.com/carlosframework/platform/internal/rootstate"
20)
21
22func TestPlan14NoCensusReleaseRootRunner(t *testing.T) {
23 if _, err := os.Lstat("/var/lib/carlos-release"); !os.IsNotExist(err) {
24 t.Fatal("existing release state", err)
25 }
26 t.Cleanup(func() { os.RemoveAll("/var/lib/carlos-release") })
27 for _, scenario := range []string{"absent", "empty", "held", "aborted"} {
28 t.Run(scenario, func(t *testing.T) {
29 var s rootstate.Store
30 if scenario != "absent" {
31 var err error
32 s, err = rootstate.Open(rootReleasePrivate, true, false)
33 if err != nil {
34 t.Fatal(err)
35 }
36 defer s.Close()
37 }
38 if scenario == "held" || scenario == "aborted" {
39 unlock, err := s.Lock(t.Context(), "release.lock")
40 if err != nil {
41 t.Fatal(err)
42 }
43 if scenario == "held" {
44 defer unlock()
45 } else {
46 unlock()
47 }
48 }
49 before, _ := os.ReadDir(rootReleasePrivate)
50 for _, flag := range []string{"", "1"} {
51 t.Setenv("CARLOS_HOST_CLAIM", flag)
52 plan14NoCensusCommands(t)
53 ctx, cancel := context.WithTimeout(t.Context(), time.Second)
54 called := false
55 err := withClaimRootRelease(ctx, false, func() (rootstate.Store, error) { t.Fatal("opened root release"); return nil, os.ErrPermission }, func() error { called = true; return nil }, func() (rootparticipation.Ledger, bool, error) { return rootparticipation.Ledger{}, false, nil })
56 if err != nil || !called {
57 t.Fatal("adopt", err, called)
58 }
59 for _, recover := range []bool{false, true} {
60 f := newApplyFixture(t, "canary", "v1.0.0")
61 f.a.participation = nil
62 f.a.rootMoves = rootMovesFloorIdentity
63 if err := f.a.runWithRelease(ctx, recover); err != nil {
64 t.Fatal("system", recover, err)
65 }
66 }
67 cancel()
68 }
69 after, _ := os.ReadDir(rootReleasePrivate)
70 if len(after) != len(before) {
71 t.Fatal("new release file", before, after)
72 }
73 if scenario == "absent" {
74 if _, err := os.Lstat(rootReleasePrivate); !os.IsNotExist(err) {
75 t.Fatal("created release directory", err)
76 }
77 }
78 })
79 }
80}
81
82func plan14NoCensusCommands(t *testing.T) {
83 t.Helper()
84 for _, mode := range []string{"adopt", "apply", "recover"} {
85 dir := t.TempDir()
86 ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second)
87 cmd := exec.CommandContext(ctx, os.Args[0], "-test.run=^TestPlan14NoCensusCommandPayload$")
88 cmd.Env = isolatedAdoptOrderEnv(t, "PLAN14_R10_COMMAND="+mode,
89 "CARLOS_HOST_CLAIM="+os.Getenv("CARLOS_HOST_CLAIM"), "CARLOS_DATA_DIR="+filepath.Join(dir, "data"),
90 "CARLOS_OPT_DIR="+filepath.Join(dir, "opt"), "CARLOS_DEPLOYMENT_BUCKET=", "CARLOS_DEPLOYMENT_DIR="+filepath.Join(dir, "bucket"), "CARLOS_REGION_HA=", "CARLOS_MOVES_PHASE1=")
91 out, err := cmd.CombinedOutput()
92 cancel()
93 if mode == "adopt" {
94 var status *exec.ExitError
95 if !errors.As(err, &status) || status.ExitCode() != 2 || !bytes.Contains(out, []byte("flag provided but not defined: -plan14-no-such-option")) {
96 t.Fatal("adopt did not reach ordinary argument handling", err, string(out))
97 }
98 } else if err != nil {
99 t.Fatal(mode, err, string(out))
100 }
101 }
102}
103
104func TestPlan14NoCensusCommandPayload(t *testing.T) {
105 switch os.Getenv("PLAN14_R10_COMMAND") {
106 case "adopt":
107 RunAdopt([]string{"-plan14-no-such-option"})
108 case "apply":
109 RunSystemApply(nil)
110 case "recover":
111 RunSystemApply([]string{"-recover"})
112 default:
113 t.Fatal("fixture only")
114 }
115}
116
117func TestPlan14PendingAcquisitionStartupRootRunner(t *testing.T) {
118 if err := os.Mkdir("/var/lib/carlos-release", 0700); err != nil {
119 t.Fatal(err)
120 }
121 t.Cleanup(func() { os.RemoveAll("/var/lib/carlos-release") })
122 for _, mode := range []string{"instance-control", "system"} {
123 t.Run(mode, func(t *testing.T) {
124 t.Setenv("PLAN14_R10_ACQUISITION", mode)
125 runServingParkPeerNamespace(t, false, false, "seed-construction")
126 })
127 }
128}
129
130func TestPlan14AcquisitionCrashPayload(t *testing.T) {
131 if os.Getenv("PLAN14_R10_CRASH") != "1" {
132 t.Fatal("fixture only")
133 }
134 s, err := rootstate.Open(rootparticipation.Namespace, false, false)
135 if err != nil {
136 t.Fatal(err)
137 }
138 l := rootparticipation.Ledger{State: s}
139 if err := l.Acquire(t.Context(), func() error { os.Exit(0); return nil }); err != nil {
140 t.Fatal(err)
141 }
142 t.Fatal("did not die at durable acquisition")
143}
144
145func plan14PendingAcquisition(t *testing.T, opt, deployment string) {
146 cmd := exec.Command(os.Args[0], "-test.run=^TestPlan14AcquisitionCrashPayload$")
147 cmd.Env = append(os.Environ(), "PLAN14_R10_CRASH=1")
148 if out, err := cmd.CombinedOutput(); err != nil {
149 t.Fatal(string(out), err)
150 }
151 s, err := rootstate.Open(rootparticipation.Namespace, false, false)
152 if err != nil {
153 t.Fatal(err)
154 }
155 defer s.Close()
156 l := rootparticipation.Ledger{State: s}
157 if _, err := l.Census(); !errors.Is(err, rootparticipation.ErrUnavailable) {
158 t.Fatal("pending acquisition admitted", err)
159 }
160 c, err := l.RecoveryCensus()
161 if err != nil || c.Pending != "acquisition" {
162 t.Fatal(c, err)
163 }
164 t.Setenv("CARLOS_DEPLOYMENT_BUCKET", deployment)
165 id, required, err := rootMovesFloorIdentity()
166 if err != nil || !required {
167 t.Fatal("floor identity dead end", required, err)
168 }
169 t.Setenv("CARLOS_DEPLOYMENT_BUCKET", "")
170 if os.Getenv("PLAN14_R10_ACQUISITION") == "system" {
171 f := newApplyFixture(t, "canary", "v1.0.0")
172 f.a.optDir = opt
173 f.a.dataDir = "/data"
174 f.a.rootMoves = func() (rootFloorIdentity, bool, error) { return id, true, nil }
175 f.a.participation = nil
176 if err := f.a.runWithRelease(t.Context(), true); err != nil {
177 t.Fatal("system recovery entrypoint", err)
178 }
179 if _, err := l.Census(); err != nil {
180 t.Fatal("acquisition not settled", err)
181 }
182 }
183}
184
185func TestPlan14RetiredInstallationStartupRootRunner(t *testing.T) {
186 if err := os.Mkdir("/var/lib/carlos-release", 0700); err != nil {
187 t.Fatal(err)
188 }
189 t.Cleanup(func() { os.RemoveAll("/var/lib/carlos-release") })
190 for _, mode := range []string{"complete", "interrupted"} {
191 t.Run(mode, func(t *testing.T) {
192 t.Setenv("PLAN14_R10_RETIRED", mode)
193 runServingParkPeerNamespace(t, false, false, "seed-construction")
194 })
195 }
196}
197
198func TestPlan14RetiredMigrationPayloadRootRunner(t *testing.T) {
199 testRootMigrationBootstrap(t, true, false)
200}
201
202func TestPlan14LocalBackingStateRootRunner(t *testing.T) {
203 if err := os.Mkdir("/var/lib/private", 0700); err == nil {
204 t.Cleanup(func() { os.Remove("/var/lib/private") })
205 } else if !os.IsExist(err) {
206 t.Fatal(err)
207 }
208 for _, dir := range []string{"/var/lib/carlos-app", "/var/lib/private/carlos-app"} {
209 t.Run(dir, func(t *testing.T) {
210 if err := os.Mkdir(dir, 0755); err != nil {
211 t.Fatal("existing backing state", err)
212 }
213 t.Cleanup(func() { os.RemoveAll(dir) })
214 if err := os.Mkdir(filepath.Join(dir, "hidden.example"), 0700); err != nil {
215 t.Fatal(err)
216 }
217 reg := restartTestRegistry(t)
218 for _, attack := range []string{"omitted", "cleared"} {
219 if attack == "cleared" {
220 if err := reg.Upsert(registry.Route{Host: "hidden.example", Account: "bab", App: "app", Socket: "/run/hidden.sock"}); err != nil {
221 t.Fatal(err)
222 }
223 }
224 p := &activationPreflightOwner{}
225 scratch := t.TempDir()
226 r := ClaimRuntimeResources{Mode: "instance-control", Registry: reg, DataDir: scratch, OptDir: scratch, UnitsDir: scratch}
227 store := release.NewDirStore(t.TempDir())
228 if _, err := OpenProductionClaimAssembly(t.Context(), store, r, p); !errors.Is(err, hostwrite.ErrUnavailable) || p.calls != 0 {
229 t.Fatal("local backing omitted", attack, err, p.calls)
230 }
231 if err := migrateClaimJournalsWith(t.Context(), store, r, p, true); !errors.Is(err, hostwrite.ErrUnavailable) || p.calls != 0 {
232 t.Fatal("migration backing omitted", attack, err, p.calls)
233 }
234 }
235 })
236 }
237}
238