Browse code

Merge pull request #38452 from avagin/cr-test

integration/container: add a base test for C/R

Sebastiaan van Stijn authored on 2019/03/07 09:54:17
Showing 3 changed files
... ...
@@ -31,7 +31,7 @@ RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list
31 31
 
32 32
 FROM base AS criu
33 33
 # Install CRIU for checkpoint/restore support
34
-ENV CRIU_VERSION 3.6
34
+ENV CRIU_VERSION 3.11
35 35
 # Install dependency packages specific to criu
36 36
 RUN apt-get update && apt-get install -y \
37 37
 	libnet-dev \
... ...
@@ -203,6 +203,9 @@ RUN apt-get update && apt-get install -y \
203 203
 	zip \
204 204
 	bzip2 \
205 205
 	xz-utils \
206
+	libprotobuf-c1 \
207
+	libnet1 \
208
+	libnl-3-200 \
206 209
 	--no-install-recommends
207 210
 COPY --from=swagger /build/swagger* /usr/local/bin/
208 211
 COPY --from=frozen-images /build/ /docker-frozen-images
... ...
@@ -2,7 +2,6 @@ package daemon // import "github.com/docker/docker/daemon"
2 2
 
3 3
 import (
4 4
 	"context"
5
-	"encoding/json"
6 5
 	"fmt"
7 6
 	"io/ioutil"
8 7
 	"os"
... ...
@@ -127,15 +126,7 @@ func (daemon *Daemon) CheckpointList(name string, config types.CheckpointListOpt
127 127
 		if !d.IsDir() {
128 128
 			continue
129 129
 		}
130
-		path := filepath.Join(checkpointDir, d.Name(), "config.json")
131
-		data, err := ioutil.ReadFile(path)
132
-		if err != nil {
133
-			return nil, err
134
-		}
135
-		var cpt types.Checkpoint
136
-		if err := json.Unmarshal(data, &cpt); err != nil {
137
-			return nil, err
138
-		}
130
+		cpt := types.Checkpoint{Name: d.Name()}
139 131
 		out = append(out, cpt)
140 132
 	}
141 133
 
142 134
new file mode 100644
... ...
@@ -0,0 +1,163 @@
0
+package container // import "github.com/docker/docker/integration/container"
1
+
2
+import (
3
+	"context"
4
+	"fmt"
5
+	"os/exec"
6
+	"regexp"
7
+	"sort"
8
+	"testing"
9
+	"time"
10
+
11
+	"github.com/docker/docker/api/types"
12
+	mounttypes "github.com/docker/docker/api/types/mount"
13
+	"github.com/docker/docker/client"
14
+	"github.com/docker/docker/integration/internal/container"
15
+	"github.com/docker/docker/internal/test/request"
16
+	"gotest.tools/assert"
17
+	is "gotest.tools/assert/cmp"
18
+	"gotest.tools/poll"
19
+	"gotest.tools/skip"
20
+)
21
+
22
+func containerExec(t *testing.T, client client.APIClient, cID string, cmd []string) {
23
+	t.Logf("Exec: %s", cmd)
24
+	ctx := context.Background()
25
+	r, err := container.Exec(ctx, client, cID, cmd)
26
+	assert.NilError(t, err)
27
+	t.Log(r.Combined())
28
+	assert.Equal(t, r.ExitCode, 0)
29
+}
30
+
31
+func TestCheckpoint(t *testing.T) {
32
+	skip.If(t, testEnv.DaemonInfo.OSType == "windows")
33
+	skip.If(t, !testEnv.DaemonInfo.ExperimentalBuild)
34
+
35
+	defer setupTest(t)()
36
+
37
+	cmd := exec.Command("criu", "check")
38
+	stdoutStderr, err := cmd.CombinedOutput()
39
+	t.Logf("%s", stdoutStderr)
40
+	assert.NilError(t, err)
41
+
42
+	ctx := context.Background()
43
+	client := request.NewAPIClient(t)
44
+
45
+	mnt := mounttypes.Mount{
46
+		Type:   mounttypes.TypeTmpfs,
47
+		Target: "/tmp",
48
+	}
49
+
50
+	t.Log("Start a container")
51
+	cID := container.Run(t, ctx, client, container.WithMount(mnt))
52
+	poll.WaitOn(t,
53
+		container.IsInState(ctx, client, cID, "running"),
54
+		poll.WithDelay(100*time.Millisecond),
55
+	)
56
+
57
+	cptOpt := types.CheckpointCreateOptions{
58
+		Exit:         false,
59
+		CheckpointID: "test",
60
+	}
61
+
62
+	{
63
+		// FIXME: ipv6 iptables modules are not uploaded in the test environment
64
+		cmd := exec.Command("bash", "-c", "set -x; "+
65
+			"mount --bind $(type -P true) $(type -P ip6tables-restore) && "+
66
+			"mount --bind $(type -P true) $(type -P ip6tables-save)")
67
+		stdoutStderr, err = cmd.CombinedOutput()
68
+		t.Logf("%s", stdoutStderr)
69
+		assert.NilError(t, err)
70
+
71
+		defer func() {
72
+			cmd := exec.Command("bash", "-c", "set -x; "+
73
+				"umount -c -i -l $(type -P ip6tables-restore); "+
74
+				"umount -c -i -l $(type -P ip6tables-save)")
75
+			stdoutStderr, err = cmd.CombinedOutput()
76
+			t.Logf("%s", stdoutStderr)
77
+			assert.NilError(t, err)
78
+		}()
79
+	}
80
+	t.Log("Do a checkpoint and leave the container running")
81
+	err = client.CheckpointCreate(ctx, cID, cptOpt)
82
+	if err != nil {
83
+		// An error can contain a path to a dump file
84
+		t.Logf("%s", err)
85
+		re := regexp.MustCompile("path= (.*): ")
86
+		m := re.FindStringSubmatch(fmt.Sprintf("%s", err))
87
+		if len(m) >= 2 {
88
+			dumpLog := m[1]
89
+			t.Logf("%s", dumpLog)
90
+			cmd := exec.Command("cat", dumpLog)
91
+			stdoutStderr, err = cmd.CombinedOutput()
92
+			t.Logf("%s", stdoutStderr)
93
+		}
94
+	}
95
+	assert.NilError(t, err)
96
+
97
+	inspect, err := client.ContainerInspect(ctx, cID)
98
+	assert.NilError(t, err)
99
+	assert.Check(t, is.Equal(true, inspect.State.Running))
100
+
101
+	checkpoints, err := client.CheckpointList(ctx, cID, types.CheckpointListOptions{})
102
+	assert.NilError(t, err)
103
+	assert.Equal(t, len(checkpoints), 1)
104
+	assert.Equal(t, checkpoints[0].Name, "test")
105
+
106
+	// Create a test file on a tmpfs mount.
107
+	containerExec(t, client, cID, []string{"touch", "/tmp/test-file"})
108
+
109
+	// Do a second checkpoint
110
+	cptOpt = types.CheckpointCreateOptions{
111
+		Exit:         true,
112
+		CheckpointID: "test2",
113
+	}
114
+	t.Log("Do a checkpoint and stop the container")
115
+	err = client.CheckpointCreate(ctx, cID, cptOpt)
116
+	assert.NilError(t, err)
117
+
118
+	poll.WaitOn(t,
119
+		container.IsInState(ctx, client, cID, "exited"),
120
+		poll.WithDelay(100*time.Millisecond),
121
+	)
122
+
123
+	inspect, err = client.ContainerInspect(ctx, cID)
124
+	assert.NilError(t, err)
125
+	assert.Check(t, is.Equal(false, inspect.State.Running))
126
+
127
+	// Check that both checkpoints are listed.
128
+	checkpoints, err = client.CheckpointList(ctx, cID, types.CheckpointListOptions{})
129
+	assert.NilError(t, err)
130
+	assert.Equal(t, len(checkpoints), 2)
131
+	cptNames := make([]string, 2)
132
+	for i, c := range checkpoints {
133
+		cptNames[i] = c.Name
134
+	}
135
+	sort.Strings(cptNames)
136
+	assert.Equal(t, cptNames[0], "test")
137
+	assert.Equal(t, cptNames[1], "test2")
138
+
139
+	// Restore the container from a second checkpoint.
140
+	startOpt := types.ContainerStartOptions{
141
+		CheckpointID: "test2",
142
+	}
143
+	t.Log("Restore the container")
144
+	err = client.ContainerStart(ctx, cID, startOpt)
145
+	assert.NilError(t, err)
146
+
147
+	inspect, err = client.ContainerInspect(ctx, cID)
148
+	assert.NilError(t, err)
149
+	assert.Check(t, is.Equal(true, inspect.State.Running))
150
+
151
+	// Check that the test file has been restored.
152
+	containerExec(t, client, cID, []string{"test", "-f", "/tmp/test-file"})
153
+
154
+	for _, id := range []string{"test", "test2"} {
155
+		cptDelOpt := types.CheckpointDeleteOptions{
156
+			CheckpointID: id,
157
+		}
158
+
159
+		err = client.CheckpointDelete(ctx, cID, cptDelOpt)
160
+		assert.NilError(t, err)
161
+	}
162
+}