소스 검색

Merge pull request #38452 from avagin/cr-test

integration/container: add a base test for C/R
Sebastiaan van Stijn 6 년 전
부모
커밋
54dddadc7d
3개의 변경된 파일168개의 추가작업 그리고 11개의 파일을 삭제
  1. 4 1
      Dockerfile
  2. 1 10
      daemon/checkpoint.go
  3. 163 0
      integration/container/checkpoint_test.go

+ 4 - 1
Dockerfile

@@ -31,7 +31,7 @@ RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list
 
 FROM base AS criu
 # Install CRIU for checkpoint/restore support
-ENV CRIU_VERSION 3.6
+ENV CRIU_VERSION 3.11
 # Install dependency packages specific to criu
 RUN apt-get update && apt-get install -y \
 	libnet-dev \
@@ -203,6 +203,9 @@ RUN apt-get update && apt-get install -y \
 	zip \
 	bzip2 \
 	xz-utils \
+	libprotobuf-c1 \
+	libnet1 \
+	libnl-3-200 \
 	--no-install-recommends
 COPY --from=swagger /build/swagger* /usr/local/bin/
 COPY --from=frozen-images /build/ /docker-frozen-images

+ 1 - 10
daemon/checkpoint.go

@@ -2,7 +2,6 @@ package daemon // import "github.com/docker/docker/daemon"
 
 import (
 	"context"
-	"encoding/json"
 	"fmt"
 	"io/ioutil"
 	"os"
@@ -127,15 +126,7 @@ func (daemon *Daemon) CheckpointList(name string, config types.CheckpointListOpt
 		if !d.IsDir() {
 			continue
 		}
-		path := filepath.Join(checkpointDir, d.Name(), "config.json")
-		data, err := ioutil.ReadFile(path)
-		if err != nil {
-			return nil, err
-		}
-		var cpt types.Checkpoint
-		if err := json.Unmarshal(data, &cpt); err != nil {
-			return nil, err
-		}
+		cpt := types.Checkpoint{Name: d.Name()}
 		out = append(out, cpt)
 	}
 

+ 163 - 0
integration/container/checkpoint_test.go

@@ -0,0 +1,163 @@
+package container // import "github.com/docker/docker/integration/container"
+
+import (
+	"context"
+	"fmt"
+	"os/exec"
+	"regexp"
+	"sort"
+	"testing"
+	"time"
+
+	"github.com/docker/docker/api/types"
+	mounttypes "github.com/docker/docker/api/types/mount"
+	"github.com/docker/docker/client"
+	"github.com/docker/docker/integration/internal/container"
+	"github.com/docker/docker/internal/test/request"
+	"gotest.tools/assert"
+	is "gotest.tools/assert/cmp"
+	"gotest.tools/poll"
+	"gotest.tools/skip"
+)
+
+func containerExec(t *testing.T, client client.APIClient, cID string, cmd []string) {
+	t.Logf("Exec: %s", cmd)
+	ctx := context.Background()
+	r, err := container.Exec(ctx, client, cID, cmd)
+	assert.NilError(t, err)
+	t.Log(r.Combined())
+	assert.Equal(t, r.ExitCode, 0)
+}
+
+func TestCheckpoint(t *testing.T) {
+	skip.If(t, testEnv.DaemonInfo.OSType == "windows")
+	skip.If(t, !testEnv.DaemonInfo.ExperimentalBuild)
+
+	defer setupTest(t)()
+
+	cmd := exec.Command("criu", "check")
+	stdoutStderr, err := cmd.CombinedOutput()
+	t.Logf("%s", stdoutStderr)
+	assert.NilError(t, err)
+
+	ctx := context.Background()
+	client := request.NewAPIClient(t)
+
+	mnt := mounttypes.Mount{
+		Type:   mounttypes.TypeTmpfs,
+		Target: "/tmp",
+	}
+
+	t.Log("Start a container")
+	cID := container.Run(t, ctx, client, container.WithMount(mnt))
+	poll.WaitOn(t,
+		container.IsInState(ctx, client, cID, "running"),
+		poll.WithDelay(100*time.Millisecond),
+	)
+
+	cptOpt := types.CheckpointCreateOptions{
+		Exit:         false,
+		CheckpointID: "test",
+	}
+
+	{
+		// FIXME: ipv6 iptables modules are not uploaded in the test environment
+		cmd := exec.Command("bash", "-c", "set -x; "+
+			"mount --bind $(type -P true) $(type -P ip6tables-restore) && "+
+			"mount --bind $(type -P true) $(type -P ip6tables-save)")
+		stdoutStderr, err = cmd.CombinedOutput()
+		t.Logf("%s", stdoutStderr)
+		assert.NilError(t, err)
+
+		defer func() {
+			cmd := exec.Command("bash", "-c", "set -x; "+
+				"umount -c -i -l $(type -P ip6tables-restore); "+
+				"umount -c -i -l $(type -P ip6tables-save)")
+			stdoutStderr, err = cmd.CombinedOutput()
+			t.Logf("%s", stdoutStderr)
+			assert.NilError(t, err)
+		}()
+	}
+	t.Log("Do a checkpoint and leave the container running")
+	err = client.CheckpointCreate(ctx, cID, cptOpt)
+	if err != nil {
+		// An error can contain a path to a dump file
+		t.Logf("%s", err)
+		re := regexp.MustCompile("path= (.*): ")
+		m := re.FindStringSubmatch(fmt.Sprintf("%s", err))
+		if len(m) >= 2 {
+			dumpLog := m[1]
+			t.Logf("%s", dumpLog)
+			cmd := exec.Command("cat", dumpLog)
+			stdoutStderr, err = cmd.CombinedOutput()
+			t.Logf("%s", stdoutStderr)
+		}
+	}
+	assert.NilError(t, err)
+
+	inspect, err := client.ContainerInspect(ctx, cID)
+	assert.NilError(t, err)
+	assert.Check(t, is.Equal(true, inspect.State.Running))
+
+	checkpoints, err := client.CheckpointList(ctx, cID, types.CheckpointListOptions{})
+	assert.NilError(t, err)
+	assert.Equal(t, len(checkpoints), 1)
+	assert.Equal(t, checkpoints[0].Name, "test")
+
+	// Create a test file on a tmpfs mount.
+	containerExec(t, client, cID, []string{"touch", "/tmp/test-file"})
+
+	// Do a second checkpoint
+	cptOpt = types.CheckpointCreateOptions{
+		Exit:         true,
+		CheckpointID: "test2",
+	}
+	t.Log("Do a checkpoint and stop the container")
+	err = client.CheckpointCreate(ctx, cID, cptOpt)
+	assert.NilError(t, err)
+
+	poll.WaitOn(t,
+		container.IsInState(ctx, client, cID, "exited"),
+		poll.WithDelay(100*time.Millisecond),
+	)
+
+	inspect, err = client.ContainerInspect(ctx, cID)
+	assert.NilError(t, err)
+	assert.Check(t, is.Equal(false, inspect.State.Running))
+
+	// Check that both checkpoints are listed.
+	checkpoints, err = client.CheckpointList(ctx, cID, types.CheckpointListOptions{})
+	assert.NilError(t, err)
+	assert.Equal(t, len(checkpoints), 2)
+	cptNames := make([]string, 2)
+	for i, c := range checkpoints {
+		cptNames[i] = c.Name
+	}
+	sort.Strings(cptNames)
+	assert.Equal(t, cptNames[0], "test")
+	assert.Equal(t, cptNames[1], "test2")
+
+	// Restore the container from a second checkpoint.
+	startOpt := types.ContainerStartOptions{
+		CheckpointID: "test2",
+	}
+	t.Log("Restore the container")
+	err = client.ContainerStart(ctx, cID, startOpt)
+	assert.NilError(t, err)
+
+	inspect, err = client.ContainerInspect(ctx, cID)
+	assert.NilError(t, err)
+	assert.Check(t, is.Equal(true, inspect.State.Running))
+
+	// Check that the test file has been restored.
+	containerExec(t, client, cID, []string{"test", "-f", "/tmp/test-file"})
+
+	for _, id := range []string{"test", "test2"} {
+		cptDelOpt := types.CheckpointDeleteOptions{
+			CheckpointID: id,
+		}
+
+		err = client.CheckpointDelete(ctx, cID, cptDelOpt)
+		assert.NilError(t, err)
+	}
+}