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 "os"
7 "path/filepath"
8 "time"
9
10 "github.com/carlosframework/platform/internal/moves"
11 "github.com/carlosframework/platform/internal/release"
12 "github.com/carlosframework/platform/internal/rootstate"
13 "github.com/carlosframework/platform/internal/seeds"
14)
15
16func rootSeedsFloorDir(opt string) string { return filepath.Join(opt, "system", "guard", "seeds") }
17func (b rootFloorBinary) forSeeds() rootFloorBinary { b.Protocol = b.SeedsProtocol; return b }
18func readRootSeedsBinary(opt, path string) (rootFloorBinary, error) {
19 b, err := readRootFloorBinary(opt, path)
20 return b.forSeeds(), err
21}
22func readEffectiveSeedsFloor(source rootFloorIdentitySource, opt, dd string) (*moves.Floor, error) {
23 id, required, err := source.read()
24 if err != nil {
25 return nil, err
26 }
27 if required {
28 return readRootSeedsBound(opt, id)
29 }
30 f, err := readLocalSeedsFloor(dd)
31 if f == nil {
32 return nil, err
33 }
34 return &moves.Floor{Min: f.Min, MinRelease: f.MinRelease}, err
35}
36func refreshRootSeedsFloor(ctx context.Context, store release.Store, opt, dd string, id rootFloorIdentity) error {
37 f, err := openRootProtocolFloors(rootSeedsFloorDir(opt), id, true)
38 if err != nil {
39 return err
40 }
41 defer f.close()
42 raw, _, rerr := store.Get(ctx, seeds.FloorKey)
43 var bound *moves.Floor
44 if rerr == nil {
45 // Unsigned legacy publication cannot arm a root seeds floor.
46 if verified, err := verifyRootSeedsPublication(raw, id); err == nil {
47 if err := acceptRootSeedsPublication(ctx, f, raw); err != nil {
48 return err
49 }
50 bound = verified
51 }
52 }
53 published, err := readRootSeedsBound(opt, id)
54 if err != nil {
55 return err
56 }
57 if published == nil {
58 return nil
59 }
60 legacy, lerr := rootProtocolLegacy(dd, seeds.FloorFile, seeds.FloorMinReleaseFile)
61 if errors.Is(rerr, os.ErrNotExist) {
62 rerr = nil
63 }
64 unlock, err := f.private.Lock(ctx, "floor.lock")
65 if err != nil {
66 return err
67 }
68 defer unlock()
69 capped, err := f.capLegacy(legacy)
70 if err != nil {
71 return err
72 }
73 local := floorMaximum(published, bound)
74 for _, fl := range capped {
75 local = floorMaximum(local, fl)
76 }
77 generation := uint64(1)
78 if r, e := f.record(rootFloorAccepted); e == nil {
79 generation = r.Generation + 1
80 }
81 r := rootFloorRecord{Schema: 1, Identity: id, Generation: generation, Floor: local}
82 failure := errors.Join(rerr, lerr)
83 return errors.Join(failure, f.persist(r, local, failure == nil))
84}
85func judgeRootSeedsPrev(ctx context.Context, opt string, id rootFloorIdentity) error {
86 bound, err := readRootSeedsBound(opt, id)
87 if err != nil || bound == nil {
88 return err
89 }
90 f, err := openRootProtocolFloors(rootSeedsFloorDir(opt), id, true)
91 if err != nil {
92 return err
93 }
94 defer f.close()
95 return (rootFloorJudge{floors: f, current: systemBinaryPath(opt), prev: systemPrevPath(opt), binary: func(path string) (rootFloorBinary, error) { return readRootSeedsBinary(opt, path) }, idle: rootFloorDowngradeIdle}).judge(ctx)
96}
97func rootRefreshAndJudgeSeedsPrev(id rootFloorIdentity) error {
98 ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
99 defer cancel()
100 opt, dd := release.OptDir(), dataDir()
101 return withPrevLock(opt, func() error {
102 store, err := openDeployStore(ctx)
103 if err != nil {
104 return err
105 }
106 if err := refreshRootSeedsFloor(ctx, store, opt, dd, id); err != nil {
107 return err
108 }
109 return judgeRootSeedsPrev(ctx, opt, id)
110 })
111}
112func (a *systemApplier) seedsActivationRefusal(version string) error {
113 floor, err := readEffectiveSeedsFloor(a.rootMoves, a.optDir, a.dataDir)
114 if err != nil {
115 return refuse("seeds protocol floor: the floor on this box cannot be read: %v", err)
116 }
117 floor = a.activationFloor(floor, true)
118 if floor == nil {
119 return nil
120 }
121 if ok, _ := seeds.ReleaseAtOrAbove(version, floor.MinRelease); !ok {
122 return refuse("seeds protocol floor: %s is below %s", version, floor.MinRelease)
123 }
124 return nil
125}
126func rootSeedsAllowsBinary(opt string, id rootFloorIdentity, path string) error {
127 floor, err := readRootSeedsBound(opt, id)
128 if err != nil {
129 return err
130 }
131 if floor == nil {
132 return nil
133 }
134 b, err := readRootSeedsBinary(opt, path)
135 if err != nil {
136 return err
137 }
138 if !b.supports(floor) && rootFloorAvailable(opt, floor, true, path) {
139 return errRootFloorHistory
140 }
141 return nil
142}
143func withRootSeedsFields(f edgesFile, opt string) edgesFile {
144 f.SeedsProtocol = seeds.ProtocolVersion
145 f.SeedsFloorState = "quarantined"
146 f.SeedsFloorMinRelease, f.PrevSeedsAllowedFor = "", ""
147 p, err := readRootProtocolProjection(rootSeedsFloorDir(opt))
148 if err != nil {
149 return f
150 }
151 if p.Identity.Deployment != os.Getenv("CARLOS_DEPLOYMENT_BUCKET") || p.Identity.Box != f.Box {
152 return f
153 }
154 public, err := rootstate.Open(rootSeedsFloorDir(opt), false, true)
155 if err != nil {
156 return f
157 }
158 defer public.Close()
159 raw, err := public.Read("publication.json")
160 if err != nil {
161 return f
162 }
163 if _, err := verifyRootSeedsPublication(raw, p.Identity); err != nil {
164 return f
165 }
166 ad, err := rootFloorAdvertisementFor(public, p)
167 if err != nil || rootstate.Sync(public) != nil {
168 return f
169 }
170 f.SeedsFloorState, f.SeedsFloorGeneration = ad.State, ad.Generation
171 f.SeedsFloorMinRelease, f.PrevSeedsAllowedFor = ad.MinRelease, ad.PrevAllowedFor
172 return f
173}
174
175func (a *systemApplier) rootProtocolAllowsBinary(path string) error {
176 id, required, err := a.rootMoves.read()
177 if err != nil || !required {
178 return err
179 }
180 b, err := readRootFloorBinary(a.optDir, path)
181 if err != nil {
182 return err
183 }
184 floor, err := readRootProtocolBound(rootFloorDir(a.optDir), id)
185 if err != nil {
186 return err
187 }
188 if !b.supports(floor) && rootFloorAvailable(a.optDir, floor, false, path) {
189 return errRootFloorHistory
190 }
191 return rootSeedsAllowsBinary(a.optDir, id, path)
192}
193