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 "context"
5 "errors"
6 "github.com/carlosframework/platform/internal/provision"
7 "os"
8 "path/filepath"
9 "testing"
10 "time"
11
12 "github.com/carlosframework/platform/internal/hostwrite"
13 "github.com/carlosframework/platform/internal/registry"
14 "github.com/carlosframework/platform/internal/release"
15 "github.com/carlosframework/platform/internal/rootstate"
16)
17
18type activationPreflightOwner struct{ calls int }
19
20func (p *activationPreflightOwner) OpenClaimOwners(context.Context, release.Store, ClaimRuntimeResources) (ClaimOwnerBindings, error) {
21 p.calls++
22 return ClaimOwnerBindings{}, os.ErrNotExist
23}
24
25func TestPlan14ActivationNamedUnitPreflight(t *testing.T) {
26 oldOpen, oldShapes := openClaimActivationState, productionClaimUnitShapes
27 t.Cleanup(func() { openClaimActivationState, productionClaimUnitShapes = oldOpen, oldShapes })
28 openClaimActivationState = func(string, bool, bool) (rootstate.Store, error) { return nil, os.ErrNotExist }
29 productionClaimUnitShapes = func() (map[string]claimUnitShape, error) { return map[string]claimUnitShape{}, nil }
30
31 for _, mode := range []string{"agent", "adopt", "instance-control"} {
32 for _, kind := range []string{"named", "backing", "ordinary", "empty"} {
33 t.Run(mode+"/"+kind, func(t *testing.T) {
34 dir := t.TempDir()
35 reg, err := registry.Open(filepath.Join(dir, "registry.db"))
36 if err != nil {
37 t.Fatal(err)
38 }
39 defer reg.Close()
40 row := registry.Route{Host: "console.example", Account: "bab", App: "console", Socket: "/run/console.sock"}
41 if kind == "named" {
42 row.Unit = "console.service"
43 }
44 if kind == "backing" {
45 row.Backing = "unit"
46 }
47 if kind != "empty" {
48 if err := reg.Upsert(row); err != nil {
49 t.Fatal(err)
50 }
51 }
52 p := &activationPreflightOwner{}
53 r := ClaimRuntimeResources{Mode: mode, Registry: reg, DataDir: filepath.Join(dir, "data"), OptDir: filepath.Join(dir, "opt"), UnitsDir: filepath.Join(dir, "units")}
54 _, err = OpenProductionClaimAssembly(t.Context(), release.NewDirStore(filepath.Join(dir, "bucket")), r, p)
55 blocked := !claimNamedUnit4aComplete && (kind == "named" || kind == "backing")
56 if blocked {
57 if !errors.Is(err, hostwrite.ErrUnavailable) || p.calls != 0 {
58 t.Fatalf("preflight=%v provider calls=%d", err, p.calls)
59 }
60 } else if !errors.Is(err, os.ErrNotExist) || p.calls != 1 {
61 t.Fatalf("ordinary construction=%v calls=%d", err, p.calls)
62 }
63 if mode == "instance-control" {
64 p.calls = 0
65 err = migrateClaimJournalsWith(t.Context(), release.NewDirStore(filepath.Join(dir, "bucket")), r, p, true)
66 if blocked && (!errors.Is(err, hostwrite.ErrUnavailable) || p.calls != 0) {
67 t.Fatalf("migration preflight: %v calls=%d", err, p.calls)
68 }
69 if !blocked && (!errors.Is(err, os.ErrNotExist) || p.calls != 1) {
70 t.Fatalf("migration ordinary: %v calls=%d", err, p.calls)
71 }
72 }
73 for _, path := range []string{r.DataDir, r.OptDir, r.UnitsDir} {
74 if _, err := os.Stat(path); !errors.Is(err, os.ErrNotExist) {
75 t.Fatalf("claim state created: %s %v", path, err)
76 }
77 }
78 })
79 }
80 }
81}
82
83func TestPlan14ActivationRejectsHiddenNamedRecords(t *testing.T) {
84 for _, attack := range []string{"omitted", "cleared"} {
85 t.Run(attack, func(t *testing.T) {
86 t.Setenv("CARLOS_REGION", "")
87 store := release.NewDirStore(t.TempDir())
88 plan14PutRecord(t, store, provision.Record{Schema: 1, Host: "console.example", Account: "bab", App: "console", Channel: "stable", Unit: "console.service", CreatedAt: time.Now()})
89 reg := restartTestRegistry(t)
90 if attack == "cleared" {
91 if err := reg.Upsert(registry.Route{Host: "console.example", Account: "bab", App: "console", Socket: "/run/console.sock"}); err != nil {
92 t.Fatal(err)
93 }
94 }
95 for _, mode := range []string{"agent", "instance-control"} {
96 p := &activationPreflightOwner{}
97 dir := t.TempDir()
98 r := ClaimRuntimeResources{Mode: mode, Registry: reg, DataDir: dir, OptDir: dir, UnitsDir: dir}
99 if _, err := OpenProductionClaimAssembly(t.Context(), store, r, p); !errors.Is(err, hostwrite.ErrUnavailable) || p.calls != 0 {
100 t.Fatal("hidden named route entered construction", err, p.calls)
101 }
102 r.Mode = "instance-control"
103 if err := migrateClaimJournalsWith(t.Context(), store, r, p, true); !errors.Is(err, hostwrite.ErrUnavailable) || p.calls != 0 {
104 t.Fatal("hidden named route entered migration", err, p.calls)
105 }
106 }
107 })
108 }
109}
110
111func TestPlan14ActivationRejectsHiddenLocalUnits(t *testing.T) {
112 for _, unit := range []string{"carlos-app@shop.example.service", "console.service", "woodstar.service.d/override.conf"} {
113 for _, attack := range []string{"omitted", "cleared"} {
114 t.Run(unit+"/"+attack, func(t *testing.T) {
115 reg := restartTestRegistry(t)
116 if attack == "cleared" {
117 if err := reg.Upsert(registry.Route{Host: "shop.example", Account: "bab", App: "shop", Socket: "/run/shop.sock"}); err != nil {
118 t.Fatal(err)
119 }
120 }
121 dir := t.TempDir()
122 units := filepath.Join(dir, "units")
123 path := filepath.Join(units, unit)
124 if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
125 t.Fatal(err)
126 }
127 if err := os.WriteFile(path, []byte("[Service]\nExecStart=/opt/carlos/live/shop.example serve\n"), 0644); err != nil {
128 t.Fatal(err)
129 }
130 store := release.NewDirStore(filepath.Join(dir, "bucket"))
131 for _, mode := range []string{"agent", "instance-control"} {
132 p := &activationPreflightOwner{}
133 r := ClaimRuntimeResources{Mode: mode, Registry: reg, DataDir: filepath.Join(dir, "data"), OptDir: filepath.Join(dir, "opt"), UnitsDir: units}
134 if _, err := OpenProductionClaimAssembly(t.Context(), store, r, p); !errors.Is(err, hostwrite.ErrUnavailable) || p.calls != 0 {
135 t.Fatal(err, p.calls)
136 }
137 r.Mode = "instance-control"
138 if err := migrateClaimJournalsWith(t.Context(), store, r, p, true); !errors.Is(err, hostwrite.ErrUnavailable) || p.calls != 0 {
139 t.Fatal(err, p.calls)
140 }
141 for _, path := range []string{r.DataDir, r.OptDir} {
142 if _, err := os.Stat(path); !os.IsNotExist(err) {
143 t.Fatal("created state", path, err)
144 }
145 }
146 }
147 })
148 }
149 }
150}
151