github.com/rumpl/bof@v23.0.0-rc.2+incompatible/integration/container/checkpoint_test.go (about) 1 package container // import "github.com/docker/docker/integration/container" 2 3 import ( 4 "context" 5 "fmt" 6 "os/exec" 7 "regexp" 8 "sort" 9 "testing" 10 "time" 11 12 "github.com/docker/docker/api/types" 13 mounttypes "github.com/docker/docker/api/types/mount" 14 "github.com/docker/docker/client" 15 "github.com/docker/docker/integration/internal/container" 16 "github.com/docker/docker/testutil/request" 17 "gotest.tools/v3/assert" 18 is "gotest.tools/v3/assert/cmp" 19 "gotest.tools/v3/poll" 20 "gotest.tools/v3/skip" 21 ) 22 23 //nolint:unused // false positive: linter detects this as "unused" 24 func containerExec(t *testing.T, client client.APIClient, cID string, cmd []string) { 25 t.Logf("Exec: %s", cmd) 26 ctx := context.Background() 27 r, err := container.Exec(ctx, client, cID, cmd) 28 assert.NilError(t, err) 29 t.Log(r.Combined()) 30 assert.Equal(t, r.ExitCode, 0) 31 } 32 33 func TestCheckpoint(t *testing.T) { 34 t.Skip("TestCheckpoint is broken; see https://github.com/moby/moby/issues/38963") 35 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 36 skip.If(t, !testEnv.DaemonInfo.ExperimentalBuild) 37 38 defer setupTest(t)() 39 40 cmd := exec.Command("criu", "check") 41 stdoutStderr, err := cmd.CombinedOutput() 42 t.Logf("%s", stdoutStderr) 43 assert.NilError(t, err) 44 45 ctx := context.Background() 46 client := request.NewAPIClient(t) 47 48 mnt := mounttypes.Mount{ 49 Type: mounttypes.TypeTmpfs, 50 Target: "/tmp", 51 } 52 53 t.Log("Start a container") 54 cID := container.Run(ctx, t, client, container.WithMount(mnt)) 55 poll.WaitOn(t, 56 container.IsInState(ctx, client, cID, "running"), 57 poll.WithDelay(100*time.Millisecond), 58 ) 59 60 cptOpt := types.CheckpointCreateOptions{ 61 Exit: false, 62 CheckpointID: "test", 63 } 64 65 { 66 // FIXME: ipv6 iptables modules are not uploaded in the test environment 67 cmd := exec.Command("bash", "-c", "set -x; "+ 68 "mount --bind $(type -P true) $(type -P ip6tables-restore) && "+ 69 "mount --bind $(type -P true) $(type -P ip6tables-save)") 70 stdoutStderr, err = cmd.CombinedOutput() 71 t.Logf("%s", stdoutStderr) 72 assert.NilError(t, err) 73 74 defer func() { 75 cmd := exec.Command("bash", "-c", "set -x; "+ 76 "umount -c -i -l $(type -P ip6tables-restore); "+ 77 "umount -c -i -l $(type -P ip6tables-save)") 78 stdoutStderr, err = cmd.CombinedOutput() 79 t.Logf("%s", stdoutStderr) 80 assert.NilError(t, err) 81 }() 82 } 83 t.Log("Do a checkpoint and leave the container running") 84 err = client.CheckpointCreate(ctx, cID, cptOpt) 85 if err != nil { 86 // An error can contain a path to a dump file 87 t.Logf("%s", err) 88 re := regexp.MustCompile("path= (.*): ") 89 m := re.FindStringSubmatch(fmt.Sprintf("%s", err)) 90 if len(m) >= 2 { 91 dumpLog := m[1] 92 t.Logf("%s", dumpLog) 93 cmd := exec.Command("cat", dumpLog) 94 stdoutStderr, err = cmd.CombinedOutput() 95 t.Logf("%s", stdoutStderr) 96 } 97 } 98 assert.NilError(t, err) 99 100 inspect, err := client.ContainerInspect(ctx, cID) 101 assert.NilError(t, err) 102 assert.Check(t, is.Equal(true, inspect.State.Running)) 103 104 checkpoints, err := client.CheckpointList(ctx, cID, types.CheckpointListOptions{}) 105 assert.NilError(t, err) 106 assert.Equal(t, len(checkpoints), 1) 107 assert.Equal(t, checkpoints[0].Name, "test") 108 109 // Create a test file on a tmpfs mount. 110 containerExec(t, client, cID, []string{"touch", "/tmp/test-file"}) 111 112 // Do a second checkpoint 113 cptOpt = types.CheckpointCreateOptions{ 114 Exit: true, 115 CheckpointID: "test2", 116 } 117 t.Log("Do a checkpoint and stop the container") 118 err = client.CheckpointCreate(ctx, cID, cptOpt) 119 assert.NilError(t, err) 120 121 poll.WaitOn(t, 122 container.IsInState(ctx, client, cID, "exited"), 123 poll.WithDelay(100*time.Millisecond), 124 ) 125 126 inspect, err = client.ContainerInspect(ctx, cID) 127 assert.NilError(t, err) 128 assert.Check(t, is.Equal(false, inspect.State.Running)) 129 130 // Check that both checkpoints are listed. 131 checkpoints, err = client.CheckpointList(ctx, cID, types.CheckpointListOptions{}) 132 assert.NilError(t, err) 133 assert.Equal(t, len(checkpoints), 2) 134 cptNames := make([]string, 2) 135 for i, c := range checkpoints { 136 cptNames[i] = c.Name 137 } 138 sort.Strings(cptNames) 139 assert.Equal(t, cptNames[0], "test") 140 assert.Equal(t, cptNames[1], "test2") 141 142 // Restore the container from a second checkpoint. 143 startOpt := types.ContainerStartOptions{ 144 CheckpointID: "test2", 145 } 146 t.Log("Restore the container") 147 err = client.ContainerStart(ctx, cID, startOpt) 148 assert.NilError(t, err) 149 150 inspect, err = client.ContainerInspect(ctx, cID) 151 assert.NilError(t, err) 152 assert.Check(t, is.Equal(true, inspect.State.Running)) 153 154 // Check that the test file has been restored. 155 containerExec(t, client, cID, []string{"test", "-f", "/tmp/test-file"}) 156 157 for _, id := range []string{"test", "test2"} { 158 cptDelOpt := types.CheckpointDeleteOptions{ 159 CheckpointID: id, 160 } 161 162 err = client.CheckpointDelete(ctx, cID, cptDelOpt) 163 assert.NilError(t, err) 164 } 165 }