Move some test fixtures to go
Michael Crosby authored on 2016/09/09 03:16:271 | 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 |
|
... | ... |
@@ -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 |
+} |