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 && rootrunner
2
3package host
4
5import (
6 "bytes"
7 "context"
8 "os"
9 "os/exec"
10 "path/filepath"
11 "reflect"
12 "strings"
13 "testing"
14 "time"
15
16 "github.com/carlosframework/platform/internal/instancefs"
17 "golang.org/x/sys/unix"
18)
19
20func servingRunnerScratchFilesystem(t *testing.T, dir string, size int64) string {
21 t.Helper()
22 image := filepath.Join(dir, "scratch.ext4")
23 f, err := os.OpenFile(image, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0600)
24 if err != nil {
25 t.Fatal(err)
26 }
27 err = f.Truncate(size)
28 closeErr := f.Close()
29 if err != nil || closeErr != nil {
30 t.Fatal(err, closeErr)
31 }
32 if out, err := exec.CommandContext(t.Context(), "mkfs.ext4", "-q", "-F", image).CombinedOutput(); err != nil {
33 t.Fatal(err, string(out))
34 }
35 out, err := exec.CommandContext(t.Context(), "losetup", "--find", "--show", image).CombinedOutput()
36 if err != nil {
37 t.Fatal(err, string(out))
38 }
39 device := strings.TrimSpace(string(out))
40 t.Cleanup(func() {
41 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
42 defer cancel()
43 if out, err := exec.CommandContext(ctx, "losetup", "--detach", device).CombinedOutput(); err != nil {
44 t.Error(err, string(out))
45 }
46 })
47 mount := filepath.Join(dir, "scratch")
48 if err := os.Mkdir(mount, 0700); err != nil {
49 t.Fatal(err)
50 }
51 if err := unix.Mount(device, mount, "ext4", unix.MS_NOSUID|unix.MS_NODEV, ""); err != nil {
52 t.Fatal(err)
53 }
54 t.Cleanup(func() {
55 if err := unix.Unmount(mount, 0); err != nil {
56 t.Error(err)
57 }
58 })
59 t.Logf("private fixture filesystem: %d MiB on %s", size>>20, device)
60 return mount
61}
62
63func TestRootServingParkSnapshotClone(t *testing.T) {
64 servingRootRunner(t)
65 // This runner really is EBS/NVMe; exercise the production sysfs resolver.
66 rootDir, err := os.Open("/")
67 if err != nil {
68 t.Fatal(err)
69 }
70 id, err := servingParkDirID(rootDir)
71 rootDir.Close()
72 if err != nil || servingParkVolume(id.Device) == "" {
73 t.Fatal("runner has no readable EBS volume identity", err)
74 }
75 t.Log("kernel backing EBS volume", servingParkVolume(id.Device))
76 base := t.TempDir()
77 mount := servingRunnerScratchFilesystem(t, base, 64<<20)
78 t.Setenv("TMPDIR", mount)
79 t.Run("clone", func(t *testing.T) {
80 f, r := servingRebootRecordFixture(t, "complete")
81 if err := f.ledger.journal.Close(); err != nil {
82 t.Fatal(err)
83 }
84 servingRunnerMount(t, f.data)
85 f.fs.mount = instancefs.MountNoSymfollow
86 before := r.Source.Files
87 // Tear down the nested bind for the block-level snapshot, then recreate it.
88 instances := filepath.Join(f.data, "instances")
89 if err := unix.Unmount(instances, 0); err != nil {
90 t.Fatal(err)
91 }
92 if err := unix.Unmount(mount, 0); err != nil {
93 t.Fatal(err)
94 }
95 clone := filepath.Join(base, "clone.ext4")
96 if out, err := exec.CommandContext(t.Context(), "cp", "--sparse=always", filepath.Join(base, "scratch.ext4"), clone).CombinedOutput(); err != nil {
97 t.Fatal(err, string(out))
98 }
99 out, err := exec.CommandContext(t.Context(), "losetup", "--find", "--show", clone).CombinedOutput()
100 if err != nil {
101 t.Fatal(err, string(out))
102 }
103 device := strings.TrimSpace(string(out))
104 // The original helper owns unmount; detach this device only after that.
105 defer func() {
106 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
107 defer cancel()
108 if out, err := exec.CommandContext(ctx, "losetup", "--detach", device).CombinedOutput(); err != nil {
109 t.Error(err, string(out))
110 }
111 }()
112 if err := unix.Mount(device, mount, "ext4", unix.MS_NOSUID|unix.MS_NODEV, ""); err != nil {
113 t.Fatal(err)
114 }
115 if err := unix.Mount(instances, instances, "", unix.MS_BIND, ""); err != nil {
116 t.Fatal(err)
117 }
118 if err := unix.Mount("", instances, "", unix.MS_BIND|unix.MS_REMOUNT|unix.MS_NOSYMFOLLOW|unix.MS_NOSUID|unix.MS_NODEV|unix.MS_NOEXEC, ""); err != nil {
119 t.Fatal(err)
120 }
121 // Loop devices have no EBS serial. Model only this hardware boundary;
122 // filesystem identity and cloning below are real kernel observations.
123 f.fs.volume = func(uint64) string { return "vol11111111111111111" }
124 path := f.path(r.Authorization, "")
125 original, err := os.ReadFile(path)
126 if err != nil {
127 t.Fatal(err)
128 }
129 changed := bytes.Repeat([]byte{'X'}, len(original))
130 if err := os.WriteFile(path, changed, 0600); err != nil {
131 t.Fatal(err)
132 }
133 observation, err := f.fs.inspectRebootRecord(t.Context(), r.Authorization.ID)
134 if err != nil || !reflect.DeepEqual(observation.Record.Source.Files, before) {
135 t.Fatal("clone did not preserve filesystem proof", err)
136 }
137 if observation.Topology.CurrentParent.Device == r.Source.Parent.Device {
138 t.Fatal("clone did not change device")
139 }
140 root := &servingParkRoot{ledger: f.ledger}
141 if err := root.commitServingReboot(t.Context(), r.Authorization.ID); err != nil {
142 t.Fatal("retention recovery", err)
143 }
144 f.now = r.ReapAfter
145 if err := f.ledger.reapLocked(t.Context(), r.Authorization.ID); err == nil {
146 t.Fatal("snapshot clone reaped")
147 }
148 for _, item := range r.Source.Files {
149 if item.Present {
150 if _, err := os.Stat(f.path(r.Authorization, strings.TrimPrefix(item.Name, r.Authorization.Successor.Host+".db"))); err != nil {
151 t.Fatal("clone artifact removed", err)
152 }
153 }
154 }
155 got, err := os.ReadFile(path)
156 if err != nil || !bytes.Equal(got, changed) {
157 t.Fatal("clone bytes changed", err)
158 }
159 t.Log("snapshot clone preserves handles/inodes, changes content and volume serial; recovery succeeds and deletion refuses")
160 // Explicit test-only root re-enrollment is the positive control: with the
161 // original serial now asserted, the very same cloned artifacts can be reaped.
162 // This makes the serial refusal decisive, rather than an unrelated mismatch.
163 binding, err := servingParkReadBinding(f.disk, "retirement-"+r.Authorization.ID)
164 if err != nil || binding == nil || binding.Volume != "" {
165 t.Fatal("clone acquired destructive binding", binding, err)
166 }
167 binding.Volume = r.Source.Volume
168 if err := f.ledger.write("current-retirement-"+r.Authorization.ID+".json", binding); err != nil {
169 t.Fatal(err)
170 }
171 f.fs.volume = func(uint64) string { return r.Source.Volume }
172 if err := f.ledger.reapLocked(t.Context(), r.Authorization.ID); err != nil {
173 t.Fatal("same-volume control has another refusal", err)
174 }
175 if _, err := os.Stat(path); !os.IsNotExist(err) {
176 t.Fatal("same-volume control did not delete", err)
177 }
178 t.Log("same snapshot with explicit fixture root re-enrollment reaped successfully; volume guard was decisive")
179 })
180}
181