carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1//go:build linux
2
3package host
4
5import (
6 "context"
7 "errors"
8 "fmt"
9 "os"
10 "path/filepath"
11 "reflect"
12
13 "github.com/carlosframework/platform/internal/hostbox"
14 "github.com/carlosframework/platform/internal/hostguard"
15)
16
17// systemd removes an edge unit's empty delegated subtree after SIGKILL. A
18// seed that never reserved a tenant role can settle that absence in the same
19// boot. This path neither kills a replacement group nor invents a reboot.
20func (k LinuxStopKernel) recoverUnlaunchedAbsent(ctx context.Context, t hostguard.FenceTarget, in StopInventory, j hostbox.StopKernelJournal, journal interface {
21 SettleRecovered(context.Context, hostguard.FenceTarget) error
22}) (StopKernelEvidence, DrainAcknowledgement, error) {
23 refuse := func(err error) (StopKernelEvidence, DrainAcknowledgement, error) {
24 return StopKernelEvidence{}, DrainAcknowledgement{}, err
25 }
26 if j.V != 1 || j.PendingRoles || len(j.Cgroups) != 1 || len(j.UnitReservationIDs) != 0 {
27 return refuse(ErrClaimStopInventory)
28 }
29 raw, ok := k.Journal.(interface {
30 Read(context.Context, hostguard.FenceTarget) (hostbox.LaunchInventory, error)
31 })
32 if !ok {
33 return refuse(ErrClaimStopInventory)
34 }
35 launch, err := raw.Read(ctx, t)
36 if err != nil {
37 return refuse(err)
38 }
39 if len(launch.Reservations) != 0 || len(launch.Groups) != 1 {
40 return refuse(ErrClaimStopInventory)
41 }
42 paths, err := k.stopDescriptorPaths(in)
43 if err != nil {
44 return refuse(err)
45 }
46 check := func(expected hostbox.StopKernelJournal) error {
47 fresh, err := k.readContainedJournal(ctx, t)
48 if err != nil {
49 return err
50 }
51 if !reflect.DeepEqual(fresh, expected) {
52 return ErrClaimStopInventory
53 }
54 again, err := raw.Read(ctx, t)
55 if err != nil {
56 return err
57 }
58 if len(again.Reservations) != 0 || !reflect.DeepEqual(again.Groups, launch.Groups) {
59 return ErrClaimStopInventory
60 }
61 boot, err := recoveryControllerAt(k.ProcRoot, t, fresh)
62 if err != nil {
63 return err
64 }
65 if boot != t.BootID {
66 return ErrClaimStopIdentity
67 }
68 if _, err := os.Lstat(filepath.Join(k.CgroupRoot, j.Cgroups[0].RelativePath)); !errors.Is(err, os.ErrNotExist) {
69 if err != nil {
70 return err
71 }
72 return ErrClaimStopInventory
73 }
74 return scanStopDescriptors(ctx, k.ProcRoot, j.Files, paths)
75 }
76 if err := check(j); err != nil {
77 return refuse(err)
78 }
79 if err := journal.SettleRecovered(ctx, t); err != nil {
80 return refuse(err)
81 }
82 settled := j
83 settled.Settled = true
84 if err := check(settled); err != nil {
85 return refuse(err)
86 }
87 group := j.Cgroups[0]
88 evidence := StopKernelEvidence{ObservedBootID: t.BootID, InventorySHA256: digestStop(in), LocalJournalSHA256: digestStop(settled), CgroupIdentities: []string{fmt.Sprintf("unlaunched-absent=%s;previous_identity=%d:%d;controller=%s", group.RelativePath, group.Device, group.Inode, t.ControllerID)}, UnitInvocationIDs: []string{}}
89 return evidence, DrainClaimAcknowledgement(t.FenceID, t.ControllerID, j.ProcessStart, j.ProducerIDs, j.Completed), nil
90}
91