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 "path/filepath"
6 "reflect"
7
8 "github.com/carlosframework/platform/internal/hostbox"
9 "github.com/carlosframework/platform/internal/hostclaim"
10 "github.com/carlosframework/platform/internal/hostguard"
11)
12
13func (h ClaimRootHTTP) servingHandover() hostbox.ServingHandover {
14 return hostbox.ServingHandover{ColdHandover: hostbox.ColdHandover{Guard: h.Stop.Coordinator.Guard, Claims: h.Stop.Coordinator.Evidence, Registry: h.Reconcile.Registry, Inventory: h.Reconcile.Inventory, Launches: h.Launches, Roots: h.Roots, JournalDir: filepath.Join(h.Reconcile.Retirement.JournalDir, "serving"), VerifyReceipt: verifyRetirementReceipt}, Validate: h.validateServingHandover, VerifyDirectory: h.verifyServingHandoverDirectory}
15}
16
17func (h ClaimRootHTTP) validateServingHandover(ctx context.Context, c *hostclaim.Claim, prior hostguard.FenceTarget, next hostbox.ColdSuccessor, in hostbox.StopInventory, installation hostguard.RootInstallation) error {
18 if h.RequireNewWork == nil || h.InventoryActor == nil {
19 return hostbox.ErrUnsupported
20 }
21 if err := h.RequireNewWork(ctx); err != nil {
22 return err
23 }
24 actor, err := h.InventoryActor(ctx)
25 if err != nil {
26 return err
27 }
28 if !actor.Eligible || actor.Quarantined || actor.Revision == 0 || actor.Box != prior.Box || actor.Region != prior.Region || actor.Enrollment != prior.Enrollment || !servingPriorBinding(next.DirectoryRevision, actor) {
29 return hostbox.ErrChanged
30 }
31 if !servingPriorBinding(prior.DirectoryRevision, actor) {
32 return hostbox.ErrChanged
33 }
34 current, err := servingWriterIdentity(hostclaim.Observed{Host: prior.Host, Claim: c}, actor.Box, actor.Region)
35 if err != nil {
36 return err
37 }
38 holder := c.Holder
39 if installation.Empty || installation.Host != prior.Host || installation.Incarnation != prior.Incarnation || installation.Stamp != prior.Stamp || installation.Migration == 0 || installation.Account != holder.Account || installation.App != holder.App || installation.Record != holder.Key || installation.Box != actor.Box || installation.Enrollment != actor.Enrollment {
40 return hostbox.ErrChanged
41 }
42 canonical, _, err := rootClaimRecord(ctx, h.Stop.Coordinator.Evidence, c, h.Roots["data"])
43 if err != nil {
44 return err
45 }
46 canonical.ClaimIncarnation, canonical.ClaimStamp = prior.Incarnation, prior.Stamp
47 for _, e := range in.Entries {
48 if e.Kind == "route" {
49 canonical.ClaimOwner, canonical.ClaimRowID = e.Ownership, e.RowIdentity
50 }
51 }
52 if err = hostbox.ValidateAgentInventory(in, &canonical, h.Roots["data"]); err != nil {
53 return err
54 }
55 var admission hostclaim.AdmissionRecord
56 for _, a := range holder.Admissions {
57 if a.Session == current.Session {
58 admission = a
59 }
60 }
61 if prior.Session != 0 {
62 p, err := servingPredecessor(c, current, prior.Stamp, admission.Predecessor)
63 if err != nil || p.Session != prior.Session || admission.Predecessor != p.Generation || admission.PredecessorRegion != p.Region || admission.WritesLost == nil || admission.WritesLost.Box != p.Box || admission.WritesLost.Session != p.Session || admission.WritesLost.Generation != p.Generation {
64 return hostbox.ErrChanged
65 }
66 for _, a := range holder.Admissions {
67 if a.Session > p.Session && a.Session < current.Session {
68 return hostbox.ErrChanged
69 }
70 }
71 } else {
72 if h.servingParks == nil || h.servingParks.state == nil {
73 return hostbox.ErrUnsupported
74 }
75 body, err := h.servingParks.state.Read(servingLegacyKey("legacy-stop", current))
76 if err != nil {
77 return err
78 }
79 var saved servingLegacyStop
80 if servingParkDecode(body, &saved) != nil || validateServingLegacyStop(saved) != nil || saved.Result.Target != prior {
81 return hostbox.ErrChanged
82 }
83 old := saved.Observed.Claim.Holder
84 if old.Account != holder.Account || old.App != holder.App || old.Key != holder.Key || old.Incarnation != holder.Incarnation || !old.CreatedAt.Equal(holder.CreatedAt) || admission.Predecessor != old.Generation {
85 return hostbox.ErrChanged
86 }
87 for _, a := range holder.Admissions {
88 if a.Session < current.Session {
89 return hostbox.ErrChanged
90 }
91 }
92 if old.WriterBox == "" {
93 if admission.WritesLost != nil || admission.PredecessorRegion != "" {
94 return hostbox.ErrChanged
95 }
96 } else if old.WriterBox != actor.Box || admission.WritesLost == nil || admission.WritesLost.Box != actor.Box || admission.WritesLost.Session != 0 || admission.WritesLost.Generation != "" || admission.PredecessorRegion != actor.Region {
97 return hostbox.ErrChanged
98 }
99 }
100 fresh, err := hostclaim.Read(ctx, h.Stop.Coordinator.Evidence, prior.Host)
101 if err != nil {
102 return err
103 }
104 if fresh.Absent || !reflect.DeepEqual(fresh.Claim, c) {
105 return hostbox.ErrChanged
106 }
107 return nil
108}
109
110// Session zero sends a selector. Root supplies the complete retained stop tuple.
111func (h ClaimRootHTTP) servingLegacyHandoverTarget(ctx context.Context, q coldHandoverRequest) (hostguard.FenceTarget, error) {
112 if h.servingParks == nil || h.servingParks.state == nil {
113 return hostguard.FenceTarget{}, hostbox.ErrUnsupported
114 }
115 p, n := q.Prior, q.Next
116 selector := hostguard.FenceTarget{Host: n.Host, Incarnation: n.Incarnation, Stamp: p.Stamp, Box: n.Box, Enrollment: n.Enrollment}
117 if p != selector || n.Op != "" || n.Phase != "" {
118 return hostguard.FenceTarget{}, hostbox.ErrChanged
119 }
120 body, err := h.servingParks.state.Read(servingLegacyKey("legacy-stop", servingArtifactIdentity{Host: n.Host, Box: n.Box, Incarnation: n.Incarnation}))
121 if err != nil {
122 return hostguard.FenceTarget{}, err
123 }
124 var saved servingLegacyStop
125 if servingParkDecode(body, &saved) != nil || validateServingLegacyStop(saved) != nil {
126 return hostguard.FenceTarget{}, hostbox.ErrChanged
127 }
128 t := saved.Result.Target
129 if t.Host != p.Host || t.Incarnation != p.Incarnation || t.Stamp != p.Stamp || t.Box != p.Box || t.Enrollment != p.Enrollment {
130 return hostguard.FenceTarget{}, hostbox.ErrChanged
131 }
132 return t, ctx.Err()
133}
134
135// servingPriorBinding reports whether a recorded installation stamp is the
136// fresh actor's binding. It is equality, not an ordering: a binding is a
137// digest, and an installation stamped under any other binding (before a
138// quarantine and readmission, say) is never served again.
139func servingPriorBinding(recorded string, actor hostbox.Actor) bool {
140 return actor.Binding != "" && recorded == actor.Binding
141}
142