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 "crypto/sha256"
7 "encoding/hex"
8 "encoding/json"
9
10 "github.com/carlosframework/platform/internal/hostactors"
11 "github.com/carlosframework/platform/internal/hostbox"
12 "github.com/carlosframework/platform/internal/hostclaim"
13 "github.com/carlosframework/platform/internal/hostevidence"
14 "github.com/carlosframework/platform/internal/release"
15)
16
17// RelocationReleaseReceipts discharges only the stop obligation. The region
18// worker still owns the journal and executor transfer after this CAS.
19type RelocationReleaseReceipts struct {
20 Store release.Store
21 Directory hostactors.Directory
22}
23
24func (r RelocationReleaseReceipts) Complete(ctx context.Context, observed hostclaim.Observed, key, digest string) (hostclaim.Observed, error) {
25 if ctx == nil || r.Store == nil || observed.Absent || observed.Claim == nil || observed.Claim.Holder == nil || observed.ETag == "" {
26 return hostclaim.Observed{}, ErrClaimStopIdentity
27 }
28 c := observed.Claim
29 if c.Op.Kind != hostclaim.KindRelocating || c.Op.Phase != "releasing" || c.Op.ID == "" || c.Op.Exec != c.Op.Intent["source_box"] || c.Op.Exec == "" {
30 return hostclaim.Observed{}, ErrClaimStopIdentity
31 }
32 raw, _, err := r.Store.Get(ctx, key)
33 if err != nil {
34 return hostclaim.Observed{}, err
35 }
36 sum := sha256.Sum256(raw)
37 if hex.EncodeToString(sum[:]) != digest {
38 return hostclaim.Observed{}, ErrClaimStopReceipt
39 }
40 var receipt StopReceipt
41 if json.Unmarshal(raw, &receipt) != nil {
42 return hostclaim.Observed{}, ErrClaimStopReceipt
43 }
44 canonical, err := json.Marshal(receipt)
45 if err != nil || !bytes.Equal(raw, canonical) {
46 return hostclaim.Observed{}, ErrClaimStopReceipt
47 }
48 h := c.Holder
49 if receipt.V != 1 || key != stopEvidenceKey(c.Host, c.Op.ID, c.Op.Exec, receipt.ID) || receipt.Host != c.Host || receipt.Incarnation != h.Incarnation || receipt.InstallationStamp != h.Stamp || receipt.WriterSession != h.Session || receipt.OperationID != c.Op.ID || receipt.Phase != c.Op.Phase || receipt.ObligationID != "relocation-release" || receipt.Box != c.Op.Exec || receipt.Region != c.Op.Intent["region"] || receipt.Enrollment != c.Op.Intent["source_enrollment"] || receipt.EvidenceAt.IsZero() || receipt.RequestLimitNS != int64(hostbox.RequestLimit) || receipt.ClaimGen == 0 || len(receipt.CgroupIdentities) == 0 || !stopDigest(receipt.InventorySHA256) || !stopDigest(receipt.LocalJournalSHA256) {
50 return hostclaim.Observed{}, ErrClaimStopReceipt
51 }
52 if h.Session == 0 {
53 replayed := c.Op.Journal["release_stop_receipt"] == key && c.Op.Journal["release_stop_sha256"] == digest
54 if receipt.Kind != StopReceiptNoProcess || receipt.FenceID != "" || receipt.ProducerDrainDigest != "" || receipt.ClaimETag == "" || (!replayed && receipt.ClaimETag != observed.ETag) || h.WriterBox != "" || h.Generation != "" || len(h.Admissions) != 0 {
55 return hostclaim.Observed{}, ErrClaimStopReceipt
56 }
57 } else if receipt.Kind != "stopped" || receipt.FenceID == "" || !stopDigest(receipt.ProducerDrainDigest) {
58 return hostclaim.Observed{}, ErrClaimStopReceipt
59 }
60 roster, err := r.Directory.Read(ctx)
61 if err != nil {
62 return hostclaim.Observed{}, err
63 }
64 box, ok := roster.Roster.Boxes[receipt.Box]
65 if !ok || box.Enrollment != receipt.Enrollment || box.Region != receipt.Region {
66 return hostclaim.Observed{}, ErrClaimStopIdentity
67 }
68 signature, _, err := r.Store.Get(ctx, key+".sig")
69 if err != nil {
70 return hostclaim.Observed{}, err
71 }
72 if err = hostevidence.Verify(box.CensusPublicKey, key, raw, signature); err != nil {
73 return hostclaim.Observed{}, err
74 }
75 if c.Op.Journal["release_stop_receipt"] == key && c.Op.Journal["release_stop_sha256"] == digest {
76 for _, ob := range c.Obligations {
77 if ob.ID == receipt.ObligationID && ob.Op == receipt.OperationID {
78 return hostclaim.Observed{}, ErrClaimStopReceipt
79 }
80 }
81 return observed, nil
82 }
83 if c.Op.Journal["release_stop_receipt"] != "" || c.Op.Journal["release_stop_sha256"] != "" {
84 return hostclaim.Observed{}, ErrClaimStopReceipt
85 }
86 return hostclaim.Update(ctx, r.Store, observed, func(next *hostclaim.Claim) error {
87 for i, ob := range next.Obligations {
88 if ob.ID == receipt.ObligationID && ob.Op == receipt.OperationID && ob.Kind == "relocation-release" && ob.Park == nil && ob.Box == receipt.Box && ob.Region == receipt.Region && ob.Owner == "region:"+receipt.Region {
89 if next.Op.Journal == nil {
90 next.Op.Journal = map[string]string{}
91 }
92 next.Op.Journal["release_stop_receipt"] = key
93 next.Op.Journal["release_stop_sha256"] = digest
94 next.Obligations = append(next.Obligations[:i], next.Obligations[i+1:]...)
95 return nil
96 }
97 }
98 return hostclaim.ErrWrongState
99 })
100}
101