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 "crypto/sha256"
6 "encoding/hex"
7 "encoding/json"
8 "os"
9 "strings"
10
11 "github.com/carlosframework/platform/internal/hostclaim"
12 "github.com/carlosframework/platform/internal/hostguard"
13 "github.com/carlosframework/platform/internal/provision"
14 "github.com/carlosframework/platform/internal/release"
15 "github.com/carlosframework/platform/internal/rootparticipation"
16 "github.com/carlosframework/platform/internal/rootstate"
17)
18
19type rootRestartRequestSource struct {
20 state rootstate.Store
21 store release.Store
22 census func() (rootparticipation.Census, error)
23}
24
25func (s rootRestartRequestSource) installation(ctx context.Context, host string) (hostguard.RootInstallation, error) {
26 g := hostguard.Guard{Root: hostguard.NewRootAuthority(s.state)}
27 captured, err := g.Capture(host)
28 if err != nil {
29 return hostguard.RootInstallation{}, err
30 }
31 if captured.Stamp == 0 {
32 return hostguard.RootInstallation{Empty: true}, nil
33 }
34 v, err := g.Root.View(ctx, host, captured)
35 if err != nil {
36 return hostguard.RootInstallation{}, err
37 }
38 return s.checkInstallation(v.Installation)
39}
40
41func (s rootRestartRequestSource) launchInstallation(ctx context.Context, host string, b release.GenerationBinding) (hostguard.RootInstallation, error) {
42 if host != b.Binding.Host || host != b.Target.Host {
43 return hostguard.RootInstallation{}, os.ErrPermission
44 }
45 in, err := hostguard.NewRootAuthority(s.state).Installation(ctx, host, hostguard.Captured{Incarnation: b.Target.Incarnation, Stamp: b.Target.Stamp})
46 if err != nil {
47 return in, err
48 }
49 if rootHistoryInstallation(in) != b.Installation || in.Account != b.Binding.Account || in.App != b.Binding.App || in.Record != b.Record || in.Box != b.Target.Box || in.Enrollment != b.Target.Enrollment {
50 return in, os.ErrPermission
51 }
52 return s.checkInstallation(in)
53}
54
55func (s rootRestartRequestSource) checkInstallation(in hostguard.RootInstallation) (hostguard.RootInstallation, error) {
56 c, err := s.census()
57 if err != nil {
58 return in, err
59 }
60 if !c.Complete || c.NeverEnrolled || in.Empty || in.Box != c.Box || in.Enrollment != c.Enrollment || in.Migration != c.Migration || in.InventoryRevision == 0 {
61 return in, os.ErrPermission
62 }
63 return in, nil
64}
65
66func (s rootRestartRequestSource) target(ctx context.Context, in hostguard.RootInstallation) (release.RestartTarget, error) {
67 if in.Record != provision.RecordKey(in.Account, in.App, in.Host) {
68 return release.RestartTarget{}, os.ErrPermission
69 }
70 rec, revision, err := provision.GetRecordETag(ctx, s.store, in.Account, in.App, in.Host)
71 if err != nil {
72 return release.RestartTarget{}, err
73 }
74 inc, err := hostclaim.Incarnation(rec.Account, rec.App, rec.Host, rec.CreatedAt)
75 if err != nil || inc != in.Incarnation {
76 return release.RestartTarget{}, os.ErrPermission
77 }
78 // The agent owns exec children. Only an explicit canonical unit enters
79 // root's unit journal; socket shape cannot invent a unit binding.
80 if rec.Unit == "" {
81 return release.RestartTarget{}, nil
82 }
83 rt, err := rootRecordRoute(rec)
84 if err != nil {
85 return release.RestartTarget{}, err
86 }
87 if !release.Adoptable(rt) || revision == "" {
88 return release.RestartTarget{}, os.ErrPermission
89 }
90 raw, err := json.Marshal(in)
91 if err != nil {
92 return release.RestartTarget{}, err
93 }
94 id := sha256.Sum256(raw)
95 return release.RestartTarget{Host: in.Host, Source: in.Record + "@" + revision, Installation: hex.EncodeToString(id[:]), Unit: rt.Unit, Environment: rec.Environment, Hibernate: rec.HibernateOrDefault()}, nil
96}
97
98func (s rootRestartRequestSource) inventory(ctx context.Context) (map[release.RestartBinding][]release.RestartTarget, error) {
99 if s.state == nil || s.store == nil || s.census == nil {
100 return nil, os.ErrPermission
101 }
102 c, err := s.census()
103 if err != nil {
104 return nil, err
105 }
106 if !c.Complete || c.NeverEnrolled {
107 return nil, os.ErrPermission
108 }
109 names, err := s.state.Names()
110 if err != nil {
111 return nil, err
112 }
113 out := map[release.RestartBinding][]release.RestartTarget{}
114 for _, name := range names {
115 if strings.HasSuffix(name, ".lock") {
116 continue
117 }
118 if !strings.HasSuffix(name, ".json") {
119 return nil, os.ErrPermission
120 }
121 in, err := s.installation(ctx, strings.TrimSuffix(name, ".json"))
122 if err != nil {
123 return nil, err
124 }
125 if in.Empty {
126 continue
127 }
128 // Sidecars use a different record family and have no root restart leg.
129 if in.Record != provision.RecordKey(in.Account, in.App, in.Host) {
130 acct, app, name, ok := provision.ParseSidecarKey(in.Record, map[string]bool{in.Account: true})
131 if ok && acct == in.Account && app == in.App && provision.ValidSidecarName(name) && provision.SidecarHost(name, app, acct) == in.Host {
132 continue
133 }
134 return nil, os.ErrPermission
135 }
136 target, err := s.target(ctx, in)
137 if err != nil {
138 return nil, err
139 }
140 if target.Host == "" {
141 continue
142 }
143 b := release.RestartBinding{Box: c.Box, Account: in.Account, App: in.App}
144 out[b] = append(out[b], target)
145 }
146 return out, nil
147}
148