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 "github.com/carlosframework/platform/internal/hostbox"
7 "github.com/carlosframework/platform/internal/hostclaim"
8 "github.com/carlosframework/platform/internal/lease"
9 "github.com/carlosframework/platform/internal/park"
10 "strings"
11 "time"
12)
13
14// ClaimRetirementCensus supplies identity; the regional engine retains retirement
15// authority and region-specific live-set checks. Bare paths need complete history.
16func ClaimRetirementCensus(o hostclaim.Observed, versions []lease.ObjectVersion) (map[string]string, error) {
17 if o.Absent || o.Claim == nil || o.ETag == "" {
18 return nil, hostbox.ErrChanged
19 }
20 if err := o.Claim.Validate(); err != nil {
21 return nil, err
22 }
23 locations, err := park.ResidueLocations(o.Host, versions)
24 if err != nil {
25 return nil, err
26 }
27 labels := map[string]string{}
28 var dependency error
29 for _, loc := range locations {
30 if loc == "moves/"+o.Host {
31 continue
32 }
33 if loc != "instances/"+o.Host {
34 // Identity is encoded in this validated qualified path, even beyond the history cap.
35 labels[loc] = strings.TrimPrefix(loc, "instances/"+o.Host+"/")
36 continue
37 }
38 inc, err := claimLegacyIncarnation(o.Claim)
39 if err != nil {
40 dependency = err
41 continue
42 }
43 labels[loc] = inc
44 }
45 return labels, dependency
46}
47func claimRetirementDependency() error {
48 return &ClaimDependencyError{Contracts: []string{"claim archived incarnation and location evidence"}}
49}
50
51func claimLegacyIncarnation(c *hostclaim.Claim) (string, error) {
52 if c == nil || len(c.RetiredIncarnations) >= 32 {
53 return "", claimRetirementDependency()
54 }
55 loc, inc := "instances/"+c.Host, ""
56 if c.Holder != nil && c.Holder.Location == loc {
57 inc = c.Holder.Incarnation
58 }
59 for _, retired := range c.RetiredIncarnations {
60 where := c.RetiredLocations[retired]
61 if where == "" {
62 return "", claimRetirementDependency()
63 }
64 if where == loc {
65 if inc != "" && inc != retired {
66 return "", claimRetirementDependency()
67 }
68 inc = retired
69 }
70 }
71 if inc == "" {
72 return "", claimRetirementDependency()
73 }
74 return inc, nil
75}
76func claimArchivedLocations(c *hostclaim.Claim) map[string]string {
77 labels := map[string]string{}
78 if c == nil {
79 return labels
80 }
81 if inc, err := claimLegacyIncarnation(c); err == nil {
82 labels["instances/"+c.Host] = inc
83 }
84 return labels
85}
86
87func claimFreeMoveProof(o hostclaim.Observed) (park.MoveSweepProof, error) {
88 if o.Absent || o.Claim == nil || o.ETag == "" || !o.Claim.Free() || len(o.Claim.RetiredIncarnations) == 0 {
89 return park.MoveSweepProof{}, claimRetirementDependency()
90 }
91 var at time.Time
92 for _, bound := range o.Claim.QuietAfter {
93 if bound.After(at) {
94 at = bound
95 }
96 }
97 if at.IsZero() {
98 return park.MoveSweepProof{}, claimRetirementDependency()
99 }
100 return park.MoveSweepProof{Host: o.Host, ClaimETag: o.ETag, MoveID: "claim-free", Incarnation: o.Claim.RetiredIncarnations[0], RetiredAt: at}, nil
101}
102
103func (p productionClaimRegional) retirement(ctx context.Context, o hostclaim.Observed, v []lease.ObjectVersion) (string, time.Time, error) {
104 _, err := ClaimRetirementCensus(o, v)
105 var dependency *ClaimDependencyError
106 if err != nil && !errors.As(err, &dependency) {
107 return "", time.Time{}, err
108 }
109 now := time.Now().UTC()
110 if p.Now != nil {
111 now = p.Now().UTC()
112 }
113 if now.IsZero() {
114 return "", time.Time{}, hostbox.ErrChanged
115 }
116 if proof, err := claimFreeMoveProof(o); err == nil {
117 if proof.RetiredAt.After(now) {
118 return "", time.Time{}, hostbox.ErrChanged
119 }
120 return proof.Incarnation, proof.RetiredAt, nil
121 }
122 if p.Parks == nil || p.Parks.Evidence == nil {
123 return "", time.Time{}, claimRetirementDependency()
124 }
125 // The moves provider must vouch for instance generations as well as lanes.
126 inc, at, err := p.Parks.Evidence.VerifyRetirement(ctx, o, v)
127 if err != nil {
128 return "", time.Time{}, err
129 }
130 if inc == "" || at.IsZero() || at.After(now) {
131 return "", time.Time{}, hostbox.ErrChanged
132 }
133 return inc, at, nil
134}
135