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 "errors"
5 "os"
6
7 "github.com/carlosframework/platform/internal/hostbox"
8 "github.com/carlosframework/platform/internal/rootstate"
9)
10
11// A binding changes only boot-local device and mount numbers. Durable records keep their
12// original identities; progress writes translate back to those identities.
13type servingParkBootBinding struct {
14 Volume string `json:",omitempty"`
15 Version int
16 ID, BeforeBoot, BootID string
17 BeforeParent, Parent servingArtifactDirectory
18}
19
20func servingParkReadBinding(state rootstate.Store, id string) (*servingParkBootBinding, error) {
21 body, err := state.Read("current-" + id + ".json")
22 if errors.Is(err, os.ErrNotExist) {
23 return nil, nil
24 }
25 if err != nil {
26 return nil, err
27 }
28 var b servingParkBootBinding
29 if servingParkDecode(body, &b) != nil || b.Version != 1 || b.ID != id || !validServingParkBootID(b.BeforeBoot) || !validServingParkBootID(b.BootID) || (b.BeforeBoot == b.BootID && b.BeforeParent.Device != b.Parent.Device) || b.BeforeParent.Device == 0 || b.BeforeParent.Inode == 0 || b.BeforeParent.Mount == 0 || b.Parent.Device == 0 || b.Parent.Inode != b.BeforeParent.Inode || b.Parent.Mount == 0 {
30 return nil, hostbox.ErrChanged
31 }
32 return &b, nil
33}
34
35func (b servingParkBootBinding) directory(d *servingArtifactDirectory, reverse bool) error {
36 if *d == (servingArtifactDirectory{}) {
37 return nil
38 }
39 from, to := b.BeforeParent, b.Parent
40 if reverse {
41 from, to = to, from
42 }
43 if d.Device != from.Device || d.Mount != from.Mount {
44 return hostbox.ErrChanged
45 }
46 d.Device, d.Mount = to.Device, to.Mount
47 return nil
48}
49
50func (b servingParkBootBinding) record(r *servingParkRecord, reverse bool) error {
51 from, to := b.BeforeBoot, b.BootID
52 if reverse {
53 from, to = to, from
54 }
55 parent := b.BeforeParent
56 if reverse {
57 parent = b.Parent
58 }
59 if b.ID != "retirement-"+r.Authorization.ID || r.Source.BootID != from || r.Source.Parent != parent {
60 return hostbox.ErrChanged
61 }
62 r.Source.BootID = to
63 for _, d := range []*servingArtifactDirectory{&r.Source.Directory, &r.Source.Parent, &r.Namespace, &r.Event, &r.Authorization.Directory} {
64 if err := b.directory(d, reverse); err != nil {
65 return err
66 }
67 }
68 // Copy before changing slices shared with a caller's immutable snapshot.
69 r.Continuations = append([]servingParkContinuation(nil), r.Continuations...)
70 for i := range r.Continuations {
71 if err := b.directory(&r.Continuations[i].Authorization.Directory, reverse); err != nil {
72 return err
73 }
74 }
75 for i := range r.Source.Files {
76 f := &r.Source.Files[i]
77 if !f.Present {
78 continue
79 }
80 d := servingArtifactDirectory{Device: f.Device, Inode: f.Inode, Mount: f.Mount}
81 if err := b.directory(&d, reverse); err != nil {
82 return err
83 }
84 f.Device, f.Mount = d.Device, d.Mount
85 }
86 return nil
87}
88
89func (l *servingParkLedger) bindRecord(r *servingParkRecord, reverse bool) error {
90 if l.historical {
91 return nil
92 }
93 b, err := servingParkReadBinding(l.state, "retirement-"+r.Authorization.ID)
94 if err != nil || b == nil {
95 return err
96 }
97 return b.record(r, reverse)
98}
99