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 "bytes"
5 "crypto/sha256"
6 "encoding/hex"
7 "encoding/json"
8 "io"
9 "os"
10 "path/filepath"
11 "slices"
12 "strings"
13
14 "github.com/carlosframework/platform/internal/hostbox"
15 "github.com/carlosframework/platform/internal/instancectl"
16 "github.com/carlosframework/platform/internal/provision"
17 "github.com/carlosframework/platform/internal/rootstate"
18)
19
20type claimUnitProgram struct {
21 Schema int
22 Host string
23 Args, Env []string
24}
25
26func readClaimUnitProgram(shape claimUnitShape) (claimUnitProgram, error) {
27 if !provision.ValidHostShape(shape.Host) {
28 return claimUnitProgram{}, os.ErrPermission
29 }
30 f, err := rootstate.OpenAuthorityFile(filepath.Join("/etc/carlos/claim-units", shape.Host+".json"))
31 if err != nil {
32 return claimUnitProgram{}, err
33 }
34 defer f.Close()
35 raw, err := io.ReadAll(io.LimitReader(f, rootstate.MaxRecord+1))
36 if err != nil {
37 return claimUnitProgram{}, err
38 }
39 return decodeClaimUnitProgram(raw, shape)
40}
41
42func decodeClaimUnitProgram(raw []byte, shape claimUnitShape) (claimUnitProgram, error) {
43 var p claimUnitProgram
44 sum := sha256.Sum256(raw)
45 dec := json.NewDecoder(bytes.NewReader(raw))
46 dec.DisallowUnknownFields()
47 if len(raw) > rootstate.MaxRecord || hex.EncodeToString(sum[:]) != shape.Program || dec.Decode(&p) != nil || dec.Decode(new(any)) != io.EOF || p.Schema != 1 || p.Host != shape.Host || len(p.Args) > 256 || len(p.Env) > 1024 {
48 return p, os.ErrPermission
49 }
50 for _, arg := range p.Args {
51 if strings.ContainsRune(arg, 0) {
52 return p, os.ErrPermission
53 }
54 }
55 seen := map[string]bool{}
56 for _, env := range p.Env {
57 key, _, ok := strings.Cut(env, "=")
58 if !ok || key == "" || strings.ContainsRune(env, 0) || seen[key] {
59 return p, os.ErrPermission
60 }
61 seen[key] = true
62 }
63 return p, nil
64}
65
66func (h *ClaimLaunchRoot) boundLaunchSpec(q hostbox.RoleLaunchRequest) (instancectl.Launch, bool, error) {
67 var launch instancectl.Launch
68 host := q.Reservation.Target.Host
69 unit, _, err := claimLaunchPlacement(h.Units, host)
70 if err != nil {
71 return launch, false, err
72 }
73 if unit == instancectl.UnitName(instancectl.RoleRun, host) {
74 return launch, false, nil
75 }
76 if h.unitBindings == nil {
77 return launch, true, os.ErrPermission
78 }
79 b, err := h.unitBindings.read(host)
80 if err != nil {
81 return launch, true, err
82 }
83 // Older bindings only describe placement and retain the ordinary isolated
84 // launch contract. Production configuration requires a program digest.
85 if b.Shape.Program == "" {
86 return launch, false, nil
87 }
88 if b.Retiring || b.Retired || b.Shape.Unit != unit || h.unitProgram == nil {
89 return launch, true, os.ErrPermission
90 }
91 p, err := h.unitProgram(b.Shape)
92 if err != nil {
93 return launch, true, err
94 }
95 if q.Spec.Identity.Config != b.Shape.Program || !slices.Equal(p.Args, q.Spec.Args) || !slices.Equal(p.Env, q.Spec.Env) {
96 return launch, true, os.ErrPermission
97 }
98 return instancectl.Launch{Schema: instancectl.LaunchSchema, Host: host, Argv: append([]string{filepath.Join(instancectl.LiveDir, host)}, p.Args...), Env: append([]string(nil), p.Env...)}, true, nil
99}
100