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 "reflect"
8
9 "github.com/carlosframework/platform/internal/hostbox"
10 "github.com/carlosframework/platform/internal/hostclaim"
11 "github.com/carlosframework/platform/internal/hostguard"
12)
13
14// Startup resumes only an existing immutable intent for its active successor.
15// A newer successor needs the ordinary request's stopped-continuation checks.
16// Incomplete paired retagging remains the independent claim writer's work.
17func (p *servingParkRoot) recoverServingPark(ctx context.Context, saved servingParkRecord) error {
18 active := saved.activeAuthorization()
19 return p.withRootInstallation(ctx, active.Successor, ctx.Err, func(o hostclaim.Observed, view hostguard.FenceView, actor hostbox.Actor, dir servingArtifactDirectory, tags uint64) error {
20 r, err := p.ledger.read(saved.Authorization.ID)
21 if err != nil || !reflect.DeepEqual(saved, r) || r.Complete || active.Directory != dir || (tags != active.TagsFrom && tags != active.Successor.Stamp) {
22 return hostbox.ErrChanged
23 }
24 if err = p.validateServingRecoveryAuthority(ctx, o, view, actor, r); err != nil {
25 return err
26 }
27 r, err = p.ledger.parkWithEvidenceLocked(ctx, r.Authorization, r.Receipts, r.LegacyEvidence)
28 if err != nil {
29 return err
30 }
31 if tags != active.Successor.Stamp {
32 return errServingParkRetagPending
33 }
34 return p.ledger.completeLocked(ctx, r.Authorization.ID, active.Successor)
35 })
36}
37
38func (p *servingParkRoot) recoverServingParks(ctx context.Context, after string, limit int) (servingParkRecoveryPage, error) {
39 var out servingParkRecoveryPage
40 if p == nil || p.ledger == nil {
41 return out, hostbox.ErrUnsupported
42 }
43 if after == "" {
44 err := p.ledger.withNamespace(ctx, func() error {
45 fs, ok := p.ledger.fs.(*servingParkFS)
46 if !ok {
47 return hostbox.ErrUnsupported
48 }
49 if err := fs.recoverRecordedNamespace(ctx); err == nil {
50 return nil
51 }
52 observation, err := fs.inspectRebootTopology(ctx)
53 if err != nil {
54 return err
55 }
56 binding := servingParkBootBinding{Version: 1, ID: "namespace", BeforeBoot: observation.Previous.BootID, BootID: observation.BootID, BeforeParent: observation.Previous.Parent, Parent: observation.CurrentParent}
57 if err := ctx.Err(); err != nil {
58 return err
59 }
60 if err := p.ledger.write("current-namespace.json", binding); err != nil {
61 return err
62 }
63 return fs.recoverRecordedNamespace(ctx)
64 })
65 if err != nil {
66 out.Results = append(out.Results, servingParkRecoveryResult{Host: "unknown", ID: "namespace", Err: err})
67 }
68 }
69 ids, more, err := p.ledger.recoveryIDs(ctx, after, limit)
70 if err != nil {
71 return out, err
72 }
73 out.More = more
74 for _, id := range ids {
75 if err = ctx.Err(); err != nil {
76 out.More = true
77 return out, err
78 }
79 r, readErr := p.ledger.read(id)
80 result := servingParkRecoveryResult{Host: "unknown", ID: id, Err: readErr}
81 if readErr == nil {
82 result.Host = r.Authorization.Successor.Host
83 fs, ok := p.ledger.fs.(*servingParkFS)
84 parentChanged := false
85 if ok {
86 parent, id, e := fs.parent()
87 if e != nil {
88 result.Err = e
89 } else {
90 parent.Close()
91 parentChanged = id != r.Source.Parent
92 }
93 }
94 if ok && result.Err == nil && r.Source.BootID != "" && (fs.checkBoot(r.Source.BootID) != nil || parentChanged) {
95 result.Err = p.commitServingReboot(ctx, id)
96 if result.Err == nil {
97 r, result.Err = p.ledger.read(id)
98 }
99 }
100 switch {
101 case result.Err != nil:
102
103 case !r.Complete:
104 result.Err = p.recoverServingPark(ctx, r)
105 default:
106 result.Err = p.ledger.recoverCompleted(ctx, id)
107 }
108 }
109 out.Results = append(out.Results, result)
110 out.Next = id
111 }
112 return out, nil
113}
114
115func (p *servingParkRoot) validateServingRecoveryAuthority(ctx context.Context, o hostclaim.Observed, view hostguard.FenceView, actor hostbox.Actor, r servingParkRecord) error {
116 active := r.activeAuthorization()
117 if err := validateServingRootHistory(ctx, o, view, actor, r); err != nil {
118 return err
119 }
120 // Any main-role intent is ambiguous at startup, even if a start reply
121 // was lost. Never resume a rename beneath a potentially live successor.
122 if err := p.ledger.legacyUnlaunched(ctx, active.Successor, actor.Enrollment); err != nil {
123 return err
124 }
125 if r.Authorization.Legacy {
126 consumed, e := p.ledger.legacyConsumption(active.Successor)
127 if e != nil || consumed == nil || !sameServingLegacyConsumption(*consumed, r) {
128 return hostbox.ErrChanged
129 }
130 if err := p.validateLegacyRootEvidence(ctx, o, view, actor, r.Authorization, r.LegacyEvidence, r.Receipts); err != nil {
131 return err
132 }
133 } else {
134 prior, e := servingPredecessor(o.Claim, active.Successor, r.Authorization.Predecessor.Stamp, r.Authorization.Predecessor.Generation)
135 if e != nil || prior != r.Authorization.Predecessor {
136 return hostbox.ErrChanged
137 }
138 receipts, e := servingRootStops(ctx, view, prior, actor)
139 if e != nil || !sameServingRootStops(receipts, r.Receipts) {
140 return ErrClaimStopReceipt
141 }
142 disposition, e := servingGenerationParkDisposition(ctx, p.ledger.journal, prior, receipts, r.Source.Files[0].Present)
143 if e != nil || disposition != r.Disposition {
144 return hostbox.ErrChanged
145 }
146 }
147 return nil
148}
149