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
2
3package host
4
5import (
6 "context"
7 "encoding/json"
8 "github.com/carlosframework/platform/internal/provision"
9 "os"
10 "strings"
11 "testing"
12 "time"
13
14 "github.com/carlosframework/platform/internal/hostbox"
15 "github.com/carlosframework/platform/internal/hostguard"
16 "github.com/carlosframework/platform/internal/registry"
17)
18
19func TestPlan14BoundUnitInputs(t *testing.T) {
20 for _, unit := range []string{"console.service", "woodstar-atbridge.service", "carlos-app@shop.example.service"} {
21 t.Run(unit, func(t *testing.T) {
22 f, _, _ := generationLaunchFixture(t)
23 b, _, shape := plan14UnitBindingFixture(t, unit, "", "")
24 if unit == "woodstar-atbridge.service" {
25 shape.Addr = ""
26 shape.Socket = "/run/carlos/woodstar-atbridge.sock"
27 }
28 if unit == "carlos-app@shop.example.service" {
29 shape.Backing = "unit"
30 }
31 in, err := f.root.Guard.Root.Installation(t.Context(), f.target.Host, hostguard.Captured{Incarnation: f.target.Incarnation, Stamp: f.target.Stamp})
32 if err != nil {
33 t.Fatal(err)
34 }
35 program := claimUnitProgram{Schema: 1, Host: in.Host, Args: []string{"serve"}, Env: []string{"SECRET=root-config"}}
36 raw, _ := json.Marshal(program)
37 shape.Program = claimUnitDigest(raw)
38 b.installation = func(context.Context, string) (hostguard.RootInstallation, error) { return in, nil }
39 b.canonical = func(context.Context, string) (claimUnitShape, error) { return shape, nil }
40 if _, err = b.establish(t.Context(), in.Host); err != nil {
41 t.Fatal(err)
42 }
43 f.root.unitBindings = b
44 f.root.unitProgram = func(s claimUnitShape) (claimUnitProgram, error) { return decodeClaimUnitProgram(raw, s) }
45 route := shape.route()
46 locked, cancel := context.WithTimeout(t.Context(), time.Second)
47 defer cancel()
48 if err := f.root.Guard.WithLocal(locked, in.Host, func() error { _, err := f.root.boundInputs(locked, route); return err }); err != nil {
49 t.Fatal("input view reacquired host lock", err)
50 }
51 q := hostbox.RoleLaunchRequest{V: hostbox.RoleLaunchV, Op: hostbox.RoleLaunchInputs, Route: &route}
52 out, err := f.root.Serve(t.Context(), f.peer, q)
53 if err != nil || out.Inputs == nil || out.Inputs.Unit != unit || out.Inputs.Program != shape.Program || out.Inputs.Env[0] != program.Env[0] {
54 t.Fatal(out, err)
55 }
56 for _, change := range []func(*registry.Route){
57 func(r *registry.Route) { r.Unit = "other.service" }, func(r *registry.Route) { r.Unit = ""; r.Backing = "" },
58 func(r *registry.Route) { r.Backing = "exec" }, func(r *registry.Route) { r.Socket = "/run/carlos/other.sock" },
59 func(r *registry.Route) { r.Addr = "127.0.0.1:9999" }, func(r *registry.Route) { r.DBPath = "/data/other.db" },
60 func(r *registry.Route) { r.Tunnel = "tunnel" }, func(r *registry.Route) { r.Seed = "seed" }, func(r *registry.Route) { r.Replica = true },
61 } {
62 forged := route
63 change(&forged)
64 q.Route = &forged
65 if _, err = f.root.Serve(t.Context(), f.peer, q); err == nil {
66 t.Fatal("changed route accepted", forged)
67 }
68 }
69 q.Route = &route
70 raw = append(raw, ' ')
71 if _, err = f.root.Serve(t.Context(), f.peer, q); err == nil {
72 t.Fatal("changed root program accepted")
73 }
74 })
75 }
76}
77
78func TestPlan14BoundColdSelection(t *testing.T) {
79 f := newAdminTokenFixture(t, "box-1")
80 unit := &hostbox.UnitLaunchInputs{Unit: "woodstar.service", Socket: "/run/carlos/woodstar.sock", DBPath: provision.NestedDBPath("/data", f.rt.Host), Program: strings.Repeat("a", 64), Args: []string{"serve"}, Env: []string{"ROOT_PROGRAM=yes"}}
81 f.rt.Unit = unit.Unit
82 f.rt.Socket = unit.Socket
83 f.rt.DBPath = unit.DBPath
84 source := claimServingLaunchSource(f.backend, f.tokens, func(context.Context, registry.Route) (*hostbox.UnitLaunchInputs, error) { return unit, nil })
85 launch, err := source(t.Context(), f.rt)
86 if err != nil {
87 t.Fatal(err)
88 }
89 if launch.Unit != unit || launch.Identity.Config != unit.Program || launch.Identity.Release != launch.Staged.Digest || launch.ExecutableSHA256 != launch.Staged.Digest {
90 t.Fatal(launch)
91 }
92 in := ClaimLaunchInputs{Unit: unit, Roles: launch.Roles, Identity: launch.Identity, Executable: launch.Executable, ExecutableSHA256: launch.ExecutableSHA256, Args: launch.Args, Env: launch.Env, DBPath: unit.DBPath, Limit: launch.Limit}
93 if err = shapeAssembly().PreflightLaunch(f.rt.Host, in); err != nil {
94 t.Fatal(err)
95 }
96 for _, change := range []func(*ClaimLaunchInputs){
97 func(in *ClaimLaunchInputs) { in.Args = []string{"shell"} }, func(in *ClaimLaunchInputs) { in.Env = []string{"ROOT_PROGRAM=no"} },
98 func(in *ClaimLaunchInputs) { in.Identity.Config = "different" }, func(in *ClaimLaunchInputs) { in.DBPath = "/data/sibling.db" },
99 } {
100 bad := in
101 change(&bad)
102 if err = shapeAssembly().PreflightLaunch(f.rt.Host, bad); err == nil {
103 t.Fatal("changed bound inputs accepted")
104 }
105 }
106 if _, err = os.Stat(f.envPath()); !os.IsNotExist(err) {
107 t.Fatal("bound selection minted ordinary environment", err)
108 }
109}
110