carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package hostops
2
3import (
4 "context"
5 "errors"
6 "github.com/carlosframework/platform/internal/hostclaim"
7 "github.com/carlosframework/platform/internal/release"
8 "reflect"
9 "time"
10)
11
12// ReportAutomaticLosses materializes retained consequences even after operation
13// or holder replacement. The signed record is durable before reporting is marked.
14func (w *ControlWriter) ReportAutomaticLosses(ctx context.Context, signer release.Signer, host string) error {
15 if recoveryWriter(ctx) != w {
16 return ErrContract
17 }
18 if err := w.lossSigner(signer); err != nil {
19 return err
20 }
21 o, err := hostclaim.Read(ctx, w.raw, host)
22 if err != nil {
23 return err
24 }
25 if o.Absent {
26 return nil
27 }
28 for _, l := range o.Claim.EvidenceRefs {
29 if l.Reported {
30 continue
31 }
32 record, err := hostclaim.ReadLossRecord(ctx, w.raw, w.pub, l.ID)
33 if errors.Is(err, hostclaim.ErrLossRecordAbsent) {
34 at, e := time.Parse(time.RFC3339Nano, l.ObservedAt)
35 if e != nil {
36 return e
37 }
38 r := hostclaim.LossRecord{AlertsPending: true, V: 1, ID: l.ID, State: "prepared", Actor: "automatic", AcceptedAt: at, Host: host, HolderIncarnation: l.Incarnation, HolderStamp: l.Stamp, HolderSession: l.Session, ExpectedClaimGen: o.Claim.Gen, ExpectedClaimETag: o.ETag, OpID: l.Op, OpKind: l.Kind, OpPhase: l.Phase, Box: l.Box, Enrollment: l.Enrollment, FencedAt: at, Timers: hostclaim.TimerLoss{Knowledge: l.Timers}, Automatic: &l}
39 record, err = hostclaim.CreateLossRecord(ctx, w.raw, signer, r)
40 }
41 if err != nil {
42 return err
43 }
44 if !reflect.DeepEqual(record.Record.Automatic, &l) || record.Record.Host != host {
45 return hostclaim.ErrLossRecord
46 }
47 if record.Record.State == "prepared" {
48 next := record.Record
49 next.State = "committed"
50 next.ResultClaimGen = next.ExpectedClaimGen
51 record, err = hostclaim.ReplaceLossRecord(ctx, w.raw, signer, record, next)
52 if err != nil {
53 return err
54 }
55 }
56 if record.Record.State != "committed" {
57 return hostclaim.ErrLossRecord
58 }
59 o, err = hostclaim.Update(ctx, w.raw, o, func(c *hostclaim.Claim) error {
60 for i := range c.EvidenceRefs {
61 if c.EvidenceRefs[i].ID == l.ID {
62 if !reflect.DeepEqual(c.EvidenceRefs[i], l) {
63 return hostclaim.ErrLossRecord
64 }
65 c.EvidenceRefs[i].Reported = true
66 return nil
67 }
68 }
69 return hostclaim.ErrLossRecord
70 })
71 if err != nil {
72 return err
73 }
74 }
75 return nil
76}
77