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 "reflect"
6 "strconv"
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 claimCrossBoxHandover) installRecoveryRemote(ctx context.Context, prior, admitted hostclaim.Observed) error {
14 if h.RecoveryRebind == nil || h.Inventory == nil || h.Guard.FenceView == nil {
15 return hostbox.ErrUnsupported
16 }
17 actor, err := h.Identity.Verify(ctx)
18 if err != nil {
19 return err
20 }
21 stamp, err := strconv.ParseUint(prior.Claim.Op.Journal[hostclaim.JournalSourceStamp], 10, 64)
22 if err != nil || stamp == 0 {
23 return hostbox.ErrChanged
24 }
25 next := admitted.Claim.Holder
26 captured := hostguard.Captured{Incarnation: next.Incarnation, Stamp: stamp}
27 successor := hostguard.Captured{Incarnation: next.Incarnation, Stamp: next.Stamp}
28 for attempt := 0; attempt < 3; attempt++ {
29 source, revision, err := h.Inventory.Snapshot(ctx, prior.Host, captured)
30 if err != nil {
31 return err
32 }
33 var q recoveryRebindRequest
34 err = h.Guard.WithLocal(ctx, prior.Host, func() error {
35 fresh, err := hostclaim.Read(ctx, h.Evidence, prior.Host)
36 if err != nil {
37 return err
38 }
39 if fresh.ETag != admitted.ETag || !hostclaim.SameWriterIdentity(fresh, admitted) {
40 return hostbox.ErrChanged
41 }
42 view, err := h.Guard.FenceView(ctx, prior.Host, captured)
43 if err != nil {
44 return err
45 }
46 if view.Installation.Stamp != stamp && view.Installation.Stamp != next.Stamp || view.Installation.Stamp == stamp && view.Installation.InventoryRevision != revision {
47 return hostbox.ErrChanged
48 }
49 _, etag, err := rootClaimRecord(ctx, h.Evidence, fresh.Claim, h.Guard.DataDir)
50 if err != nil {
51 return err
52 }
53 q = recoveryRebindRequest{V: 1, Prior: captured, Revision: revision, RecordKey: next.Key, RecordETag: etag, Next: hostbox.ColdSuccessor{Host: admitted.Host, Incarnation: next.Incarnation, Stamp: next.Stamp, Session: next.Session, Generation: next.Generation, Box: actor.Box, Enrollment: actor.Enrollment, DirectoryRevision: actor.Binding, ETag: admitted.ETag, Op: admitted.Claim.Op.ID, Phase: admitted.Claim.Op.Phase}}
54 return nil
55 })
56 if err != nil {
57 return err
58 }
59 if err = h.RecoveryRebind(ctx, q); err != nil {
60 return err
61 }
62 if err = h.Guard.Activate(ctx, admitted.Host, h.Box, nil); err != nil {
63 return err
64 }
65 current, rev, err := h.Inventory.Snapshot(ctx, prior.Host, successor)
66 if err != nil {
67 return err
68 }
69 err = h.Guard.With(ctx, prior.Host, successor, func(c *hostclaim.Claim) error {
70 if !hostclaim.SameWriterIdentity(admitted, hostclaim.Observed{Host: admitted.Host, Claim: c}) {
71 return hostbox.ErrChanged
72 }
73 return nil
74 }, func() error {
75 fresh, err := hostclaim.Read(ctx, h.Evidence, prior.Host)
76 if err != nil {
77 return err
78 }
79 if fresh.ETag != admitted.ETag || !hostclaim.SameWriterIdentity(fresh, admitted) {
80 return hostbox.ErrChanged
81 }
82 view, err := h.Guard.FenceView(ctx, prior.Host, successor)
83 if err != nil {
84 return err
85 }
86 if view.Installation.Stamp != next.Stamp || view.Installation.Incarnation != next.Incarnation || view.Installation.InventoryRevision != rev || rev != 1 || !reflect.DeepEqual(current, recoveryInventory(source, q.Next)) {
87 return hostbox.ErrChanged
88 }
89 _, etag, err := rootClaimRecord(ctx, h.Evidence, fresh.Claim, h.Guard.DataDir)
90 if err != nil {
91 return err
92 }
93 if etag != q.RecordETag {
94 return hostbox.ErrChanged
95 }
96 source.InstallationStamp = next.Stamp
97 owner := ""
98 for _, e := range current.Entries {
99 if e.Kind == "route" {
100 owner = e.Ownership
101 }
102 }
103 if owner == "" {
104 return hostbox.ErrTypedInventory
105 }
106 return h.rebindRecoveryRows(ctx, &source, stamp, owner)
107 })
108 if err == hostbox.ErrChanged {
109 continue
110 }
111 if err != nil {
112 return err
113 }
114 return nil
115 }
116 return hostbox.ErrChanged
117}
118