Browse code

Merge pull request #26119 from cpuguy83/lazily_load_fixtures

Move some test fixtures to go

Michael Crosby authored on 2016/09/09 03:16:27
Showing 16 changed files
1 1
deleted file mode 100644
... ...
@@ -1,67 +0,0 @@
1
-#!/bin/bash
2
-set -e
3
-
4
-# image list should match what's in the Dockerfile (minus the explicit images IDs)
5
-images=(
6
-	buildpack-deps:jessie
7
-	busybox:latest
8
-	debian:jessie
9
-	hello-world:latest
10
-)
11
-
12
-if [ "$TEST_IMAGE_NAMESPACE" ]; then
13
-	for (( i = 0; i < ${#images[@]}; i++ )); do
14
-		images[$i]="$TEST_IMAGE_NAMESPACE/${images[$i]}"
15
-	done
16
-fi
17
-
18
-if ! docker inspect "${images[@]}" &> /dev/null; then
19
-	hardCodedDir='/docker-frozen-images'
20
-	if [ -d "$hardCodedDir" ]; then
21
-		# Do not use a subshell for the following command. Windows to Linux CI
22
-		# runs bash 3.x so will not trap an error in a subshell.
23
-		# http://stackoverflow.com/questions/22630363/how-does-set-e-work-with-subshells
24
-		set -x; tar -cC "$hardCodedDir" . | docker load; set +x
25
-	else
26
-		dir="$DEST/frozen-images"
27
-		# extract the exact "RUN download-frozen-image-v2.sh" line from the Dockerfile itself for consistency
28
-		# NOTE: this will fail if either "curl" or "jq" is not installed or if the Dockerfile is not available/readable
29
-		awk '
30
-			$1 == "RUN" && $2 == "./contrib/download-frozen-image-v2.sh" {
31
-				for (i = 2; i < NF; i++)
32
-					printf ( $i == "'"$hardCodedDir"'" ? "'"$dir"'" : $i ) " ";
33
-				print $NF;
34
-				if (/\\$/) {
35
-					inCont = 1;
36
-					next;
37
-				}
38
-			}
39
-			inCont {
40
-				print;
41
-				if (!/\\$/) {
42
-					inCont = 0;
43
-				}
44
-			}
45
-		' "$DOCKERFILE" | sh -x
46
-		# Do not use a subshell for the following command. Windows to Linux CI
47
-		# runs bash 3.x so will not trap an error in a subshell.
48
-		# http://stackoverflow.com/questions/22630363/how-does-set-e-work-with-subshells
49
-		set -x; tar -cC "$dir" . | docker load; set +x
50
-	fi
51
-fi
52
-
53
-if [ "$TEST_IMAGE_NAMESPACE" ]; then
54
-	for image in "${images[@]}"; do
55
-		target="${image#$TEST_IMAGE_NAMESPACE/}"
56
-		if [ "$target" != "$image" ]; then
57
-			# tag images to ensure that all integrations work with the defined image names
58
-			docker tag "$image" "$target"
59
-			# then remove original tags as these make problems with later tests (e.g., TestInspectApiImageResponse)
60
-			docker rmi "$image"
61
-		fi
62
-	done
63
-fi
64
-
65
-# explicitly rename "hello-world:latest" to ":frozen" for the test that uses it
66
-docker tag hello-world:latest hello-world:frozen
67
-docker rmi hello-world:latest
68 1
deleted file mode 100644
... ...
@@ -1,32 +0,0 @@
1
-#!/bin/bash
2
-set -e
3
-
4
-# This scripts sets up the required images for Windows to Windows CI
5
-
6
-# Tag (microsoft/)windowsservercore as latest
7
-set +e
8
-! BUILD=$(docker images | grep windowsservercore | grep -v latest | awk '{print $2}')
9
-if [ -z $BUILD ]; then
10
-	echo "ERROR: Could not find windowsservercore images"
11
-	exit 1
12
-fi
13
-
14
-# Get the name. Around 2016 6D TP5, these have the microsoft/ prefix, hence cater for both.
15
-! IMAGENAME=$(docker images | grep windowsservercore | grep -v latest | awk '{print $1}')
16
-if [ -z $IMAGENAME ]; then
17
-	echo "ERROR: Could not find windowsservercore image"
18
-	exit 1
19
-fi
20
-
21
-! LATESTCOUNT=$(docker images | grep windowsservercore | grep -v $BUILD | wc -l)
22
-if [ $LATESTCOUNT -ne 1 ]; then
23
-	set -e
24
-	docker tag $IMAGENAME:$BUILD windowsservercore:latest
25
-	echo "INFO: Tagged $IMAGENAME:$BUILD as windowsservercore:latest"
26
-fi
27
-
28
-# Busybox (requires windowsservercore)
29
-if [ -z "$(docker images | grep busybox)" ]; then
30
-	echo "INFO: Building busybox"
31
-	docker build -t busybox https://raw.githubusercontent.com/jhowardmsft/busybox/master/Dockerfile
32
-fi
33 1
\ No newline at end of file
34 2
deleted file mode 100644
... ...
@@ -1,15 +0,0 @@
1
-#!/bin/bash
2
-set -e
3
-
4
-# Build a Go static web server on top of busybox image
5
-# and compile it for target daemon
6
-
7
-dir="$DEST/httpserver"
8
-mkdir -p "$dir"
9
-(
10
-	cd "$dir"
11
-	GOOS=${DOCKER_ENGINE_GOOS:="linux"} GOARCH=${DOCKER_ENGINE_GOARCH:="amd64"} CGO_ENABLED=0 go build -o httpserver github.com/docker/docker/contrib/httpserver
12
-	cp ../../../../contrib/httpserver/Dockerfile .
13
-	docker build -qt httpserver . > /dev/null
14
-)
15
-rm -rf "$dir"
16 1
deleted file mode 100644
... ...
@@ -1,22 +0,0 @@
1
-#!/bin/bash
2
-set -e
3
-
4
-# Build a C binary for testing no-new-privileges
5
-# and compile it for target daemon
6
-if [ "$DOCKER_ENGINE_GOOS" = "linux" ]; then
7
-	if [ "$DOCKER_ENGINE_OSARCH" = "$DOCKER_CLIENT_OSARCH" ]; then
8
-		tmpdir=$(mktemp -d)
9
-		gcc -g -Wall -static contrib/nnp-test/nnp-test.c -o "${tmpdir}/nnp-test"
10
-
11
-		dockerfile="${tmpdir}/Dockerfile"
12
-		cat <<-EOF > "$dockerfile"
13
-		FROM debian:jessie
14
-		COPY . /usr/bin/
15
-		RUN chmod +s /usr/bin/nnp-test
16
-		EOF
17
-		docker build --force-rm ${DOCKER_BUILD_ARGS} -qt nnp-test "${tmpdir}" > /dev/null
18
-		rm -rf "${tmpdir}"
19
-	else
20
-		docker build ${DOCKER_BUILD_ARGS} -qt nnp-test contrib/nnp-test > /dev/null
21
-	fi
22
-fi
23 1
deleted file mode 100644
... ...
@@ -1,26 +0,0 @@
1
-#!/bin/bash
2
-set -e
3
-
4
-# Build a C binary for cloning a userns for seccomp tests
5
-# and compile it for target daemon
6
-if [ "$DOCKER_ENGINE_GOOS" = "linux" ]; then
7
-	if [ "$DOCKER_ENGINE_OSARCH" = "$DOCKER_CLIENT_OSARCH" ]; then
8
-		tmpdir=$(mktemp -d)
9
-		gcc -g -Wall -static contrib/syscall-test/userns.c -o "${tmpdir}/userns-test"
10
-		gcc -g -Wall -static contrib/syscall-test/ns.c -o "${tmpdir}/ns-test"
11
-		gcc -g -Wall -static contrib/syscall-test/acct.c -o "${tmpdir}/acct-test"
12
-		if [ "$DOCKER_ENGINE_OSARCH" = "linux/amd64" ]; then
13
-			gcc -s -m32 -nostdlib contrib/syscall-test/exit32.s -o "${tmpdir}/exit32-test"
14
-		fi
15
-
16
-		dockerfile="${tmpdir}/Dockerfile"
17
-		cat <<-EOF > "$dockerfile"
18
-		FROM debian:jessie
19
-		COPY . /usr/bin/
20
-		EOF
21
-		docker build --force-rm ${DOCKER_BUILD_ARGS} -qt syscall-test "${tmpdir}" > /dev/null
22
-		rm -rf "${tmpdir}"
23
-	else
24
-		docker build ${DOCKER_BUILD_ARGS} -qt syscall-test contrib/syscall-test > /dev/null
25
-	fi
26
-fi
... ...
@@ -4,11 +4,4 @@ set -e
4 4
 bundle .detect-daemon-osarch
5 5
 if [ $DOCKER_ENGINE_GOOS != "windows" ]; then
6 6
 	bundle .ensure-emptyfs
7
-	bundle .ensure-frozen-images
8
-	bundle .ensure-httpserver
9
-	bundle .ensure-syscall-test
10
-	bundle .ensure-nnp-test
11
-else
12
-	# Note this is Windows to Windows CI, not Windows to Linux CI
13
-	bundle .ensure-frozen-images-windows
14 7
 fi
... ...
@@ -67,11 +67,13 @@ test_env() {
67 67
 			DOCKER_HOST="$DOCKER_HOST" \
68 68
 			DOCKER_REMAP_ROOT="$DOCKER_REMAP_ROOT" \
69 69
 			DOCKER_REMOTE_DAEMON="$DOCKER_REMOTE_DAEMON" \
70
+			DOCKERFILE="$DOCKERFILE" \
70 71
 			GOPATH="$GOPATH" \
71 72
 			GOTRACEBACK=all \
72 73
 			HOME="$ABS_DEST/fake-HOME" \
73 74
 			PATH="$PATH" \
74 75
 			TEMP="$TEMP" \
76
+			TEST_IMAGE_NAMESPACE="$TEST_IMAGE_NAMESPACE" \
75 77
 			"$@"
76 78
 	)
77 79
 }
... ...
@@ -17,7 +17,10 @@ for f in "${files[@]}"; do
17 17
 
18 18
 	# we use "git show" here to validate that what's committed doesn't contain golang built-in testing
19 19
 	if git show "$VALIDATE_HEAD:$f" | grep -q testing.T; then
20
-		badFiles+=( "$f" )
20
+		if [ "$(echo $f | grep '_test')" ]; then
21
+			# allow testing.T for non- _test files
22
+			badFiles+=( "$f" )
23
+		fi
21 24
 	fi
22 25
 done
23 26
 
... ...
@@ -23,6 +23,9 @@ func Test(t *testing.T) {
23 23
 		fmt.Println("INFO: Testing against a local daemon")
24 24
 	}
25 25
 
26
+	if daemonPlatform == "linux" {
27
+		ensureFrozenImagesLinux(t)
28
+	}
26 29
 	check.TestingT(t)
27 30
 }
28 31
 
... ...
@@ -371,8 +371,9 @@ func (d *Daemon) LoadBusybox() error {
371 371
 			return fmt.Errorf("unexpected error on busybox.tar stat: %v", err)
372 372
 		}
373 373
 		// saving busybox image from main daemon
374
-		if err := exec.Command(dockerBinary, "save", "--output", bb, "busybox:latest").Run(); err != nil {
375
-			return fmt.Errorf("could not save busybox image: %v", err)
374
+		if out, err := exec.Command(dockerBinary, "save", "--output", bb, "busybox:latest").CombinedOutput(); err != nil {
375
+			imagesOut, _ := exec.Command(dockerBinary, "images", "--format", "{{ .Repository }}:{{ .Tag }}").CombinedOutput()
376
+			return fmt.Errorf("could not save busybox image: %s\n%s", string(out), strings.TrimSpace(string(imagesOut)))
376 377
 		}
377 378
 	}
378 379
 	// loading busybox image to this daemon
... ...
@@ -308,8 +308,13 @@ RUN echo 2 #layer2
308 308
 }
309 309
 
310 310
 func (*DockerSuite) TestRmiParentImageFail(c *check.C) {
311
-	parent := inspectField(c, "busybox", "Parent")
312
-	out, _, err := dockerCmdWithError("rmi", parent)
311
+	_, err := buildImage("test", `
312
+	FROM busybox
313
+	RUN echo hello`, false)
314
+	c.Assert(err, checker.IsNil)
315
+
316
+	id := inspectField(c, "busybox", "ID")
317
+	out, _, err := dockerCmdWithError("rmi", id)
313 318
 	c.Assert(err, check.NotNil)
314 319
 	if !strings.Contains(out, "image has dependent child images") {
315 320
 		c.Fatalf("rmi should have failed because it's a parent image, got %s", out)
... ...
@@ -1019,6 +1019,7 @@ func (s *DockerSuite) TestRunSeccompProfileDenyUnshareUserns(c *check.C) {
1019 1019
 // with a the default seccomp profile exits with operation not permitted.
1020 1020
 func (s *DockerSuite) TestRunSeccompProfileDenyCloneUserns(c *check.C) {
1021 1021
 	testRequires(c, SameHostDaemon, seccompEnabled)
1022
+	ensureSyscallTest(c)
1022 1023
 
1023 1024
 	runCmd := exec.Command(dockerBinary, "run", "syscall-test", "userns-test", "id")
1024 1025
 	out, _, err := runCommandWithOutput(runCmd)
... ...
@@ -1031,6 +1032,7 @@ func (s *DockerSuite) TestRunSeccompProfileDenyCloneUserns(c *check.C) {
1031 1031
 // 'docker run --security-opt seccomp=unconfined syscall-test' allows creating a userns.
1032 1032
 func (s *DockerSuite) TestRunSeccompUnconfinedCloneUserns(c *check.C) {
1033 1033
 	testRequires(c, SameHostDaemon, seccompEnabled, UserNamespaceInKernel, NotUserNamespace, unprivilegedUsernsClone)
1034
+	ensureSyscallTest(c)
1034 1035
 
1035 1036
 	// make sure running w privileged is ok
1036 1037
 	runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp=unconfined", "syscall-test", "userns-test", "id")
... ...
@@ -1043,6 +1045,7 @@ func (s *DockerSuite) TestRunSeccompUnconfinedCloneUserns(c *check.C) {
1043 1043
 // allows creating a userns.
1044 1044
 func (s *DockerSuite) TestRunSeccompAllowPrivCloneUserns(c *check.C) {
1045 1045
 	testRequires(c, SameHostDaemon, seccompEnabled, UserNamespaceInKernel, NotUserNamespace)
1046
+	ensureSyscallTest(c)
1046 1047
 
1047 1048
 	// make sure running w privileged is ok
1048 1049
 	runCmd := exec.Command(dockerBinary, "run", "--privileged", "syscall-test", "userns-test", "id")
... ...
@@ -1055,6 +1058,7 @@ func (s *DockerSuite) TestRunSeccompAllowPrivCloneUserns(c *check.C) {
1055 1055
 // with the default seccomp profile.
1056 1056
 func (s *DockerSuite) TestRunSeccompProfileAllow32Bit(c *check.C) {
1057 1057
 	testRequires(c, SameHostDaemon, seccompEnabled, IsAmd64)
1058
+	ensureSyscallTest(c)
1058 1059
 
1059 1060
 	runCmd := exec.Command(dockerBinary, "run", "syscall-test", "exit32-test", "id")
1060 1061
 	if out, _, err := runCommandWithOutput(runCmd); err != nil {
... ...
@@ -1075,6 +1079,7 @@ func (s *DockerSuite) TestRunSeccompAllowSetrlimit(c *check.C) {
1075 1075
 
1076 1076
 func (s *DockerSuite) TestRunSeccompDefaultProfileAcct(c *check.C) {
1077 1077
 	testRequires(c, SameHostDaemon, seccompEnabled, NotUserNamespace)
1078
+	ensureSyscallTest(c)
1078 1079
 
1079 1080
 	out, _, err := dockerCmdWithError("run", "syscall-test", "acct-test")
1080 1081
 	if err == nil || !strings.Contains(out, "Operation not permitted") {
... ...
@@ -1104,6 +1109,7 @@ func (s *DockerSuite) TestRunSeccompDefaultProfileAcct(c *check.C) {
1104 1104
 
1105 1105
 func (s *DockerSuite) TestRunSeccompDefaultProfileNS(c *check.C) {
1106 1106
 	testRequires(c, SameHostDaemon, seccompEnabled, NotUserNamespace)
1107
+	ensureSyscallTest(c)
1107 1108
 
1108 1109
 	out, _, err := dockerCmdWithError("run", "syscall-test", "ns-test", "echo", "hello0")
1109 1110
 	if err == nil || !strings.Contains(out, "Operation not permitted") {
... ...
@@ -1140,6 +1146,7 @@ func (s *DockerSuite) TestRunSeccompDefaultProfileNS(c *check.C) {
1140 1140
 // effective uid transtions on executing setuid binaries.
1141 1141
 func (s *DockerSuite) TestRunNoNewPrivSetuid(c *check.C) {
1142 1142
 	testRequires(c, DaemonIsLinux, NotUserNamespace, SameHostDaemon)
1143
+	ensureNNPTest(c)
1143 1144
 
1144 1145
 	// test that running a setuid binary results in no effective uid transition
1145 1146
 	runCmd := exec.Command(dockerBinary, "run", "--security-opt", "no-new-privileges", "--user", "1000", "nnp-test", "/usr/bin/nnp-test")
... ...
@@ -754,6 +754,10 @@ func newRemoteFileServer(ctx *FakeContext) (*remoteFileServer, error) {
754 754
 		container = fmt.Sprintf("fileserver-cnt-%s", strings.ToLower(stringutils.GenerateRandomAlphaOnlyString(10)))
755 755
 	)
756 756
 
757
+	if err := ensureHTTPServerImage(); err != nil {
758
+		return nil, err
759
+	}
760
+
757 761
 	// Build the image
758 762
 	if err := fakeContextAddDockerfile(ctx, `FROM httpserver
759 763
 COPY . /static`); err != nil {
760 764
new file mode 100644
... ...
@@ -0,0 +1,69 @@
0
+package main
1
+
2
+import (
3
+	"fmt"
4
+	"io/ioutil"
5
+	"os"
6
+	"os/exec"
7
+	"path/filepath"
8
+	"sync"
9
+)
10
+
11
+var ensureHTTPServerOnce sync.Once
12
+
13
+func ensureHTTPServerImage() error {
14
+	var doIt bool
15
+	ensureHTTPServerOnce.Do(func() {
16
+		doIt = true
17
+	})
18
+
19
+	if !doIt {
20
+		return nil
21
+	}
22
+
23
+	protectedImages["httpserver:latest"] = struct{}{}
24
+
25
+	tmp, err := ioutil.TempDir("", "docker-http-server-test")
26
+	if err != nil {
27
+		return fmt.Errorf("could not build http server: %v", err)
28
+	}
29
+	defer os.RemoveAll(tmp)
30
+
31
+	goos := daemonPlatform
32
+	if goos == "" {
33
+		goos = "linux"
34
+	}
35
+	goarch := os.Getenv("DOCKER_ENGINE_GOARCH")
36
+	if goarch == "" {
37
+		goarch = "amd64"
38
+	}
39
+
40
+	goCmd, lookErr := exec.LookPath("go")
41
+	if lookErr != nil {
42
+		return fmt.Errorf("could not build http server: %v", lookErr)
43
+	}
44
+
45
+	cmd := exec.Command(goCmd, "build", "-o", filepath.Join(tmp, "httpserver"), "github.com/docker/docker/contrib/httpserver")
46
+	cmd.Env = append(os.Environ(), []string{
47
+		"CGO_ENABLED=0",
48
+		"GOOS=" + goos,
49
+		"GOARCH=" + goarch,
50
+	}...)
51
+	var out []byte
52
+	if out, err = cmd.CombinedOutput(); err != nil {
53
+		return fmt.Errorf("could not build http server: %s", string(out))
54
+	}
55
+
56
+	cpCmd, lookErr := exec.LookPath("cp")
57
+	if lookErr != nil {
58
+		return fmt.Errorf("could not build http server: %v", lookErr)
59
+	}
60
+	if out, err = exec.Command(cpCmd, "../contrib/httpserver/Dockerfile", filepath.Join(tmp, "Dockerfile")).CombinedOutput(); err != nil {
61
+		return fmt.Errorf("could not build http server: %v", string(out))
62
+	}
63
+
64
+	if out, err = exec.Command(dockerBinary, "build", "-q", "-t", "httpserver", tmp).CombinedOutput(); err != nil {
65
+		return fmt.Errorf("could not build http server: %v", string(out))
66
+	}
67
+	return nil
68
+}
0 69
new file mode 100644
... ...
@@ -0,0 +1,171 @@
0
+package load
1
+
2
+import (
3
+	"bufio"
4
+	"bytes"
5
+	"os"
6
+	"os/exec"
7
+	"path/filepath"
8
+	"strings"
9
+	"sync"
10
+
11
+	"github.com/pkg/errors"
12
+)
13
+
14
+var frozenImgDir = "/docker-frozen-images"
15
+
16
+// FrozenImagesLinux loads the frozen image set for the integration suite
17
+// If the images are not available locally it will download them
18
+// TODO: This loads whatever is in the frozen image dir, regardless of what
19
+// images were passed in. If the images need to be downloaded, then it will respect
20
+// the passed in images
21
+func FrozenImagesLinux(dockerBinary string, images ...string) error {
22
+	imgNS := os.Getenv("TEST_IMAGE_NAMESPACE")
23
+	var loadImages []string
24
+	for _, img := range images {
25
+		if imgNS != "" {
26
+			img = imgNS + "/" + img
27
+		}
28
+		if err := exec.Command(dockerBinary, "inspect", "--type=image", img).Run(); err != nil {
29
+			loadImages = append(loadImages, img)
30
+		}
31
+	}
32
+
33
+	if len(loadImages) == 0 {
34
+		// everything is loaded, we're done
35
+		return nil
36
+	}
37
+
38
+	fi, err := os.Stat(frozenImgDir)
39
+	if err != nil || !fi.IsDir() {
40
+		if err := pullImages(dockerBinary, loadImages); err != nil {
41
+			return errors.Wrap(err, "error pulling image list")
42
+		}
43
+	} else {
44
+		if err := loadFrozenImags(dockerBinary); err != nil {
45
+			return err
46
+		}
47
+	}
48
+
49
+	if imgNS != "" {
50
+		for _, img := range loadImages {
51
+			target := strings.TrimPrefix(img, imgNS+"/")
52
+			if target != img {
53
+				if out, err := exec.Command(dockerBinary, "tag", img, target).CombinedOutput(); err != nil {
54
+					return errors.Errorf("%v: %s", err, string(out))
55
+				}
56
+				if out, err := exec.Command(dockerBinary, "rmi", img).CombinedOutput(); err != nil {
57
+					return errors.Errorf("%v: %s", err, string(out))
58
+				}
59
+			}
60
+		}
61
+	}
62
+	return nil
63
+}
64
+
65
+func loadFrozenImags(dockerBinary string) error {
66
+	tar, err := exec.LookPath("tar")
67
+	if err != nil {
68
+		return errors.Wrap(err, "could not find tar binary")
69
+	}
70
+	tarCmd := exec.Command(tar, "-cC", frozenImgDir, ".")
71
+	out, err := tarCmd.StdoutPipe()
72
+	if err != nil {
73
+		return errors.Wrap(err, "error getting stdout pipe for tar command")
74
+	}
75
+
76
+	errBuf := bytes.NewBuffer(nil)
77
+	tarCmd.Stderr = errBuf
78
+	tarCmd.Start()
79
+	defer tarCmd.Wait()
80
+
81
+	cmd := exec.Command(dockerBinary, "load")
82
+	cmd.Stdin = out
83
+	if out, err := cmd.CombinedOutput(); err != nil {
84
+		return errors.Errorf("%v: %s", err, string(out))
85
+	}
86
+	return nil
87
+}
88
+
89
+func pullImages(dockerBinary string, images []string) error {
90
+	cwd, err := os.Getwd()
91
+	if err != nil {
92
+		return errors.Wrap(err, "error getting path to dockerfile")
93
+	}
94
+	dockerfile := os.Getenv("DOCKERFILE")
95
+	if dockerfile == "" {
96
+		dockerfile = "Dockerfile"
97
+	}
98
+	dockerfilePath := filepath.Join(filepath.Dir(filepath.Clean(cwd)), dockerfile)
99
+	pullRefs, err := readFrozenImageList(dockerfilePath, images)
100
+	if err != nil {
101
+		return errors.Wrap(err, "error reading frozen image list")
102
+	}
103
+
104
+	var wg sync.WaitGroup
105
+	chErr := make(chan error, len(images))
106
+	for tag, ref := range pullRefs {
107
+		wg.Add(1)
108
+		go func(tag, ref string) {
109
+			defer wg.Done()
110
+			if out, err := exec.Command(dockerBinary, "pull", ref).CombinedOutput(); err != nil {
111
+				chErr <- errors.Errorf("%v: %s", string(out), err)
112
+				return
113
+			}
114
+			if out, err := exec.Command(dockerBinary, "tag", ref, tag).CombinedOutput(); err != nil {
115
+				chErr <- errors.Errorf("%v: %s", string(out), err)
116
+				return
117
+			}
118
+			if out, err := exec.Command(dockerBinary, "rmi", ref).CombinedOutput(); err != nil {
119
+				chErr <- errors.Errorf("%v: %s", string(out), err)
120
+				return
121
+			}
122
+		}(tag, ref)
123
+	}
124
+	wg.Wait()
125
+	close(chErr)
126
+	return <-chErr
127
+}
128
+
129
+func readFrozenImageList(dockerfilePath string, images []string) (map[string]string, error) {
130
+	f, err := os.Open(dockerfilePath)
131
+	if err != nil {
132
+		return nil, errors.Wrap(err, "error reading dockerfile")
133
+	}
134
+	defer f.Close()
135
+	ls := make(map[string]string)
136
+
137
+	scanner := bufio.NewScanner(f)
138
+	for scanner.Scan() {
139
+		line := strings.Fields(scanner.Text())
140
+		if len(line) < 3 {
141
+			continue
142
+		}
143
+		if !(line[0] == "RUN" && line[1] == "./contrib/download-frozen-image-v2.sh") {
144
+			continue
145
+		}
146
+
147
+		frozenImgDir = line[2]
148
+		if line[2] == frozenImgDir {
149
+			frozenImgDir = filepath.Join(os.Getenv("DEST"), "frozen-images")
150
+		}
151
+
152
+		for scanner.Scan() {
153
+			img := strings.TrimSpace(scanner.Text())
154
+			img = strings.TrimSuffix(img, "\\")
155
+			img = strings.TrimSpace(img)
156
+			split := strings.Split(img, "@")
157
+			if len(split) < 2 {
158
+				break
159
+			}
160
+
161
+			for _, i := range images {
162
+				if split[0] == i {
163
+					ls[i] = img
164
+					break
165
+				}
166
+			}
167
+		}
168
+	}
169
+	return ls, nil
170
+}
0 171
new file mode 100644
... ...
@@ -0,0 +1,160 @@
0
+package main
1
+
2
+import (
3
+	"io/ioutil"
4
+	"os"
5
+	"os/exec"
6
+	"path/filepath"
7
+	"runtime"
8
+	"strings"
9
+	"sync"
10
+	"testing"
11
+
12
+	"github.com/docker/docker/integration-cli/fixtures/load"
13
+	"github.com/docker/docker/pkg/integration/checker"
14
+	"github.com/go-check/check"
15
+)
16
+
17
+func ensureFrozenImagesLinux(t *testing.T) {
18
+	images := []string{"busybox:latest", "hello-world:latest", "debian:jessie"}
19
+	err := load.FrozenImagesLinux(dockerBinary, images...)
20
+	if err != nil {
21
+		t.Log(dockerCmdWithError("images"))
22
+		t.Fatalf("%+v", err)
23
+	}
24
+
25
+	// hello-world:latest gets re-tagged as hello-world:frozen
26
+	// there are some tests that use hello-world:latest specifically so it pulls
27
+	// the image and hello-world:frozen is used for when we just want a super
28
+	// small image
29
+	if out, err := exec.Command(dockerBinary, "tag", "hello-world:latest", "hello-world:frozen").CombinedOutput(); err != nil {
30
+		t.Log(dockerCmdWithError("images"))
31
+		t.Fatal(string(out))
32
+	}
33
+	if out, err := exec.Command(dockerBinary, "rmi", "hello-world:latest").CombinedOutput(); err != nil {
34
+		t.Log(dockerCmdWithError("images"))
35
+		t.Fatal(string(out))
36
+	}
37
+
38
+	for _, img := range images {
39
+		if img == "hello-world:latest" {
40
+			img = "hello-world:frozen"
41
+		}
42
+		protectedImages[img] = struct{}{}
43
+	}
44
+}
45
+
46
+var ensureSyscallTestOnce sync.Once
47
+
48
+func ensureSyscallTest(c *check.C) {
49
+	var doIt bool
50
+	ensureSyscallTestOnce.Do(func() {
51
+		doIt = true
52
+	})
53
+	if !doIt {
54
+		return
55
+	}
56
+	protectedImages["syscall-test:latest"] = struct{}{}
57
+
58
+	// if no match, must build in docker, which is significantly slower
59
+	// (slower mostly because of the vfs graphdriver)
60
+	if daemonPlatform != runtime.GOOS {
61
+		ensureSyscallTestBuild(c)
62
+		return
63
+	}
64
+
65
+	tmp, err := ioutil.TempDir("", "syscall-test-build")
66
+	c.Assert(err, checker.IsNil, check.Commentf("couldn't create temp dir"))
67
+	defer os.RemoveAll(tmp)
68
+
69
+	gcc, err := exec.LookPath("gcc")
70
+	c.Assert(err, checker.IsNil, check.Commentf("could not find gcc"))
71
+
72
+	out, err := exec.Command(gcc, "-g", "-Wall", "-static", "../contrib/syscall-test/userns.c", "-o", tmp+"/"+"userns-test").CombinedOutput()
73
+	c.Assert(err, checker.IsNil, check.Commentf(string(out)))
74
+	out, err = exec.Command(gcc, "-g", "-Wall", "-static", "../contrib/syscall-test/ns.c", "-o", tmp+"/"+"ns-test").CombinedOutput()
75
+	c.Assert(err, checker.IsNil, check.Commentf(string(out)))
76
+	out, err = exec.Command(gcc, "-g", "-Wall", "-static", "../contrib/syscall-test/acct.c", "-o", tmp+"/"+"acct-test").CombinedOutput()
77
+	c.Assert(err, checker.IsNil, check.Commentf(string(out)))
78
+
79
+	if runtime.GOOS == "linux" && runtime.GOARCH == "amd64" {
80
+		out, err = exec.Command(gcc, "-s", "-m32", "-nostdlib", "../contrib/syscall-test/exit32.s", "-o", tmp+"/"+"exit32-test").CombinedOutput()
81
+		c.Assert(err, checker.IsNil, check.Commentf(string(out)))
82
+	}
83
+
84
+	dockerFile := filepath.Join(tmp, "Dockerfile")
85
+	content := []byte(`
86
+	FROM debian:jessie
87
+	COPY . /usr/bin/
88
+	`)
89
+	err = ioutil.WriteFile(dockerFile, content, 600)
90
+	c.Assert(err, checker.IsNil)
91
+
92
+	var buildArgs []string
93
+	if arg := os.Getenv("DOCKER_BUILD_ARGS"); strings.TrimSpace(arg) != "" {
94
+		buildArgs = strings.Split(arg, " ")
95
+	}
96
+	buildArgs = append(buildArgs, []string{"-q", "-t", "syscall-test", tmp}...)
97
+	buildArgs = append([]string{"build"}, buildArgs...)
98
+	dockerCmd(c, buildArgs...)
99
+}
100
+
101
+func ensureSyscallTestBuild(c *check.C) {
102
+	err := load.FrozenImagesLinux(dockerBinary, "buildpack-deps:jessie")
103
+	c.Assert(err, checker.IsNil)
104
+
105
+	var buildArgs []string
106
+	if arg := os.Getenv("DOCKER_BUILD_ARGS"); strings.TrimSpace(arg) != "" {
107
+		buildArgs = strings.Split(arg, " ")
108
+	}
109
+	buildArgs = append(buildArgs, []string{"-q", "-t", "syscall-test", "../contrib/syscall-test"}...)
110
+	buildArgs = append([]string{"build"}, buildArgs...)
111
+	dockerCmd(c, buildArgs...)
112
+}
113
+
114
+func ensureNNPTest(c *check.C) {
115
+	protectedImages["nnp-test:latest"] = struct{}{}
116
+	if daemonPlatform != runtime.GOOS {
117
+		ensureNNPTestBuild(c)
118
+		return
119
+	}
120
+
121
+	tmp, err := ioutil.TempDir("", "docker-nnp-test")
122
+	c.Assert(err, checker.IsNil)
123
+
124
+	gcc, err := exec.LookPath("gcc")
125
+	c.Assert(err, checker.IsNil, check.Commentf("could not find gcc"))
126
+
127
+	out, err := exec.Command(gcc, "-g", "-Wall", "-static", "../contrib/nnp-test/nnp-test.c", "-o", filepath.Join(tmp, "nnp-test")).CombinedOutput()
128
+	c.Assert(err, checker.IsNil, check.Commentf(string(out)))
129
+
130
+	dockerfile := filepath.Join(tmp, "Dockerfile")
131
+	content := `
132
+	FROM debian:jessie
133
+	COPY . /usr/bin
134
+	RUN chmod +s /usr/bin/nnp-test
135
+	`
136
+	err = ioutil.WriteFile(dockerfile, []byte(content), 600)
137
+	c.Assert(err, checker.IsNil, check.Commentf("could not write Dockerfile for nnp-test image"))
138
+
139
+	var buildArgs []string
140
+	if arg := os.Getenv("DOCKER_BUILD_ARGS"); strings.TrimSpace(arg) != "" {
141
+		buildArgs = strings.Split(arg, " ")
142
+	}
143
+	buildArgs = append(buildArgs, []string{"-q", "-t", "nnp-test", tmp}...)
144
+	buildArgs = append([]string{"build"}, buildArgs...)
145
+	dockerCmd(c, buildArgs...)
146
+}
147
+
148
+func ensureNNPTestBuild(c *check.C) {
149
+	err := load.FrozenImagesLinux(dockerBinary, "buildpack-deps:jessie")
150
+	c.Assert(err, checker.IsNil)
151
+
152
+	var buildArgs []string
153
+	if arg := os.Getenv("DOCKER_BUILD_ARGS"); strings.TrimSpace(arg) != "" {
154
+		buildArgs = strings.Split(arg, " ")
155
+	}
156
+	buildArgs = append(buildArgs, []string{"-q", "-t", "npp-test", "../contrib/nnp-test"}...)
157
+	buildArgs = append([]string{"build"}, buildArgs...)
158
+	dockerCmd(c, buildArgs...)
159
+}