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 "os"
7 "path"
8 "strings"
9
10 "github.com/carlosframework/platform/internal/instancectl"
11 "github.com/carlosframework/platform/internal/rootstate"
12)
13
14type claimUnitPredecessor struct {
15 Unit, Invocation, Group string
16 Boot string `json:",omitempty"`
17 GroupIdentity rootstate.FileIdentity
18}
19
20type claimUnitMigration struct {
21 Definition rootstate.FileIdentity
22 Digest string
23 Predecessor claimUnitPredecessor
24 Socket claimUnitSocketIdentity `json:",omitempty"`
25}
26
27type claimUnitSocketIdentity struct {
28 Boot string
29 Device, Inode uint64
30 UID, GID, Mode uint32
31}
32
33func (p claimUnitPredecessor) valid(unit string) bool {
34 return p.Unit == unit && instancectl.ValidBoundClaimUnit(unit) && p.Invocation != "" && claimPredecessorPlacement(unit, p.Group) && p.GroupIdentity != (rootstate.FileIdentity{})
35}
36
37func (r claimUnitMigration) valid(b claimUnitBinding) bool {
38 return r.Definition != (rootstate.FileIdentity{}) && claimHexDigest(r.Digest) && r.Digest == b.Shape.PredecessorDigest && r.Predecessor.valid(b.Shape.Unit)
39}
40
41// The materialization lock and root host lock cover capture through replacement.
42// Only the root configuration's exact digest admits an operator definition.
43func (m claimUnitMaterializer) migration(ctx context.Context, b claimUnitBinding, raw []byte, id rootstate.FileIdentity) (*claimUnitMigration, error) {
44 if !claimHexDigest(b.Shape.PredecessorDigest) || claimUnitDigest(raw) != b.Shape.PredecessorDigest || id == (rootstate.FileIdentity{}) || m.predecessor == nil || m.stopPredecessor == nil || m.replace == nil {
45 return nil, os.ErrPermission
46 }
47 p, err := m.predecessor(ctx, b)
48 if err != nil {
49 return nil, err
50 }
51 r := &claimUnitMigration{Definition: id, Digest: claimUnitDigest(raw), Predecessor: p}
52 if claimFlatSocket(b.Shape) {
53 if m.socketCapture == nil || m.socketPark == nil {
54 return nil, os.ErrPermission
55 }
56 r.Socket, err = m.socketCapture(ctx, b.Shape, p)
57 if err != nil {
58 return nil, err
59 }
60 }
61 if !r.valid(b) {
62 return nil, os.ErrPermission
63 }
64 return r, nil
65}
66
67func (m claimUnitMaterializer) finishMigration(ctx context.Context, r claimUnitMaterialization, want []byte) error {
68 if r.Migration == nil || !r.Migration.valid(r.Binding) || m.stopPredecessor == nil || m.replace == nil {
69 return os.ErrPermission
70 }
71 raw, id, err := m.read(r.Binding.Shape.Unit)
72 if err != nil {
73 return err
74 }
75 if id.Same(r.Migration.Definition) && claimUnitDigest(raw) == r.Migration.Digest {
76 if err = m.stopPredecessor(ctx, r.Migration.Predecessor); err != nil {
77 return err
78 }
79 if err = m.idle(r.Binding.Shape.Host); err != nil {
80 return err
81 }
82 if err = m.finishSocketMigration(r); err != nil {
83 return err
84 }
85 if err = m.replace(r.Binding.Shape.Unit, id, want); err != nil {
86 return err
87 }
88 raw, id, err = m.read(r.Binding.Shape.Unit)
89 if err != nil {
90 return err
91 }
92 } else if !bytes.Equal(raw, want) {
93 return os.ErrPermission
94 }
95 if !bytes.Equal(raw, want) || id == (rootstate.FileIdentity{}) {
96 return os.ErrPermission
97 }
98 // A crash after rename still has to prove the predecessor gone. The durable
99 // definition refuses execution until a later root reservation opens its gate.
100 if err = m.stopPredecessor(ctx, r.Migration.Predecessor); err != nil {
101 return err
102 }
103 if err = m.idle(r.Binding.Shape.Host); err != nil {
104 return err
105 }
106 if err = m.finishSocketMigration(r); err != nil {
107 return err
108 }
109 r.Identity = id
110 return m.save(r)
111}
112
113func (m claimUnitMaterializer) finishSocketMigration(r claimUnitMaterialization) error {
114 if !claimFlatSocket(r.Binding.Shape) {
115 return nil
116 }
117 if r.Migration == nil || r.Migration.Socket.Boot == "" || m.socketPark == nil {
118 return os.ErrPermission
119 }
120 return m.socketPark(r.Binding, r.Migration.Socket)
121}
122
123func claimPredecessorPlacement(unit, group string) bool {
124 if !instancectl.ValidBoundClaimUnit(unit) {
125 return false
126 }
127 if group == "system.slice/"+unit {
128 return true
129 }
130 prefix, _, template := strings.Cut(unit, "@")
131 return template && prefix != "" && group == path.Join("system.slice", "system-"+instancectl.Escape(prefix)+".slice", unit)
132}
133