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 "context"
7 "crypto/ed25519"
8 "encoding/base64"
9 "os"
10 "path/filepath"
11 "testing"
12
13 "github.com/carlosframework/platform/internal/release"
14)
15
16func TestPlan14RootFloorHealthyAdoptRootRunner(t *testing.T) {
17 scratch := generationRootRunnerDir(t)
18 t.Setenv("TMPDIR", scratch)
19 for _, healthy := range []bool{false, true} {
20 t.Run(map[bool]string{false: "failed health", true: "healthy"}[healthy], func(t *testing.T) {
21 f, _ := applyHappyVersion(t, "v2.0.0")
22 f.answer["units:"+filepath.Join(f.a.stagingDir(), "carlos")] += " data-instances.mount"
23 for path := f.a.optDir; path != scratch; path = filepath.Dir(path) {
24 if err := os.Chmod(path, 0755); err != nil {
25 t.Fatal(err)
26 }
27 }
28 t.Setenv("CARLOS_RELEASE_PUBKEY", base64.StdEncoding.EncodeToString(f.pub))
29 id := rootFloorIdentity{"deploy", "box", "en"}
30 f.a.rootMoves = func() (rootFloorIdentity, bool, error) { return id, true, nil }
31 raw, etag, err := f.store.Get(t.Context(), release.SystemPointerKey("router", "stable"))
32 if err != nil {
33 t.Fatal(err)
34 }
35 var p release.SystemPointer
36 if err := release.VerifyRootEnvelope(f.pub, raw, &p); err != nil {
37 t.Fatal(err)
38 }
39 p.Current.ReleaseTag = "v2.0.0"
40 p.Current.MovesProtocol = 1
41 wire, err := release.SignRootEnvelope(release.RootSigner(f.priv), p)
42 if err != nil {
43 t.Fatal(err)
44 }
45 if _, err := f.store.Put(t.Context(), release.SystemPointerKey("router", "stable"), wire, etag); err != nil {
46 t.Fatal(err)
47 }
48 rootFloorSignRunnerBytes(t, f.a.optDir, systemBinaryPath(f.a.optDir), "v1.0.0", []byte("#!/bin/sh\necho carlos v1.0.0\n"), f.priv)
49 f.answer["version:"+systemPrevPath(f.a.optDir)] = "carlos v1.0.0\n"
50 if !healthy {
51 f.probeErr = os.ErrInvalid
52 }
53 err = f.a.Run(context.Background(), false)
54 floors, e := openRootMovesFloors(f.a.optDir, id, false)
55 if e != nil {
56 t.Fatal(e)
57 }
58 defer floors.close()
59 _, accepted := floors.record(rootFloorAccepted)
60 if healthy {
61 if err != nil || accepted != nil {
62 t.Fatal("healthy apply did not accept", err, accepted)
63 }
64 h, e := floors.healthy()
65 if e != nil || h.Version != "v2.0.0" {
66 t.Fatal("wrong accepted build", h, e)
67 }
68 } else if accepted == nil {
69 t.Fatal("failed health accepted a floor")
70 }
71 })
72 }
73}
74
75func TestPlan14RootFloorUnknownCrashRecoveryRootRunner(t *testing.T) {
76 scratch := generationRootRunnerDir(t)
77 t.Setenv("TMPDIR", scratch)
78 f, _ := applyHappyVersion(t, "v2.0.0")
79 for path := f.a.optDir; path != scratch; path = filepath.Dir(path) {
80 if err := os.Chmod(path, 0755); err != nil {
81 t.Fatal(err)
82 }
83 }
84 f.brokenBox("v2.0.0", "v1.0.0", "v1.0.0")
85 t.Setenv("CARLOS_RELEASE_PUBKEY", base64.StdEncoding.EncodeToString(f.pub))
86 id := rootFloorIdentity{"deploy", "box", "en"}
87 f.a.rootMoves = func() (rootFloorIdentity, bool, error) { return id, true, nil }
88 rootFloorSignRunnerBytes(t, f.a.optDir, systemBinaryPath(f.a.optDir), "v2.0.0", []byte("#!/bin/sh\nexit 99\n"), f.priv)
89 rootFloorSignRunnerBytes(t, f.a.optDir, systemPrevPath(f.a.optDir), "v1.0.0", []byte("#!/bin/sh\necho carlos v1.0.0\n"), f.priv)
90 delete(f.answer, "version:"+systemBinaryPath(f.a.optDir))
91 f.a.openStore = func(context.Context) (release.Store, ed25519.PublicKey, error) {
92 t.Fatal("offline recovery opened provider")
93 return nil, nil, os.ErrPermission
94 }
95 restored, err := f.a.recoverIfNeeded(t.Context())
96 if err != nil || !restored {
97 t.Fatal("unknown-history restore failed", restored, err)
98 }
99 b, err := readRootFloorBinary(f.a.optDir, systemBinaryPath(f.a.optDir))
100 if err != nil || b.Version != "v1.0.0" {
101 t.Fatal("prev not restored", b, err)
102 }
103 if f.result() == nil || f.result().Outcome != systemOutcomeRolledBack {
104 t.Fatal("recovery did not finish", f.result())
105 }
106 if !f.called("systemctl restart --no-block " + systemEdgeUnit) {
107 t.Fatal("recovery did not schedule edge", f.calls)
108 }
109}
110