carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package hostclaim
2
3import (
4 "encoding/json"
5 "errors"
6 "fmt"
7 "strings"
8 "time"
9)
10
11var ErrAckAlreadyApplied = errors.New("hostclaim: execution acknowledgement already applied")
12
13type ExecutionAcknowledgement struct {
14 Op string `json:"op"`
15 Enrollment string `json:"enrollment"`
16 BootID string `json:"boot_id"`
17 ControllerID string `json:"controller_id"`
18 LeaseETag string `json:"lease_etag"`
19 Expires time.Time `json:"expires"`
20}
21
22// AcknowledgeExecution records the acknowledged lease for one required
23// participant. The lease write and durable local state happen before this
24// transition. The first acknowledgement binds the participant's boot and
25// controller, and later ones only extend the same lease: a replacement must
26// carry the same op, enrollment, boot and controller, a lease ETag and a
27// strictly later expiry. Anything else is a conflicting acknowledgement and
28// is never overwritten.
29func AcknowledgeExecution(box string, ack ExecutionAcknowledgement) func(*Claim) error {
30 return func(c *Claim) error {
31 if !validBoxReference(box) || c.Op.Kind == "" || c.Op.Kind == KindServing || c.Op.ID == "" || ack.Op != c.Op.ID ||
32 ack.Enrollment == "" || ack.BootID == "" || ack.ControllerID == "" || ack.LeaseETag == "" || ack.Expires.IsZero() ||
33 !stringPresent(c.Op.Participants, box) {
34 return fmt.Errorf("%w: execution acknowledgement is not for a required active participant", ErrWrongState)
35 }
36 raw, err := json.Marshal(ack)
37 if err != nil {
38 return err
39 }
40 if c.Op.Journal == nil {
41 c.Op.Journal = map[string]string{}
42 }
43 key := "exec_ack." + box
44 if previous, ok := c.Op.Journal[key]; ok {
45 if previous == string(raw) {
46 return ErrAckAlreadyApplied
47 }
48 if !extendsAcknowledgement(previous, ack) {
49 return fmt.Errorf("%w: participant already acknowledged different lease", ErrWrongState)
50 }
51 }
52 c.Op.Journal[key] = string(raw)
53 return nil
54 }
55}
56
57// extendsAcknowledgement reports whether next only extends the lease that
58// previous acknowledged: the same op, enrollment, boot and controller, a lease
59// ETag, and a strictly later expiry. An undecodable previous value never is.
60func extendsAcknowledgement(previous string, next ExecutionAcknowledgement) bool {
61 dec := json.NewDecoder(strings.NewReader(previous))
62 dec.DisallowUnknownFields()
63 var prior ExecutionAcknowledgement
64 if dec.Decode(&prior) != nil || dec.More() {
65 return false
66 }
67 return prior.Op == next.Op && prior.Enrollment == next.Enrollment && prior.BootID == next.BootID && prior.ControllerID == next.ControllerID &&
68 next.LeaseETag != "" && next.Expires.After(prior.Expires)
69}
70
71func validBoxReference(box string) bool {
72 if box == "" || len(box) > 128 || strings.ContainsAny(box, "/\\\x00\r\n\t ") {
73 return false
74 }
75 return true
76}
77