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 "context"
6 "encoding/json"
7 "errors"
8 "os"
9 "reflect"
10
11 "github.com/carlosframework/platform/internal/hostbox"
12 "github.com/carlosframework/platform/internal/hostclaim"
13)
14
15// A session-zero witness is retained separately from fence receipts. Admission
16// changes its ETag; keeping the original observation binds it to the first cold
17// admission without pretending that session zero held a serving fence.
18type servingLegacyStop struct {
19 Observed hostclaim.Observed
20 Result StopResult
21}
22
23type servingLegacyEvidence struct {
24 Selector servingLegacyPredecessor
25 NoProcess *servingLegacyStop `json:",omitempty"`
26}
27
28func servingLegacyKey(kind string, a servingArtifactIdentity) string {
29 return kind + "-" + servingParkKey(a.Box, a.Host+"\x00"+a.Incarnation) + ".json"
30}
31
32func validateServingLegacyStop(s servingLegacyStop) error {
33 o, result := s.Observed, s.Result
34 if o.Absent || o.ETag == "" || o.Claim == nil || o.Claim.Holder == nil || o.Claim.Host != o.Host {
35 return hostbox.ErrChanged
36 }
37 c, h, t := o.Claim, o.Claim.Holder, result.Target
38 if c.Validate() != nil {
39 return hostbox.ErrChanged
40 }
41 if c.Op.Kind != hostclaim.KindServing || c.Op.ID != "" || c.Op.Phase != "" || c.Op.Exec != t.Box || h.Session != 0 || h.Generation != "" || len(h.Admissions) != 0 || (h.WriterBox != "" && h.WriterBox != t.Box) || t.Host != o.Host || t.Incarnation != h.Incarnation || t.Stamp != h.Stamp || t.Stamp == 0 || t.Session != 0 || t.FenceID != "" || t.Op != "" || t.Phase != "" || t.ObligationID != "" || t.ClaimGen != c.Gen || t.ClaimETag != o.ETag {
42 return hostbox.ErrChanged
43 }
44 var r StopReceipt
45 if json.Unmarshal(result.Bytes, &r) != nil || !bytes.Equal(result.Bytes, mustMarshalStopReceipt(r)) || r.V != 1 || r.Kind != StopReceiptNoProcess || !stopComponent(r.ID) || r.ProducerDrainDigest != "" || !stopDigest(r.InventorySHA256) || !stopDigest(r.LocalJournalSHA256) || len(r.CgroupIdentities) == 0 || len(r.UnitInvocationIDs) != 0 || r.ClaimETag != o.ETag || r.ClaimGen != c.Gen || result.EvidenceAt.IsZero() || result.Key != stopEvidenceKey(o.Host, "", t.Box, r.ID) {
46 return ErrClaimStopReceipt
47 }
48 req := StopRequest{Region: t.Region, Host: t.Host, Incarnation: t.Incarnation, InstallationStamp: t.Stamp, Box: t.Box, Enrollment: t.Enrollment, BootID: t.BootID, ControllerID: t.ControllerID, ExpectedClaimETag: o.ETag, ExpectedDirectoryRevision: t.DirectoryRevision, RosterRevision: t.RosterRevision}
49 if t.Region == "" || t.Box == "" || t.Enrollment == "" || t.BootID == "" || t.ControllerID == "" || t.DirectoryRevision == "" || t.RosterRevision == 0 {
50 return ErrClaimStopReceipt
51 }
52 _, err := validateTransportStop(req, result)
53 return err
54}
55
56func (l *servingParkLedger) legacyStop(a servingArtifactIdentity) (servingLegacyStop, error) {
57 var s servingLegacyStop
58 b, err := l.state.Read(servingLegacyKey("legacy-stop", a))
59 if err != nil {
60 return s, err
61 }
62 if servingParkDecode(b, &s) != nil || validateServingLegacyStop(s) != nil {
63 return s, hostbox.ErrChanged
64 }
65 t := s.Result.Target
66 if t.Host != a.Host || t.Box != a.Box || t.Region != a.Region || t.Incarnation != a.Incarnation {
67 return s, hostbox.ErrChanged
68 }
69 return s, nil
70}
71
72func (l *servingParkLedger) legacyConsumption(a servingArtifactIdentity) (*servingLegacyConsumption, error) {
73 b, err := l.state.Read(servingLegacyKey("legacy", a))
74 if errors.Is(err, os.ErrNotExist) {
75 return nil, nil
76 }
77 if err != nil {
78 return nil, err
79 }
80 var c servingLegacyConsumption
81 if servingParkDecode(b, &c) != nil || !c.Authorization.Legacy || c.Authorization.Successor.Host != a.Host || c.Authorization.Successor.Box != a.Box || c.Authorization.Successor.Incarnation != a.Incarnation {
82 return nil, hostbox.ErrChanged
83 }
84 r := servingParkRecord{Authorization: c.Authorization, Source: c.Source}
85 if err := l.bindRecord(&r, false); err != nil {
86 return nil, err
87 }
88 c.Authorization, c.Source = r.Authorization, r.Source
89 return &c, nil
90}
91
92func sameServingLegacyEvidence(a, b *servingLegacyEvidence) bool { return reflect.DeepEqual(a, b) }
93
94func validateServingLegacyEvidence(a servingParkAuthorization, evidence *servingLegacyEvidence) error {
95 if !a.Legacy || evidence == nil {
96 return hostbox.ErrChanged
97 }
98 p := evidence.Selector
99 if (p.Session == 0) != (p.Generation == "") || p.Session >= a.OriginalSuccessor.Session || (p.Empty && p.Session != 0) {
100 return hostbox.ErrChanged
101 }
102 if p.Session != 0 {
103 if evidence.NoProcess != nil {
104 return hostbox.ErrChanged
105 }
106 return nil
107 }
108 if evidence.NoProcess == nil || validateServingLegacyStop(*evidence.NoProcess) != nil {
109 return hostbox.ErrChanged
110 }
111 s, current := *evidence.NoProcess, a.OriginalSuccessor
112 h, t := s.Observed.Claim.Holder, s.Result.Target
113 if t.Host != current.Host || t.Box != current.Box || t.Region != current.Region || t.Incarnation != current.Incarnation || h.Location != current.Location || h.Stamp >= current.Stamp || s.Observed.Claim.Gen >= current.Stamp || p.Empty != (h.WriterBox == "") {
114 return hostbox.ErrChanged
115 }
116 return nil
117}
118
119// The current writer must still be only a preparation. Even an uncompleted
120// launch intention makes untagged bytes ambiguous and forbids legacy capture.
121func (l *servingParkLedger) legacyUnlaunched(ctx context.Context, a servingArtifactIdentity, enrollment string) error {
122 records, err := l.journal.RootSessionLaunches(ctx, a.Host, a.Incarnation, a.Stamp, a.Session, a.Box, enrollment)
123 if err != nil {
124 return err
125 }
126 for _, r := range records {
127 for _, reservation := range r.Reservations {
128 if reservation.Role == "main" {
129 return hostbox.ErrChanged
130 }
131 }
132 }
133 return nil
134}
135
136func sameServingLegacyConsumption(c servingLegacyConsumption, r servingParkRecord) bool {
137 if c.Authorization != r.Authorization || !sameServingRootStops(c.Receipts, r.Receipts) || !sameServingLegacyEvidence(c.LegacyEvidence, r.LegacyEvidence) || c.Source.Directory != r.Source.Directory || c.Source.Parent != r.Source.Parent || c.Source.Persistent != r.Source.Persistent || c.Source.BootID != r.Source.BootID {
138 return false
139 }
140 for i, item := range c.Source.Files {
141 other := r.Source.Files[i]
142 item.Moved, item.DeleteIntent, item.Deleted = false, false, false
143 other.Moved, other.DeleteIntent, other.Deleted = false, false, false
144 if item != other {
145 return false
146 }
147 }
148 return true
149}
150