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 "errors"
8 "net"
9 "os"
10 "reflect"
11
12 "github.com/carlosframework/platform/internal/hostbox"
13 "github.com/carlosframework/platform/internal/hostclaim"
14 "github.com/carlosframework/platform/internal/hostguard"
15)
16
17// Called only by the root stop coordinator after its kernel observation and
18// before publishing the receipt. There is no transport operation for inserting
19// this evidence. A claim change during the observation or lock wait refuses it.
20func (p *servingParkRoot) retainLegacyNoProcess(ctx context.Context, o hostclaim.Observed, result StopResult) error {
21 if p == nil || p.ledger == nil || p.root.RequireNewWork == nil || p.root.InventoryActor == nil || p.root.Stop.Coordinator.Guard.Root == nil {
22 return hostbox.ErrUnsupported
23 }
24 s := servingLegacyStop{Observed: o, Result: result}
25 if validateServingLegacyStop(s) != nil {
26 return ErrClaimStopReceipt
27 }
28 return p.ledger.withNamespace(ctx, func() error {
29 return p.root.Stop.Coordinator.Guard.With(ctx, o.Host, hostguard.Captured{Incarnation: result.Target.Incarnation, Stamp: result.Target.Stamp}, func(c *hostclaim.Claim) error {
30 if !reflect.DeepEqual(c, o.Claim) {
31 return hostbox.ErrChanged
32 }
33 return nil
34 }, func() error {
35 if err := p.root.RequireNewWork(ctx); err != nil {
36 return err
37 }
38 actor, err := p.root.InventoryActor(ctx)
39 if err != nil {
40 return err
41 }
42 t := result.Target
43 if !actor.Eligible || actor.Quarantined || actor.Box != t.Box || actor.Region != t.Region || actor.Enrollment != t.Enrollment || actor.Revision == 0 || !servingPriorBinding(t.DirectoryRevision, actor) {
44 return hostbox.ErrChanged
45 }
46 fresh, err := p.root.Stop.Coordinator.Guard.Claims.Read(ctx, o.Host)
47 if err != nil {
48 return err
49 }
50 if fresh.ETag != o.ETag || fresh.Absent {
51 return hostbox.ErrChanged
52 }
53 a := servingArtifactIdentity{Host: o.Host, Box: result.Target.Box, Region: result.Target.Region, Incarnation: result.Target.Incarnation}
54 old, err := p.ledger.legacyStop(a)
55 if err == nil {
56 // Retry reservation and settlement change Gen, ETag and WakeRetry
57 // without admitting a writer. Keep the first receipt across those
58 // changes, but refuse a different holder or enrollment.
59 priorClaim, nextClaim := *old.Observed.Claim, *o.Claim
60 priorHolder, nextHolder := *priorClaim.Holder, *nextClaim.Holder
61 priorHolder.WakeRetry, nextHolder.WakeRetry = nil, nil
62 priorClaim.Holder, nextClaim.Holder = &priorHolder, &nextHolder
63 priorClaim.Gen = nextClaim.Gen
64 if !reflect.DeepEqual(priorClaim, nextClaim) || old.Result.Target.Enrollment != result.Target.Enrollment || old.Result.Target.DirectoryRevision != result.Target.DirectoryRevision {
65 return hostbox.ErrChanged
66 }
67 return nil
68 }
69 if !errors.Is(err, os.ErrNotExist) {
70 return err
71 }
72 return p.ledger.write(servingLegacyKey("legacy-stop", a), s)
73 })
74 })
75}
76
77func (p *servingParkRoot) validateLegacyRootEvidence(ctx context.Context, o hostclaim.Observed, view hostguard.FenceView, actor hostbox.Actor, a servingParkAuthorization, e *servingLegacyEvidence, receipts []hostguard.FenceReceipt) error {
78 if validateServingLegacyEvidence(a, e) != nil {
79 return hostbox.ErrChanged
80 }
81 current := a.OriginalSuccessor
82 var entry *hostclaim.AdmissionRecord
83 for i := range o.Claim.Holder.Admissions {
84 r := &o.Claim.Holder.Admissions[i]
85 if r.Session == current.Session {
86 if entry != nil {
87 return hostbox.ErrChanged
88 }
89 entry = r
90 }
91 }
92 if entry == nil || entry.Mode != "cold" || entry.Box != current.Box || entry.Region != current.Region || entry.Generation != current.Generation || entry.Predecessor != e.Selector.Generation {
93 return hostbox.ErrChanged
94 }
95 if e.NoProcess != nil {
96 saved, err := p.ledger.legacyStop(current)
97 if err != nil || !reflect.DeepEqual(saved, *e.NoProcess) || len(receipts) != 0 {
98 return hostbox.ErrChanged
99 }
100 t, h := saved.Result.Target, saved.Observed.Claim.Holder
101 if t.Enrollment != actor.Enrollment || !servingPriorBinding(t.DirectoryRevision, actor) || h.Account != o.Claim.Holder.Account || h.App != o.Claim.Holder.App || h.Key != o.Claim.Holder.Key || !h.CreatedAt.Equal(o.Claim.Holder.CreatedAt) {
102 return hostbox.ErrChanged
103 }
104 for _, r := range o.Claim.Holder.Admissions {
105 if r.Session < current.Session {
106 return hostbox.ErrChanged
107 }
108 }
109 if e.Selector.Empty {
110 if entry.PredecessorRegion != "" || entry.WritesLost != nil {
111 return hostbox.ErrChanged
112 }
113 } else if entry.WritesLost == nil || entry.WritesLost.Box != current.Box || entry.WritesLost.Session != 0 || entry.WritesLost.Generation != "" || entry.PredecessorRegion != current.Region {
114 return hostbox.ErrChanged
115 }
116 return nil
117 }
118 prior, err := servingPredecessor(o.Claim, a.Successor, e.Selector.Session, e.Selector.Generation)
119 if err != nil || prior.Stamp >= current.Stamp {
120 return hostbox.ErrChanged
121 }
122 stops, err := servingRootStops(ctx, view, prior, actor)
123 if err != nil {
124 return err
125 }
126 if !sameServingRootStops(stops, receipts) {
127 return ErrClaimStopReceipt
128 }
129 return nil
130}
131
132func (p *servingParkRoot) parkLegacyServingDatabase(ctx context.Context, conn net.Conn, current servingArtifactIdentity, requested servingLegacyPredecessor) (servingParkAuthorization, error) {
133 var out servingParkAuthorization
134 err := p.withAuthority(ctx, conn, current, func(o hostclaim.Observed, view hostguard.FenceView, actor hostbox.Actor, dir servingArtifactDirectory, tags uint64) error {
135 var err error
136 consumed, err := p.ledger.legacyConsumption(current)
137 if err != nil {
138 return err
139 }
140 a := servingParkAuthorization{Legacy: true, OriginalSuccessor: current, Successor: current, Directory: dir}
141 a.ID = servingRetirementID(a.Predecessor, current, true)
142 e := &servingLegacyEvidence{Selector: requested}
143 var receipts []hostguard.FenceReceipt
144 var saved *servingParkRecord
145 if consumed != nil {
146 if consumed.Collected {
147 return hostbox.ErrChanged
148 }
149 a, e, receipts = consumed.Authorization, consumed.LegacyEvidence, consumed.Receipts
150 if a.Directory != dir || e == nil {
151 return hostbox.ErrChanged
152 }
153 r, readErr := p.ledger.read(a.ID)
154 if readErr == nil {
155 saved = &r
156 } else if !errors.Is(readErr, os.ErrNotExist) {
157 return readErr
158 }
159 } else {
160 if tags != 0 {
161 return hostbox.ErrChanged
162 }
163 if requested.Session == 0 {
164 stop, readErr := p.ledger.legacyStop(current)
165 if readErr != nil {
166 return readErr
167 }
168 e.NoProcess = &stop
169 } else {
170 prior, readErr := servingPredecessor(o.Claim, current, requested.Session, requested.Generation)
171 if readErr != nil {
172 return readErr
173 }
174 receipts, err = servingRootStops(ctx, view, prior, actor)
175 if err != nil {
176 return err
177 }
178 }
179 }
180 if err = p.validateLegacyRootEvidence(ctx, o, view, actor, a, e, receipts); err != nil {
181 return err
182 }
183 active := a
184 if saved != nil {
185 if !sameServingLegacySource(saved.Source, consumed.Source) || saved.Authorization != a || !sameServingLegacyEvidence(saved.LegacyEvidence, e) || !sameServingRootStops(saved.Receipts, receipts) {
186 return hostbox.ErrChanged
187 }
188 if err = validateServingRootHistory(ctx, o, view, actor, *saved); err != nil {
189 return err
190 }
191 active = saved.activeAuthorization()
192 }
193 if tags != active.TagsFrom && tags != active.Successor.Stamp && tags != current.Stamp {
194 return hostbox.ErrChanged
195 }
196 var next servingParkAuthorization
197 var stops []hostguard.FenceReceipt
198 if active.Successor != current {
199 if saved != nil && saved.Complete || active.Successor.Stamp >= current.Stamp {
200 return hostbox.ErrChanged
201 }
202 prior, e := servingPredecessor(o.Claim, current, active.Successor.Stamp, active.Successor.Generation)
203 if e != nil || prior != active.Successor {
204 return hostbox.ErrChanged
205 }
206 stops, err = servingRootStops(ctx, view, prior, actor)
207 if err != nil {
208 return err
209 }
210 next = active
211 next.Successor, next.TagsFrom = current, tags
212 }
213 if err = p.ledger.legacyUnlaunched(ctx, current, actor.Enrollment); err != nil {
214 return err
215 }
216 if consumed == nil && e.Selector.Empty {
217 if p.empty == nil {
218 return hostbox.ErrUnsupported
219 }
220 if a.Successor != current {
221 return hostbox.ErrChanged
222 }
223 in := ClaimLaunchInputs{Empty: true, Admission: hostclaim.Admission{NewGeneration: current.Generation}}
224 if err = p.empty.EmptyAuthority(ctx, o, in); err != nil {
225 return err
226 }
227 }
228 // Remote first-creator proof can wait on I/O; it cannot carry a stale claim
229 // into the first source capture or any replay mutation.
230 fresh, err := p.root.Stop.Coordinator.Guard.Claims.Read(ctx, current.Host)
231 if err != nil {
232 return err
233 }
234 if fresh.Absent || fresh.ETag != o.ETag {
235 return hostbox.ErrChanged
236 }
237 if err = p.prepareServingNamespace(ctx, a, receipts, e); err != nil {
238 return err
239 }
240 r, err := p.ledger.parkWithEvidenceLocked(ctx, a, receipts, e)
241 if err != nil {
242 return err
243 }
244 if err = p.ledger.fs.CheckParked(&r); err != nil {
245 return err
246 }
247 if next.ID != "" {
248 r, err = p.ledger.continueLocked(ctx, a.ID, next, stops)
249 if err != nil {
250 return err
251 }
252 }
253 out = r.activeAuthorization()
254 return nil
255 })
256 return out, err
257}
258
259func sameServingLegacySource(a, b servingParkSource) bool {
260 if a.Directory != b.Directory || a.Parent != b.Parent || a.Persistent != b.Persistent || a.BootID != b.BootID {
261 return false
262 }
263 for i := range a.Files {
264 if a.Files[i].Persistent != b.Files[i].Persistent || !sameServingParkFile(a.Files[i], b.Files[i]) {
265 return false
266 }
267 }
268 return true
269}
270