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 "context"
7 "golang.org/x/sys/unix"
8 "os"
9 "os/exec"
10 "path/filepath"
11 "strconv"
12 "strings"
13 "testing"
14 "time"
15)
16
17func TestRootRebootFilesSeedTwoHostRenumberPhase1(t *testing.T) {
18 TestRootRebootFilesSeedTwoHostPhase1(t)
19}
20func TestRootRebootFilesSeedTwoHostRenumberPhase2(t *testing.T) {
21 TestRootRebootFilesSeedTwoHostPhase2(t)
22}
23
24func seedRunnerRebootDisk(t *testing.T) {
25 t.Helper()
26 command := func(args ...string) string {
27 t.Helper()
28 out, err := exec.CommandContext(t.Context(), args[0], args[1:]...).CombinedOutput()
29 if err != nil {
30 t.Fatalf("renumber disk %q: %v %s", args, err, out)
31 }
32 return strings.TrimSpace(string(out))
33 }
34 create := func(path string, size int64) {
35 t.Helper()
36 f, err := os.OpenFile(path, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0600)
37 if err != nil {
38 t.Fatal(err)
39 }
40 err = f.Truncate(size)
41 closeErr := f.Close()
42 if err != nil || closeErr != nil {
43 t.Fatal(err, closeErr)
44 }
45 }
46 detach := func(device string) {
47 t.Cleanup(func() {
48 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
49 defer cancel()
50 if out, err := exec.CommandContext(ctx, "losetup", "--detach", device).CombinedOutput(); err != nil {
51 t.Errorf("detach %s: %v %s", device, err, out)
52 }
53 })
54 }
55 image := filepath.Join(seedRebootPath, "data.ext4")
56 deviceFile := filepath.Join(seedRebootPath, "data.device")
57 first := strings.HasSuffix(t.Name(), "Phase1")
58 renumber := strings.Contains(t.Name(), "Renumber")
59 device := ""
60 if first {
61 create(image, 2<<30)
62 command("mkfs.ext4", "-q", "-F", image)
63 } else {
64 old, err := os.ReadFile(deviceFile)
65 if err != nil {
66 t.Fatal(err)
67 }
68 suffix := strings.TrimPrefix(string(old), "/dev/loop")
69 if suffix == string(old) {
70 t.Fatal("invalid loop device")
71 }
72 if _, err := strconv.ParseUint(suffix, 10, 32); err != nil {
73 t.Fatal(err)
74 }
75 if renumber {
76 blocker := filepath.Join(seedRebootPath, "blocker")
77 create(blocker, 1<<20)
78 command("losetup", string(old), blocker)
79 detach(string(old))
80 } else {
81 device = string(old)
82 command("losetup", device, image)
83 }
84 }
85 if device == "" {
86 device = command("losetup", "--find", "--show", image)
87 }
88 detach(device)
89 if first {
90 if err := os.WriteFile(deviceFile, []byte(device), 0600); err != nil {
91 t.Fatal(err)
92 }
93 } else {
94 old, err := os.ReadFile(deviceFile)
95 if err != nil || (string(old) != device) != renumber {
96 t.Fatal("unexpected reboot device number", err)
97 }
98 }
99 if err := unix.Mount(device, "/data", "ext4", unix.MS_NOSUID|unix.MS_NODEV, ""); err != nil {
100 t.Fatal(err)
101 }
102 t.Cleanup(func() {
103 if err := unix.Unmount("/data", 0); err != nil {
104 t.Error(err)
105 }
106 })
107 t.Logf("two-host data filesystem attached at %s", device)
108}
109
110func TestRootServingHandoverDirectoryProof(t *testing.T) {
111 servingRootRunner(t)
112 TestServingHandoverRebootDirectoryProof(t)
113 TestServingHandoverRebootEqualNumbers(t)
114}
115
116func TestRootServingParkRetainedDoesNotBlockRetirement(t *testing.T) {
117 servingRootRunner(t)
118 TestServingParkRetainedDoesNotBlockRetirement(t)
119 TestServingParkRetainedReplacementWriteFailures(t)
120 TestServingParkQuarantineRetainedParkAllowsRetirement(t)
121}
122