Browse code

Introduce a environment package in integration-cli

Signed-off-by: Vincent Demeester <vincent@sbr.pm>

Vincent Demeester authored on 2016/12/26 04:28:38
Showing 35 changed files
... ...
@@ -4,27 +4,136 @@ import (
4 4
 	"fmt"
5 5
 	"net/http/httptest"
6 6
 	"os"
7
+	"os/exec"
7 8
 	"path/filepath"
9
+	"strings"
8 10
 	"sync"
9 11
 	"syscall"
10 12
 	"testing"
11 13
 
14
+	"github.com/docker/docker/api/types/container"
12 15
 	"github.com/docker/docker/api/types/swarm"
13 16
 	cliconfig "github.com/docker/docker/cli/config"
14 17
 	"github.com/docker/docker/integration-cli/daemon"
18
+	"github.com/docker/docker/integration-cli/environment"
15 19
 	"github.com/docker/docker/pkg/reexec"
16 20
 	"github.com/go-check/check"
17 21
 )
18 22
 
19
-func Test(t *testing.T) {
23
+const (
24
+	// the private registry to use for tests
25
+	privateRegistryURL = "127.0.0.1:5000"
26
+
27
+	// path to containerd's ctr binary
28
+	ctrBinary = "docker-containerd-ctr"
29
+
30
+	// the docker daemon binary to use
31
+	dockerdBinary = "dockerd"
32
+)
33
+
34
+var (
35
+	testEnv *environment.Execution
36
+
37
+	// FIXME(vdemeester) remove these and use environmentdaemonPid
38
+	protectedImages = map[string]struct{}{}
39
+
40
+	// the docker client binary to use
41
+	dockerBinary = "docker"
42
+
43
+	// isLocalDaemon is true if the daemon under test is on the same
44
+	// host as the CLI.
45
+	isLocalDaemon bool
46
+	// daemonPlatform is held globally so that tests can make intelligent
47
+	// decisions on how to configure themselves according to the platform
48
+	// of the daemon. This is initialized in docker_utils by sending
49
+	// a version call to the daemon and examining the response header.
50
+	daemonPlatform string
51
+
52
+	// WindowsBaseImage is the name of the base image for Windows testing
53
+	// Environment variable WINDOWS_BASE_IMAGE can override this
54
+	WindowsBaseImage string
55
+
56
+	// For a local daemon on Linux, these values will be used for testing
57
+	// user namespace support as the standard graph path(s) will be
58
+	// appended with the root remapped uid.gid prefix
59
+	dockerBasePath       string
60
+	volumesConfigPath    string
61
+	containerStoragePath string
62
+
63
+	// daemonStorageDriver is held globally so that tests can know the storage
64
+	// driver of the daemon. This is initialized in docker_utils by sending
65
+	// a version call to the daemon and examining the response header.
66
+	daemonStorageDriver string
67
+
68
+	// isolation is the isolation mode of the daemon under test
69
+	isolation container.Isolation
70
+
71
+	// experimentalDaemon tell whether the main daemon has
72
+	// experimental features enabled or not
73
+	experimentalDaemon bool
74
+
75
+	daemonKernelVersion string
76
+)
77
+
78
+func init() {
79
+	var err error
80
+
20 81
 	reexec.Init() // This is required for external graphdriver tests
21 82
 
83
+	testEnv, err = environment.New()
84
+	if err != nil {
85
+		fmt.Println(err)
86
+		os.Exit(1)
87
+	}
88
+
89
+	assignGlobalVariablesFromTestEnv(testEnv)
90
+}
91
+
92
+// FIXME(vdemeester) remove this and use environment
93
+func assignGlobalVariablesFromTestEnv(testEnv *environment.Execution) {
94
+	isLocalDaemon = testEnv.LocalDaemon()
95
+	daemonPlatform = testEnv.DaemonPlatform()
96
+	dockerBasePath = testEnv.DockerBasePath()
97
+	volumesConfigPath = testEnv.VolumesConfigPath()
98
+	containerStoragePath = testEnv.ContainerStoragePath()
99
+	daemonStorageDriver = testEnv.DaemonStorageDriver()
100
+	isolation = testEnv.Isolation()
101
+	experimentalDaemon = testEnv.ExperimentalDaemon()
102
+	daemonKernelVersion = testEnv.DaemonKernelVersion()
103
+	WindowsBaseImage = testEnv.MinimalBaseImage()
104
+}
105
+
106
+func TestMain(m *testing.M) {
107
+	var err error
108
+	if dockerBin := os.Getenv("DOCKER_BINARY"); dockerBin != "" {
109
+		dockerBinary = dockerBin
110
+	}
111
+	dockerBinary, err = exec.LookPath(dockerBinary)
112
+	if err != nil {
113
+		fmt.Printf("ERROR: couldn't resolve full path to the Docker binary (%v)\n", err)
114
+		os.Exit(1)
115
+	}
116
+
117
+	cmd := exec.Command(dockerBinary, "images", "-f", "dangling=false", "--format", "{{.Repository}}:{{.Tag}}")
118
+	cmd.Env = appendBaseEnv(true)
119
+	out, err := cmd.CombinedOutput()
120
+	if err != nil {
121
+		panic(fmt.Errorf("err=%v\nout=%s\n", err, out))
122
+	}
123
+	images := strings.Split(strings.TrimSpace(string(out)), "\n")
124
+	for _, img := range images {
125
+		protectedImages[img] = struct{}{}
126
+	}
22 127
 	if !isLocalDaemon {
23 128
 		fmt.Println("INFO: Testing against a remote daemon")
24 129
 	} else {
25 130
 		fmt.Println("INFO: Testing against a local daemon")
26 131
 	}
132
+	exitCode := m.Run()
133
+	os.Exit(exitCode)
134
+}
27 135
 
136
+func Test(t *testing.T) {
28 137
 	if daemonPlatform == "linux" {
29 138
 		ensureFrozenImagesLinux(t)
30 139
 	}
... ...
@@ -39,8 +148,8 @@ type DockerSuite struct {
39 39
 }
40 40
 
41 41
 func (s *DockerSuite) OnTimeout(c *check.C) {
42
-	if daemonPid > 0 && isLocalDaemon {
43
-		daemon.SignalDaemonDump(daemonPid)
42
+	if testEnv.DaemonPID() > 0 && isLocalDaemon {
43
+		daemon.SignalDaemonDump(testEnv.DaemonPID())
44 44
 	}
45 45
 }
46 46
 
... ...
@@ -324,7 +324,7 @@ func (d *Daemon) StartWithLogFile(out *os.File, providedArgs ...string) error {
324 324
 func (d *Daemon) StartWithBusybox(t testingT, arg ...string) {
325 325
 	d.Start(t, arg...)
326 326
 	if err := d.LoadBusybox(); err != nil {
327
-		t.Fatalf("Error loading busybox image to current daeom: %s", d.id)
327
+		t.Fatalf("Error loading busybox image to current daemon: %s\n%v", d.id, err)
328 328
 	}
329 329
 }
330 330
 
... ...
@@ -10,6 +10,7 @@ import (
10 10
 
11 11
 	"github.com/docker/docker/api/types"
12 12
 	"github.com/docker/docker/api/types/container"
13
+	"github.com/docker/docker/integration-cli/environment"
13 14
 	"github.com/docker/docker/pkg/integration/checker"
14 15
 	icmd "github.com/docker/docker/pkg/integration/cmd"
15 16
 	"github.com/go-check/check"
... ...
@@ -212,7 +213,7 @@ func (s *DockerSuite) TestInspectBindMountPoint(c *check.C) {
212 212
 	if daemonPlatform == "windows" {
213 213
 		modifier = ""
214 214
 		// TODO Windows: Temporary check - remove once TP5 support is dropped
215
-		if windowsDaemonKV < 14350 {
215
+		if environment.WindowsKernelVersion(testEnv.DaemonKernelVersion()) < 14350 {
216 216
 			c.Skip("Needs later Windows build for RO volumes")
217 217
 		}
218 218
 		// Linux creates the host directory if it doesn't exist. Windows does not.
219 219
deleted file mode 100644
... ...
@@ -1,142 +0,0 @@
1
-package main
2
-
3
-import (
4
-	"encoding/json"
5
-	"fmt"
6
-	"io/ioutil"
7
-	"os"
8
-	"os/exec"
9
-	"path/filepath"
10
-	"strconv"
11
-
12
-	"github.com/docker/docker/api/types/container"
13
-	"github.com/docker/docker/pkg/reexec"
14
-)
15
-
16
-const (
17
-	// the private registry to use for tests
18
-	privateRegistryURL = "127.0.0.1:5000"
19
-
20
-	// the docker daemon binary to use
21
-	dockerdBinary = "dockerd"
22
-)
23
-
24
-var (
25
-	// the docker client binary to use
26
-	dockerBinary = "docker"
27
-
28
-	// path to containerd's ctr binary
29
-	ctrBinary = "docker-containerd-ctr"
30
-
31
-	// isLocalDaemon is true if the daemon under test is on the same
32
-	// host as the CLI.
33
-	isLocalDaemon bool
34
-
35
-	// daemonPlatform is held globally so that tests can make intelligent
36
-	// decisions on how to configure themselves according to the platform
37
-	// of the daemon. This is initialized in docker_utils by sending
38
-	// a version call to the daemon and examining the response header.
39
-	daemonPlatform string
40
-
41
-	// windowsDaemonKV is used on Windows to distinguish between different
42
-	// versions. This is necessary to enable certain tests based on whether
43
-	// the platform supports it. For example, Windows Server 2016 TP3 did
44
-	// not support volumes, but TP4 did.
45
-	windowsDaemonKV int
46
-
47
-	// For a local daemon on Linux, these values will be used for testing
48
-	// user namespace support as the standard graph path(s) will be
49
-	// appended with the root remapped uid.gid prefix
50
-	dockerBasePath       string
51
-	volumesConfigPath    string
52
-	containerStoragePath string
53
-
54
-	// experimentalDaemon tell whether the main daemon has
55
-	// experimental features enabled or not
56
-	experimentalDaemon bool
57
-
58
-	// daemonStorageDriver is held globally so that tests can know the storage
59
-	// driver of the daemon. This is initialized in docker_utils by sending
60
-	// a version call to the daemon and examining the response header.
61
-	daemonStorageDriver string
62
-
63
-	// WindowsBaseImage is the name of the base image for Windows testing
64
-	// Environment variable WINDOWS_BASE_IMAGE can override this
65
-	WindowsBaseImage = "microsoft/windowsservercore"
66
-
67
-	// isolation is the isolation mode of the daemon under test
68
-	isolation container.Isolation
69
-
70
-	// daemonPid is the pid of the main test daemon
71
-	daemonPid int
72
-
73
-	daemonKernelVersion string
74
-)
75
-
76
-func init() {
77
-	reexec.Init()
78
-	if dockerBin := os.Getenv("DOCKER_BINARY"); dockerBin != "" {
79
-		dockerBinary = dockerBin
80
-	}
81
-	var err error
82
-	dockerBinary, err = exec.LookPath(dockerBinary)
83
-	if err != nil {
84
-		fmt.Printf("ERROR: couldn't resolve full path to the Docker binary (%v)\n", err)
85
-		os.Exit(1)
86
-	}
87
-
88
-	// Deterministically working out the environment in which CI is running
89
-	// to evaluate whether the daemon is local or remote is not possible through
90
-	// a build tag.
91
-	//
92
-	// For example Windows to Linux CI under Jenkins tests the 64-bit
93
-	// Windows binary build with the daemon build tag, but calls a remote
94
-	// Linux daemon.
95
-	//
96
-	// We can't just say if Windows then assume the daemon is local as at
97
-	// some point, we will be testing the Windows CLI against a Windows daemon.
98
-	//
99
-	// Similarly, it will be perfectly valid to also run CLI tests from
100
-	// a Linux CLI (built with the daemon tag) against a Windows daemon.
101
-	if len(os.Getenv("DOCKER_REMOTE_DAEMON")) > 0 {
102
-		isLocalDaemon = false
103
-	} else {
104
-		isLocalDaemon = true
105
-	}
106
-
107
-	// TODO Windows CI. This are incorrect and need fixing into
108
-	// platform specific pieces.
109
-	// This is only used for a tests with local daemon true (Linux-only today)
110
-	// default is "/var/lib/docker", but we'll try and ask the
111
-	// /info endpoint for the specific root dir
112
-	dockerBasePath = "/var/lib/docker"
113
-	type Info struct {
114
-		DockerRootDir     string
115
-		ExperimentalBuild bool
116
-		KernelVersion     string
117
-	}
118
-	var i Info
119
-	status, b, err := sockRequest("GET", "/info", nil)
120
-	if err == nil && status == 200 {
121
-		if err = json.Unmarshal(b, &i); err == nil {
122
-			dockerBasePath = i.DockerRootDir
123
-			experimentalDaemon = i.ExperimentalBuild
124
-			daemonKernelVersion = i.KernelVersion
125
-		}
126
-	}
127
-	volumesConfigPath = dockerBasePath + "/volumes"
128
-	containerStoragePath = dockerBasePath + "/containers"
129
-
130
-	if len(os.Getenv("WINDOWS_BASE_IMAGE")) > 0 {
131
-		WindowsBaseImage = os.Getenv("WINDOWS_BASE_IMAGE")
132
-		fmt.Println("INFO: Windows Base image is ", WindowsBaseImage)
133
-	}
134
-
135
-	dest := os.Getenv("DEST")
136
-	b, err = ioutil.ReadFile(filepath.Join(dest, "docker.pid"))
137
-	if err == nil {
138
-		if p, err := strconv.ParseInt(string(b), 10, 32); err == nil {
139
-			daemonPid = int(p)
140
-		}
141
-	}
142
-}
143 1
deleted file mode 100644
... ...
@@ -1,1368 +0,0 @@
1
-package main
2
-
3
-import (
4
-	"bufio"
5
-	"bytes"
6
-	"encoding/json"
7
-	"errors"
8
-	"fmt"
9
-	"io"
10
-	"io/ioutil"
11
-	"net"
12
-	"net/http"
13
-	"net/http/httptest"
14
-	"net/http/httputil"
15
-	"net/url"
16
-	"os"
17
-	"os/exec"
18
-	"path"
19
-	"path/filepath"
20
-	"strconv"
21
-	"strings"
22
-	"time"
23
-
24
-	"github.com/docker/docker/api/types"
25
-	volumetypes "github.com/docker/docker/api/types/volume"
26
-	"github.com/docker/docker/integration-cli/daemon"
27
-	"github.com/docker/docker/opts"
28
-	"github.com/docker/docker/pkg/httputils"
29
-	"github.com/docker/docker/pkg/integration"
30
-	"github.com/docker/docker/pkg/integration/checker"
31
-	icmd "github.com/docker/docker/pkg/integration/cmd"
32
-	"github.com/docker/docker/pkg/ioutils"
33
-	"github.com/docker/docker/pkg/stringutils"
34
-	"github.com/go-check/check"
35
-)
36
-
37
-func init() {
38
-	cmd := exec.Command(dockerBinary, "images", "-f", "dangling=false", "--format", "{{.Repository}}:{{.Tag}}")
39
-	cmd.Env = appendBaseEnv(true)
40
-	out, err := cmd.CombinedOutput()
41
-	if err != nil {
42
-		panic(fmt.Errorf("err=%v\nout=%s\n", err, out))
43
-	}
44
-	images := strings.Split(strings.TrimSpace(string(out)), "\n")
45
-	for _, img := range images {
46
-		protectedImages[img] = struct{}{}
47
-	}
48
-
49
-	res, body, err := sockRequestRaw("GET", "/info", nil, "application/json")
50
-	if err != nil {
51
-		panic(fmt.Errorf("Init failed to get /info: %v", err))
52
-	}
53
-	defer body.Close()
54
-	if res.StatusCode != http.StatusOK {
55
-		panic(fmt.Errorf("Init failed to get /info. Res=%v", res))
56
-	}
57
-
58
-	svrHeader, _ := httputils.ParseServerHeader(res.Header.Get("Server"))
59
-	daemonPlatform = svrHeader.OS
60
-	if daemonPlatform != "linux" && daemonPlatform != "windows" {
61
-		panic("Cannot run tests against platform: " + daemonPlatform)
62
-	}
63
-
64
-	// Now we know the daemon platform, can set paths used by tests.
65
-	var info types.Info
66
-	err = json.NewDecoder(body).Decode(&info)
67
-	if err != nil {
68
-		panic(fmt.Errorf("Init failed to unmarshal docker info: %v", err))
69
-	}
70
-
71
-	daemonStorageDriver = info.Driver
72
-	dockerBasePath = info.DockerRootDir
73
-	volumesConfigPath = filepath.Join(dockerBasePath, "volumes")
74
-	containerStoragePath = filepath.Join(dockerBasePath, "containers")
75
-	// Make sure in context of daemon, not the local platform. Note we can't
76
-	// use filepath.FromSlash or ToSlash here as they are a no-op on Unix.
77
-	if daemonPlatform == "windows" {
78
-		volumesConfigPath = strings.Replace(volumesConfigPath, `/`, `\`, -1)
79
-		containerStoragePath = strings.Replace(containerStoragePath, `/`, `\`, -1)
80
-		// On Windows, extract out the version as we need to make selective
81
-		// decisions during integration testing as and when features are implemented.
82
-		// e.g. in "10.0 10550 (10550.1000.amd64fre.branch.date-time)" we want 10550
83
-		windowsDaemonKV, _ = strconv.Atoi(strings.Split(info.KernelVersion, " ")[1])
84
-	} else {
85
-		volumesConfigPath = strings.Replace(volumesConfigPath, `\`, `/`, -1)
86
-		containerStoragePath = strings.Replace(containerStoragePath, `\`, `/`, -1)
87
-	}
88
-	isolation = info.Isolation
89
-}
90
-
91
-func daemonHost() string {
92
-	daemonURLStr := "unix://" + opts.DefaultUnixSocket
93
-	if daemonHostVar := os.Getenv("DOCKER_HOST"); daemonHostVar != "" {
94
-		daemonURLStr = daemonHostVar
95
-	}
96
-	return daemonURLStr
97
-}
98
-
99
-// FIXME(vdemeester) should probably completely move to daemon struct/methods
100
-func sockConn(timeout time.Duration, daemonStr string) (net.Conn, error) {
101
-	if daemonStr == "" {
102
-		daemonStr = daemonHost()
103
-	}
104
-	return daemon.SockConn(timeout, daemonStr)
105
-}
106
-
107
-func sockRequest(method, endpoint string, data interface{}) (int, []byte, error) {
108
-	jsonData := bytes.NewBuffer(nil)
109
-	if err := json.NewEncoder(jsonData).Encode(data); err != nil {
110
-		return -1, nil, err
111
-	}
112
-
113
-	res, body, err := sockRequestRaw(method, endpoint, jsonData, "application/json")
114
-	if err != nil {
115
-		return -1, nil, err
116
-	}
117
-	b, err := integration.ReadBody(body)
118
-	return res.StatusCode, b, err
119
-}
120
-
121
-func sockRequestRaw(method, endpoint string, data io.Reader, ct string) (*http.Response, io.ReadCloser, error) {
122
-	return sockRequestRawToDaemon(method, endpoint, data, ct, "")
123
-}
124
-
125
-func sockRequestRawToDaemon(method, endpoint string, data io.Reader, ct, daemon string) (*http.Response, io.ReadCloser, error) {
126
-	req, client, err := newRequestClient(method, endpoint, data, ct, daemon)
127
-	if err != nil {
128
-		return nil, nil, err
129
-	}
130
-
131
-	resp, err := client.Do(req)
132
-	if err != nil {
133
-		client.Close()
134
-		return nil, nil, err
135
-	}
136
-	body := ioutils.NewReadCloserWrapper(resp.Body, func() error {
137
-		defer resp.Body.Close()
138
-		return client.Close()
139
-	})
140
-
141
-	return resp, body, nil
142
-}
143
-
144
-func sockRequestHijack(method, endpoint string, data io.Reader, ct string) (net.Conn, *bufio.Reader, error) {
145
-	req, client, err := newRequestClient(method, endpoint, data, ct, "")
146
-	if err != nil {
147
-		return nil, nil, err
148
-	}
149
-
150
-	client.Do(req)
151
-	conn, br := client.Hijack()
152
-	return conn, br, nil
153
-}
154
-
155
-func newRequestClient(method, endpoint string, data io.Reader, ct, daemon string) (*http.Request, *httputil.ClientConn, error) {
156
-	c, err := sockConn(time.Duration(10*time.Second), daemon)
157
-	if err != nil {
158
-		return nil, nil, fmt.Errorf("could not dial docker daemon: %v", err)
159
-	}
160
-
161
-	client := httputil.NewClientConn(c, nil)
162
-
163
-	req, err := http.NewRequest(method, endpoint, data)
164
-	if err != nil {
165
-		client.Close()
166
-		return nil, nil, fmt.Errorf("could not create new request: %v", err)
167
-	}
168
-
169
-	if ct != "" {
170
-		req.Header.Set("Content-Type", ct)
171
-	}
172
-	return req, client, nil
173
-}
174
-
175
-func deleteContainer(container ...string) error {
176
-	result := icmd.RunCommand(dockerBinary, append([]string{"rm", "-fv"}, container...)...)
177
-	return result.Compare(icmd.Success)
178
-}
179
-
180
-func getAllContainers() (string, error) {
181
-	getContainersCmd := exec.Command(dockerBinary, "ps", "-q", "-a")
182
-	out, exitCode, err := runCommandWithOutput(getContainersCmd)
183
-	if exitCode != 0 && err == nil {
184
-		err = fmt.Errorf("failed to get a list of containers: %v\n", out)
185
-	}
186
-
187
-	return out, err
188
-}
189
-
190
-func deleteAllContainers(c *check.C) {
191
-	containers, err := getAllContainers()
192
-	c.Assert(err, checker.IsNil, check.Commentf("containers: %v", containers))
193
-
194
-	if containers != "" {
195
-		err = deleteContainer(strings.Split(strings.TrimSpace(containers), "\n")...)
196
-		c.Assert(err, checker.IsNil)
197
-	}
198
-}
199
-
200
-func deleteAllNetworks(c *check.C) {
201
-	networks, err := getAllNetworks()
202
-	c.Assert(err, check.IsNil)
203
-	var errs []string
204
-	for _, n := range networks {
205
-		if n.Name == "bridge" || n.Name == "none" || n.Name == "host" {
206
-			continue
207
-		}
208
-		if daemonPlatform == "windows" && strings.ToLower(n.Name) == "nat" {
209
-			// nat is a pre-defined network on Windows and cannot be removed
210
-			continue
211
-		}
212
-		status, b, err := sockRequest("DELETE", "/networks/"+n.Name, nil)
213
-		if err != nil {
214
-			errs = append(errs, err.Error())
215
-			continue
216
-		}
217
-		if status != http.StatusNoContent {
218
-			errs = append(errs, fmt.Sprintf("error deleting network %s: %s", n.Name, string(b)))
219
-		}
220
-	}
221
-	c.Assert(errs, checker.HasLen, 0, check.Commentf(strings.Join(errs, "\n")))
222
-}
223
-
224
-func getAllNetworks() ([]types.NetworkResource, error) {
225
-	var networks []types.NetworkResource
226
-	_, b, err := sockRequest("GET", "/networks", nil)
227
-	if err != nil {
228
-		return nil, err
229
-	}
230
-	if err := json.Unmarshal(b, &networks); err != nil {
231
-		return nil, err
232
-	}
233
-	return networks, nil
234
-}
235
-
236
-func deleteAllPlugins(c *check.C) {
237
-	plugins, err := getAllPlugins()
238
-	c.Assert(err, checker.IsNil)
239
-	var errs []string
240
-	for _, p := range plugins {
241
-		pluginName := p.Name
242
-		status, b, err := sockRequest("DELETE", "/plugins/"+pluginName+"?force=1", nil)
243
-		if err != nil {
244
-			errs = append(errs, err.Error())
245
-			continue
246
-		}
247
-		if status != http.StatusOK {
248
-			errs = append(errs, fmt.Sprintf("error deleting plugin %s: %s", p.Name, string(b)))
249
-		}
250
-	}
251
-	c.Assert(errs, checker.HasLen, 0, check.Commentf(strings.Join(errs, "\n")))
252
-}
253
-
254
-func getAllPlugins() (types.PluginsListResponse, error) {
255
-	var plugins types.PluginsListResponse
256
-	_, b, err := sockRequest("GET", "/plugins", nil)
257
-	if err != nil {
258
-		return nil, err
259
-	}
260
-	if err := json.Unmarshal(b, &plugins); err != nil {
261
-		return nil, err
262
-	}
263
-	return plugins, nil
264
-}
265
-
266
-func deleteAllVolumes(c *check.C) {
267
-	volumes, err := getAllVolumes()
268
-	c.Assert(err, checker.IsNil)
269
-	var errs []string
270
-	for _, v := range volumes {
271
-		status, b, err := sockRequest("DELETE", "/volumes/"+v.Name, nil)
272
-		if err != nil {
273
-			errs = append(errs, err.Error())
274
-			continue
275
-		}
276
-		if status != http.StatusNoContent {
277
-			errs = append(errs, fmt.Sprintf("error deleting volume %s: %s", v.Name, string(b)))
278
-		}
279
-	}
280
-	c.Assert(errs, checker.HasLen, 0, check.Commentf(strings.Join(errs, "\n")))
281
-}
282
-
283
-func getAllVolumes() ([]*types.Volume, error) {
284
-	var volumes volumetypes.VolumesListOKBody
285
-	_, b, err := sockRequest("GET", "/volumes", nil)
286
-	if err != nil {
287
-		return nil, err
288
-	}
289
-	if err := json.Unmarshal(b, &volumes); err != nil {
290
-		return nil, err
291
-	}
292
-	return volumes.Volumes, nil
293
-}
294
-
295
-var protectedImages = map[string]struct{}{}
296
-
297
-func deleteAllImages(c *check.C) {
298
-	cmd := exec.Command(dockerBinary, "images", "--digests")
299
-	cmd.Env = appendBaseEnv(true)
300
-	out, err := cmd.CombinedOutput()
301
-	c.Assert(err, checker.IsNil)
302
-	lines := strings.Split(string(out), "\n")[1:]
303
-	imgMap := map[string]struct{}{}
304
-	for _, l := range lines {
305
-		if l == "" {
306
-			continue
307
-		}
308
-		fields := strings.Fields(l)
309
-		imgTag := fields[0] + ":" + fields[1]
310
-		if _, ok := protectedImages[imgTag]; !ok {
311
-			if fields[0] == "<none>" || fields[1] == "<none>" {
312
-				if fields[2] != "<none>" {
313
-					imgMap[fields[0]+"@"+fields[2]] = struct{}{}
314
-				} else {
315
-					imgMap[fields[3]] = struct{}{}
316
-				}
317
-				// continue
318
-			} else {
319
-				imgMap[imgTag] = struct{}{}
320
-			}
321
-		}
322
-	}
323
-	if len(imgMap) != 0 {
324
-		imgs := make([]string, 0, len(imgMap))
325
-		for k := range imgMap {
326
-			imgs = append(imgs, k)
327
-		}
328
-		dockerCmd(c, append([]string{"rmi", "-f"}, imgs...)...)
329
-	}
330
-}
331
-
332
-func getPausedContainers() ([]string, error) {
333
-	getPausedContainersCmd := exec.Command(dockerBinary, "ps", "-f", "status=paused", "-q", "-a")
334
-	out, exitCode, err := runCommandWithOutput(getPausedContainersCmd)
335
-	if exitCode != 0 && err == nil {
336
-		err = fmt.Errorf("failed to get a list of paused containers: %v\n", out)
337
-	}
338
-	if err != nil {
339
-		return nil, err
340
-	}
341
-
342
-	return strings.Fields(out), nil
343
-}
344
-
345
-func unpauseContainer(c *check.C, container string) {
346
-	dockerCmd(c, "unpause", container)
347
-}
348
-
349
-func unpauseAllContainers(c *check.C) {
350
-	containers, err := getPausedContainers()
351
-	c.Assert(err, checker.IsNil, check.Commentf("containers: %v", containers))
352
-	for _, value := range containers {
353
-		unpauseContainer(c, value)
354
-	}
355
-}
356
-
357
-func deleteImages(images ...string) error {
358
-	args := []string{dockerBinary, "rmi", "-f"}
359
-	return icmd.RunCmd(icmd.Cmd{Command: append(args, images...)}).Error
360
-}
361
-
362
-func dockerCmdWithError(args ...string) (string, int, error) {
363
-	if err := validateArgs(args...); err != nil {
364
-		return "", 0, err
365
-	}
366
-	result := icmd.RunCommand(dockerBinary, args...)
367
-	if result.Error != nil {
368
-		return result.Combined(), result.ExitCode, result.Compare(icmd.Success)
369
-	}
370
-	return result.Combined(), result.ExitCode, result.Error
371
-}
372
-
373
-func dockerCmdWithStdoutStderr(c *check.C, args ...string) (string, string, int) {
374
-	if err := validateArgs(args...); err != nil {
375
-		c.Fatalf(err.Error())
376
-	}
377
-
378
-	result := icmd.RunCommand(dockerBinary, args...)
379
-	c.Assert(result, icmd.Matches, icmd.Success)
380
-	return result.Stdout(), result.Stderr(), result.ExitCode
381
-}
382
-
383
-func dockerCmd(c *check.C, args ...string) (string, int) {
384
-	if err := validateArgs(args...); err != nil {
385
-		c.Fatalf(err.Error())
386
-	}
387
-	result := icmd.RunCommand(dockerBinary, args...)
388
-	c.Assert(result, icmd.Matches, icmd.Success)
389
-	return result.Combined(), result.ExitCode
390
-}
391
-
392
-func dockerCmdWithResult(args ...string) *icmd.Result {
393
-	return icmd.RunCommand(dockerBinary, args...)
394
-}
395
-
396
-func binaryWithArgs(args ...string) []string {
397
-	return append([]string{dockerBinary}, args...)
398
-}
399
-
400
-// execute a docker command with a timeout
401
-func dockerCmdWithTimeout(timeout time.Duration, args ...string) *icmd.Result {
402
-	if err := validateArgs(args...); err != nil {
403
-		return &icmd.Result{Error: err}
404
-	}
405
-	return icmd.RunCmd(icmd.Cmd{Command: binaryWithArgs(args...), Timeout: timeout})
406
-}
407
-
408
-// execute a docker command in a directory
409
-func dockerCmdInDir(c *check.C, path string, args ...string) (string, int, error) {
410
-	if err := validateArgs(args...); err != nil {
411
-		c.Fatalf(err.Error())
412
-	}
413
-	result := icmd.RunCmd(icmd.Cmd{Command: binaryWithArgs(args...), Dir: path})
414
-	return result.Combined(), result.ExitCode, result.Error
415
-}
416
-
417
-// validateArgs is a checker to ensure tests are not running commands which are
418
-// not supported on platforms. Specifically on Windows this is 'busybox top'.
419
-func validateArgs(args ...string) error {
420
-	if daemonPlatform != "windows" {
421
-		return nil
422
-	}
423
-	foundBusybox := -1
424
-	for key, value := range args {
425
-		if strings.ToLower(value) == "busybox" {
426
-			foundBusybox = key
427
-		}
428
-		if (foundBusybox != -1) && (key == foundBusybox+1) && (strings.ToLower(value) == "top") {
429
-			return errors.New("cannot use 'busybox top' in tests on Windows. Use runSleepingContainer()")
430
-		}
431
-	}
432
-	return nil
433
-}
434
-
435
-// find the State.ExitCode in container metadata
436
-func findContainerExitCode(c *check.C, name string, vargs ...string) string {
437
-	args := append(vargs, "inspect", "--format='{{ .State.ExitCode }} {{ .State.Error }}'", name)
438
-	cmd := exec.Command(dockerBinary, args...)
439
-	out, _, err := runCommandWithOutput(cmd)
440
-	if err != nil {
441
-		c.Fatal(err, out)
442
-	}
443
-	return out
444
-}
445
-
446
-func findContainerIP(c *check.C, id string, network string) string {
447
-	out, _ := dockerCmd(c, "inspect", fmt.Sprintf("--format='{{ .NetworkSettings.Networks.%s.IPAddress }}'", network), id)
448
-	return strings.Trim(out, " \r\n'")
449
-}
450
-
451
-func getContainerCount() (int, error) {
452
-	const containers = "Containers:"
453
-
454
-	cmd := exec.Command(dockerBinary, "info")
455
-	out, _, err := runCommandWithOutput(cmd)
456
-	if err != nil {
457
-		return 0, err
458
-	}
459
-
460
-	lines := strings.Split(out, "\n")
461
-	for _, line := range lines {
462
-		if strings.Contains(line, containers) {
463
-			output := strings.TrimSpace(line)
464
-			output = strings.TrimLeft(output, containers)
465
-			output = strings.Trim(output, " ")
466
-			containerCount, err := strconv.Atoi(output)
467
-			if err != nil {
468
-				return 0, err
469
-			}
470
-			return containerCount, nil
471
-		}
472
-	}
473
-	return 0, fmt.Errorf("couldn't find the Container count in the output")
474
-}
475
-
476
-// FakeContext creates directories that can be used as a build context
477
-type FakeContext struct {
478
-	Dir string
479
-}
480
-
481
-// Add a file at a path, creating directories where necessary
482
-func (f *FakeContext) Add(file, content string) error {
483
-	return f.addFile(file, []byte(content))
484
-}
485
-
486
-func (f *FakeContext) addFile(file string, content []byte) error {
487
-	fp := filepath.Join(f.Dir, filepath.FromSlash(file))
488
-	dirpath := filepath.Dir(fp)
489
-	if dirpath != "." {
490
-		if err := os.MkdirAll(dirpath, 0755); err != nil {
491
-			return err
492
-		}
493
-	}
494
-	return ioutil.WriteFile(fp, content, 0644)
495
-
496
-}
497
-
498
-// Delete a file at a path
499
-func (f *FakeContext) Delete(file string) error {
500
-	fp := filepath.Join(f.Dir, filepath.FromSlash(file))
501
-	return os.RemoveAll(fp)
502
-}
503
-
504
-// Close deletes the context
505
-func (f *FakeContext) Close() error {
506
-	return os.RemoveAll(f.Dir)
507
-}
508
-
509
-func fakeContextFromNewTempDir() (*FakeContext, error) {
510
-	tmp, err := ioutil.TempDir("", "fake-context")
511
-	if err != nil {
512
-		return nil, err
513
-	}
514
-	if err := os.Chmod(tmp, 0755); err != nil {
515
-		return nil, err
516
-	}
517
-	return fakeContextFromDir(tmp), nil
518
-}
519
-
520
-func fakeContextFromDir(dir string) *FakeContext {
521
-	return &FakeContext{dir}
522
-}
523
-
524
-func fakeContextWithFiles(files map[string]string) (*FakeContext, error) {
525
-	ctx, err := fakeContextFromNewTempDir()
526
-	if err != nil {
527
-		return nil, err
528
-	}
529
-	for file, content := range files {
530
-		if err := ctx.Add(file, content); err != nil {
531
-			ctx.Close()
532
-			return nil, err
533
-		}
534
-	}
535
-	return ctx, nil
536
-}
537
-
538
-func fakeContextAddDockerfile(ctx *FakeContext, dockerfile string) error {
539
-	if err := ctx.Add("Dockerfile", dockerfile); err != nil {
540
-		ctx.Close()
541
-		return err
542
-	}
543
-	return nil
544
-}
545
-
546
-func fakeContext(dockerfile string, files map[string]string) (*FakeContext, error) {
547
-	ctx, err := fakeContextWithFiles(files)
548
-	if err != nil {
549
-		return nil, err
550
-	}
551
-	if err := fakeContextAddDockerfile(ctx, dockerfile); err != nil {
552
-		return nil, err
553
-	}
554
-	return ctx, nil
555
-}
556
-
557
-// FakeStorage is a static file server. It might be running locally or remotely
558
-// on test host.
559
-type FakeStorage interface {
560
-	Close() error
561
-	URL() string
562
-	CtxDir() string
563
-}
564
-
565
-func fakeBinaryStorage(archives map[string]*bytes.Buffer) (FakeStorage, error) {
566
-	ctx, err := fakeContextFromNewTempDir()
567
-	if err != nil {
568
-		return nil, err
569
-	}
570
-	for name, content := range archives {
571
-		if err := ctx.addFile(name, content.Bytes()); err != nil {
572
-			return nil, err
573
-		}
574
-	}
575
-	return fakeStorageWithContext(ctx)
576
-}
577
-
578
-// fakeStorage returns either a local or remote (at daemon machine) file server
579
-func fakeStorage(files map[string]string) (FakeStorage, error) {
580
-	ctx, err := fakeContextWithFiles(files)
581
-	if err != nil {
582
-		return nil, err
583
-	}
584
-	return fakeStorageWithContext(ctx)
585
-}
586
-
587
-// fakeStorageWithContext returns either a local or remote (at daemon machine) file server
588
-func fakeStorageWithContext(ctx *FakeContext) (FakeStorage, error) {
589
-	if isLocalDaemon {
590
-		return newLocalFakeStorage(ctx)
591
-	}
592
-	return newRemoteFileServer(ctx)
593
-}
594
-
595
-// localFileStorage is a file storage on the running machine
596
-type localFileStorage struct {
597
-	*FakeContext
598
-	*httptest.Server
599
-}
600
-
601
-func (s *localFileStorage) URL() string {
602
-	return s.Server.URL
603
-}
604
-
605
-func (s *localFileStorage) CtxDir() string {
606
-	return s.FakeContext.Dir
607
-}
608
-
609
-func (s *localFileStorage) Close() error {
610
-	defer s.Server.Close()
611
-	return s.FakeContext.Close()
612
-}
613
-
614
-func newLocalFakeStorage(ctx *FakeContext) (*localFileStorage, error) {
615
-	handler := http.FileServer(http.Dir(ctx.Dir))
616
-	server := httptest.NewServer(handler)
617
-	return &localFileStorage{
618
-		FakeContext: ctx,
619
-		Server:      server,
620
-	}, nil
621
-}
622
-
623
-// remoteFileServer is a containerized static file server started on the remote
624
-// testing machine to be used in URL-accepting docker build functionality.
625
-type remoteFileServer struct {
626
-	host      string // hostname/port web server is listening to on docker host e.g. 0.0.0.0:43712
627
-	container string
628
-	image     string
629
-	ctx       *FakeContext
630
-}
631
-
632
-func (f *remoteFileServer) URL() string {
633
-	u := url.URL{
634
-		Scheme: "http",
635
-		Host:   f.host}
636
-	return u.String()
637
-}
638
-
639
-func (f *remoteFileServer) CtxDir() string {
640
-	return f.ctx.Dir
641
-}
642
-
643
-func (f *remoteFileServer) Close() error {
644
-	defer func() {
645
-		if f.ctx != nil {
646
-			f.ctx.Close()
647
-		}
648
-		if f.image != "" {
649
-			deleteImages(f.image)
650
-		}
651
-	}()
652
-	if f.container == "" {
653
-		return nil
654
-	}
655
-	return deleteContainer(f.container)
656
-}
657
-
658
-func newRemoteFileServer(ctx *FakeContext) (*remoteFileServer, error) {
659
-	var (
660
-		image     = fmt.Sprintf("fileserver-img-%s", strings.ToLower(stringutils.GenerateRandomAlphaOnlyString(10)))
661
-		container = fmt.Sprintf("fileserver-cnt-%s", strings.ToLower(stringutils.GenerateRandomAlphaOnlyString(10)))
662
-	)
663
-
664
-	if err := ensureHTTPServerImage(); err != nil {
665
-		return nil, err
666
-	}
667
-
668
-	// Build the image
669
-	if err := fakeContextAddDockerfile(ctx, `FROM httpserver
670
-COPY . /static`); err != nil {
671
-		return nil, fmt.Errorf("Cannot add Dockerfile to context: %v", err)
672
-	}
673
-	if _, err := buildImageFromContext(image, ctx, false); err != nil {
674
-		return nil, fmt.Errorf("failed building file storage container image: %v", err)
675
-	}
676
-
677
-	// Start the container
678
-	runCmd := exec.Command(dockerBinary, "run", "-d", "-P", "--name", container, image)
679
-	if out, ec, err := runCommandWithOutput(runCmd); err != nil {
680
-		return nil, fmt.Errorf("failed to start file storage container. ec=%v\nout=%s\nerr=%v", ec, out, err)
681
-	}
682
-
683
-	// Find out the system assigned port
684
-	out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "port", container, "80/tcp"))
685
-	if err != nil {
686
-		return nil, fmt.Errorf("failed to find container port: err=%v\nout=%s", err, out)
687
-	}
688
-
689
-	fileserverHostPort := strings.Trim(out, "\n")
690
-	_, port, err := net.SplitHostPort(fileserverHostPort)
691
-	if err != nil {
692
-		return nil, fmt.Errorf("unable to parse file server host:port: %v", err)
693
-	}
694
-
695
-	dockerHostURL, err := url.Parse(daemonHost())
696
-	if err != nil {
697
-		return nil, fmt.Errorf("unable to parse daemon host URL: %v", err)
698
-	}
699
-
700
-	host, _, err := net.SplitHostPort(dockerHostURL.Host)
701
-	if err != nil {
702
-		return nil, fmt.Errorf("unable to parse docker daemon host:port: %v", err)
703
-	}
704
-
705
-	return &remoteFileServer{
706
-		container: container,
707
-		image:     image,
708
-		host:      fmt.Sprintf("%s:%s", host, port),
709
-		ctx:       ctx}, nil
710
-}
711
-
712
-func inspectFieldAndMarshall(c *check.C, name, field string, output interface{}) {
713
-	str := inspectFieldJSON(c, name, field)
714
-	err := json.Unmarshal([]byte(str), output)
715
-	if c != nil {
716
-		c.Assert(err, check.IsNil, check.Commentf("failed to unmarshal: %v", err))
717
-	}
718
-}
719
-
720
-func inspectFilter(name, filter string) (string, error) {
721
-	format := fmt.Sprintf("{{%s}}", filter)
722
-	inspectCmd := exec.Command(dockerBinary, "inspect", "-f", format, name)
723
-	out, exitCode, err := runCommandWithOutput(inspectCmd)
724
-	if err != nil || exitCode != 0 {
725
-		return "", fmt.Errorf("failed to inspect %s: %s", name, out)
726
-	}
727
-	return strings.TrimSpace(out), nil
728
-}
729
-
730
-func inspectFieldWithError(name, field string) (string, error) {
731
-	return inspectFilter(name, fmt.Sprintf(".%s", field))
732
-}
733
-
734
-func inspectField(c *check.C, name, field string) string {
735
-	out, err := inspectFilter(name, fmt.Sprintf(".%s", field))
736
-	if c != nil {
737
-		c.Assert(err, check.IsNil)
738
-	}
739
-	return out
740
-}
741
-
742
-func inspectFieldJSON(c *check.C, name, field string) string {
743
-	out, err := inspectFilter(name, fmt.Sprintf("json .%s", field))
744
-	if c != nil {
745
-		c.Assert(err, check.IsNil)
746
-	}
747
-	return out
748
-}
749
-
750
-func inspectFieldMap(c *check.C, name, path, field string) string {
751
-	out, err := inspectFilter(name, fmt.Sprintf("index .%s %q", path, field))
752
-	if c != nil {
753
-		c.Assert(err, check.IsNil)
754
-	}
755
-	return out
756
-}
757
-
758
-func inspectMountSourceField(name, destination string) (string, error) {
759
-	m, err := inspectMountPoint(name, destination)
760
-	if err != nil {
761
-		return "", err
762
-	}
763
-	return m.Source, nil
764
-}
765
-
766
-func inspectMountPoint(name, destination string) (types.MountPoint, error) {
767
-	out, err := inspectFilter(name, "json .Mounts")
768
-	if err != nil {
769
-		return types.MountPoint{}, err
770
-	}
771
-
772
-	return inspectMountPointJSON(out, destination)
773
-}
774
-
775
-var errMountNotFound = errors.New("mount point not found")
776
-
777
-func inspectMountPointJSON(j, destination string) (types.MountPoint, error) {
778
-	var mp []types.MountPoint
779
-	if err := json.Unmarshal([]byte(j), &mp); err != nil {
780
-		return types.MountPoint{}, err
781
-	}
782
-
783
-	var m *types.MountPoint
784
-	for _, c := range mp {
785
-		if c.Destination == destination {
786
-			m = &c
787
-			break
788
-		}
789
-	}
790
-
791
-	if m == nil {
792
-		return types.MountPoint{}, errMountNotFound
793
-	}
794
-
795
-	return *m, nil
796
-}
797
-
798
-func inspectImage(name, filter string) (string, error) {
799
-	args := []string{"inspect", "--type", "image"}
800
-	if filter != "" {
801
-		format := fmt.Sprintf("{{%s}}", filter)
802
-		args = append(args, "-f", format)
803
-	}
804
-	args = append(args, name)
805
-	inspectCmd := exec.Command(dockerBinary, args...)
806
-	out, exitCode, err := runCommandWithOutput(inspectCmd)
807
-	if err != nil || exitCode != 0 {
808
-		return "", fmt.Errorf("failed to inspect %s: %s", name, out)
809
-	}
810
-	return strings.TrimSpace(out), nil
811
-}
812
-
813
-func getIDByName(name string) (string, error) {
814
-	return inspectFieldWithError(name, "Id")
815
-}
816
-
817
-func buildImageCmd(name, dockerfile string, useCache bool, buildFlags ...string) *exec.Cmd {
818
-	return daemon.BuildImageCmdWithHost(dockerBinary, name, dockerfile, "", useCache, buildFlags...)
819
-}
820
-
821
-func buildImageWithOut(name, dockerfile string, useCache bool, buildFlags ...string) (string, string, error) {
822
-	buildCmd := buildImageCmd(name, dockerfile, useCache, buildFlags...)
823
-	out, exitCode, err := runCommandWithOutput(buildCmd)
824
-	if err != nil || exitCode != 0 {
825
-		return "", out, fmt.Errorf("failed to build the image: %s", out)
826
-	}
827
-	id, err := getIDByName(name)
828
-	if err != nil {
829
-		return "", out, err
830
-	}
831
-	return id, out, nil
832
-}
833
-
834
-func buildImageWithStdoutStderr(name, dockerfile string, useCache bool, buildFlags ...string) (string, string, string, error) {
835
-	buildCmd := buildImageCmd(name, dockerfile, useCache, buildFlags...)
836
-	result := icmd.RunCmd(transformCmd(buildCmd))
837
-	err := result.Error
838
-	exitCode := result.ExitCode
839
-	if err != nil || exitCode != 0 {
840
-		return "", result.Stdout(), result.Stderr(), fmt.Errorf("failed to build the image: %s", result.Combined())
841
-	}
842
-	id, err := getIDByName(name)
843
-	if err != nil {
844
-		return "", result.Stdout(), result.Stderr(), err
845
-	}
846
-	return id, result.Stdout(), result.Stderr(), nil
847
-}
848
-
849
-func buildImage(name, dockerfile string, useCache bool, buildFlags ...string) (string, error) {
850
-	id, _, err := buildImageWithOut(name, dockerfile, useCache, buildFlags...)
851
-	return id, err
852
-}
853
-
854
-func buildImageFromContext(name string, ctx *FakeContext, useCache bool, buildFlags ...string) (string, error) {
855
-	id, _, err := buildImageFromContextWithOut(name, ctx, useCache, buildFlags...)
856
-	if err != nil {
857
-		return "", err
858
-	}
859
-	return id, nil
860
-}
861
-
862
-func buildImageFromContextWithOut(name string, ctx *FakeContext, useCache bool, buildFlags ...string) (string, string, error) {
863
-	args := []string{"build", "-t", name}
864
-	if !useCache {
865
-		args = append(args, "--no-cache")
866
-	}
867
-	args = append(args, buildFlags...)
868
-	args = append(args, ".")
869
-	buildCmd := exec.Command(dockerBinary, args...)
870
-	buildCmd.Dir = ctx.Dir
871
-	out, exitCode, err := runCommandWithOutput(buildCmd)
872
-	if err != nil || exitCode != 0 {
873
-		return "", "", fmt.Errorf("failed to build the image: %s", out)
874
-	}
875
-	id, err := getIDByName(name)
876
-	if err != nil {
877
-		return "", "", err
878
-	}
879
-	return id, out, nil
880
-}
881
-
882
-func buildImageFromContextWithStdoutStderr(name string, ctx *FakeContext, useCache bool, buildFlags ...string) (string, string, string, error) {
883
-	args := []string{"build", "-t", name}
884
-	if !useCache {
885
-		args = append(args, "--no-cache")
886
-	}
887
-	args = append(args, buildFlags...)
888
-	args = append(args, ".")
889
-
890
-	result := icmd.RunCmd(icmd.Cmd{
891
-		Command: append([]string{dockerBinary}, args...),
892
-		Dir:     ctx.Dir,
893
-	})
894
-	exitCode := result.ExitCode
895
-	err := result.Error
896
-	if err != nil || exitCode != 0 {
897
-		return "", result.Stdout(), result.Stderr(), fmt.Errorf("failed to build the image: %s", result.Combined())
898
-	}
899
-	id, err := getIDByName(name)
900
-	if err != nil {
901
-		return "", result.Stdout(), result.Stderr(), err
902
-	}
903
-	return id, result.Stdout(), result.Stderr(), nil
904
-}
905
-
906
-func buildImageFromGitWithStdoutStderr(name string, ctx *fakeGit, useCache bool, buildFlags ...string) (string, string, string, error) {
907
-	args := []string{"build", "-t", name}
908
-	if !useCache {
909
-		args = append(args, "--no-cache")
910
-	}
911
-	args = append(args, buildFlags...)
912
-	args = append(args, ctx.RepoURL)
913
-	result := icmd.RunCmd(icmd.Cmd{
914
-		Command: append([]string{dockerBinary}, args...),
915
-	})
916
-	exitCode := result.ExitCode
917
-	err := result.Error
918
-	if err != nil || exitCode != 0 {
919
-		return "", result.Stdout(), result.Stderr(), fmt.Errorf("failed to build the image: %s", result.Combined())
920
-	}
921
-	id, err := getIDByName(name)
922
-	if err != nil {
923
-		return "", result.Stdout(), result.Stderr(), err
924
-	}
925
-	return id, result.Stdout(), result.Stderr(), nil
926
-}
927
-
928
-func buildImageFromPath(name, path string, useCache bool, buildFlags ...string) (string, error) {
929
-	args := []string{"build", "-t", name}
930
-	if !useCache {
931
-		args = append(args, "--no-cache")
932
-	}
933
-	args = append(args, buildFlags...)
934
-	args = append(args, path)
935
-	buildCmd := exec.Command(dockerBinary, args...)
936
-	out, exitCode, err := runCommandWithOutput(buildCmd)
937
-	if err != nil || exitCode != 0 {
938
-		return "", fmt.Errorf("failed to build the image: %s", out)
939
-	}
940
-	return getIDByName(name)
941
-}
942
-
943
-type gitServer interface {
944
-	URL() string
945
-	Close() error
946
-}
947
-
948
-type localGitServer struct {
949
-	*httptest.Server
950
-}
951
-
952
-func (r *localGitServer) Close() error {
953
-	r.Server.Close()
954
-	return nil
955
-}
956
-
957
-func (r *localGitServer) URL() string {
958
-	return r.Server.URL
959
-}
960
-
961
-type fakeGit struct {
962
-	root    string
963
-	server  gitServer
964
-	RepoURL string
965
-}
966
-
967
-func (g *fakeGit) Close() {
968
-	g.server.Close()
969
-	os.RemoveAll(g.root)
970
-}
971
-
972
-func newFakeGit(name string, files map[string]string, enforceLocalServer bool) (*fakeGit, error) {
973
-	ctx, err := fakeContextWithFiles(files)
974
-	if err != nil {
975
-		return nil, err
976
-	}
977
-	defer ctx.Close()
978
-	curdir, err := os.Getwd()
979
-	if err != nil {
980
-		return nil, err
981
-	}
982
-	defer os.Chdir(curdir)
983
-
984
-	if output, err := exec.Command("git", "init", ctx.Dir).CombinedOutput(); err != nil {
985
-		return nil, fmt.Errorf("error trying to init repo: %s (%s)", err, output)
986
-	}
987
-	err = os.Chdir(ctx.Dir)
988
-	if err != nil {
989
-		return nil, err
990
-	}
991
-	if output, err := exec.Command("git", "config", "user.name", "Fake User").CombinedOutput(); err != nil {
992
-		return nil, fmt.Errorf("error trying to set 'user.name': %s (%s)", err, output)
993
-	}
994
-	if output, err := exec.Command("git", "config", "user.email", "fake.user@example.com").CombinedOutput(); err != nil {
995
-		return nil, fmt.Errorf("error trying to set 'user.email': %s (%s)", err, output)
996
-	}
997
-	if output, err := exec.Command("git", "add", "*").CombinedOutput(); err != nil {
998
-		return nil, fmt.Errorf("error trying to add files to repo: %s (%s)", err, output)
999
-	}
1000
-	if output, err := exec.Command("git", "commit", "-a", "-m", "Initial commit").CombinedOutput(); err != nil {
1001
-		return nil, fmt.Errorf("error trying to commit to repo: %s (%s)", err, output)
1002
-	}
1003
-
1004
-	root, err := ioutil.TempDir("", "docker-test-git-repo")
1005
-	if err != nil {
1006
-		return nil, err
1007
-	}
1008
-	repoPath := filepath.Join(root, name+".git")
1009
-	if output, err := exec.Command("git", "clone", "--bare", ctx.Dir, repoPath).CombinedOutput(); err != nil {
1010
-		os.RemoveAll(root)
1011
-		return nil, fmt.Errorf("error trying to clone --bare: %s (%s)", err, output)
1012
-	}
1013
-	err = os.Chdir(repoPath)
1014
-	if err != nil {
1015
-		os.RemoveAll(root)
1016
-		return nil, err
1017
-	}
1018
-	if output, err := exec.Command("git", "update-server-info").CombinedOutput(); err != nil {
1019
-		os.RemoveAll(root)
1020
-		return nil, fmt.Errorf("error trying to git update-server-info: %s (%s)", err, output)
1021
-	}
1022
-	err = os.Chdir(curdir)
1023
-	if err != nil {
1024
-		os.RemoveAll(root)
1025
-		return nil, err
1026
-	}
1027
-
1028
-	var server gitServer
1029
-	if !enforceLocalServer {
1030
-		// use fakeStorage server, which might be local or remote (at test daemon)
1031
-		server, err = fakeStorageWithContext(fakeContextFromDir(root))
1032
-		if err != nil {
1033
-			return nil, fmt.Errorf("cannot start fake storage: %v", err)
1034
-		}
1035
-	} else {
1036
-		// always start a local http server on CLI test machine
1037
-		httpServer := httptest.NewServer(http.FileServer(http.Dir(root)))
1038
-		server = &localGitServer{httpServer}
1039
-	}
1040
-	return &fakeGit{
1041
-		root:    root,
1042
-		server:  server,
1043
-		RepoURL: fmt.Sprintf("%s/%s.git", server.URL(), name),
1044
-	}, nil
1045
-}
1046
-
1047
-// Write `content` to the file at path `dst`, creating it if necessary,
1048
-// as well as any missing directories.
1049
-// The file is truncated if it already exists.
1050
-// Fail the test when error occurs.
1051
-func writeFile(dst, content string, c *check.C) {
1052
-	// Create subdirectories if necessary
1053
-	c.Assert(os.MkdirAll(path.Dir(dst), 0700), check.IsNil)
1054
-	f, err := os.OpenFile(dst, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0700)
1055
-	c.Assert(err, check.IsNil)
1056
-	defer f.Close()
1057
-	// Write content (truncate if it exists)
1058
-	_, err = io.Copy(f, strings.NewReader(content))
1059
-	c.Assert(err, check.IsNil)
1060
-}
1061
-
1062
-// Return the contents of file at path `src`.
1063
-// Fail the test when error occurs.
1064
-func readFile(src string, c *check.C) (content string) {
1065
-	data, err := ioutil.ReadFile(src)
1066
-	c.Assert(err, check.IsNil)
1067
-
1068
-	return string(data)
1069
-}
1070
-
1071
-func containerStorageFile(containerID, basename string) string {
1072
-	return filepath.Join(containerStoragePath, containerID, basename)
1073
-}
1074
-
1075
-// docker commands that use this function must be run with the '-d' switch.
1076
-func runCommandAndReadContainerFile(filename string, cmd *exec.Cmd) ([]byte, error) {
1077
-	out, _, err := runCommandWithOutput(cmd)
1078
-	if err != nil {
1079
-		return nil, fmt.Errorf("%v: %q", err, out)
1080
-	}
1081
-
1082
-	contID := strings.TrimSpace(out)
1083
-
1084
-	if err := waitRun(contID); err != nil {
1085
-		return nil, fmt.Errorf("%v: %q", contID, err)
1086
-	}
1087
-
1088
-	return readContainerFile(contID, filename)
1089
-}
1090
-
1091
-func readContainerFile(containerID, filename string) ([]byte, error) {
1092
-	f, err := os.Open(containerStorageFile(containerID, filename))
1093
-	if err != nil {
1094
-		return nil, err
1095
-	}
1096
-	defer f.Close()
1097
-
1098
-	content, err := ioutil.ReadAll(f)
1099
-	if err != nil {
1100
-		return nil, err
1101
-	}
1102
-
1103
-	return content, nil
1104
-}
1105
-
1106
-func readContainerFileWithExec(containerID, filename string) ([]byte, error) {
1107
-	out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "exec", containerID, "cat", filename))
1108
-	return []byte(out), err
1109
-}
1110
-
1111
-// daemonTime provides the current time on the daemon host
1112
-func daemonTime(c *check.C) time.Time {
1113
-	if isLocalDaemon {
1114
-		return time.Now()
1115
-	}
1116
-
1117
-	status, body, err := sockRequest("GET", "/info", nil)
1118
-	c.Assert(err, check.IsNil)
1119
-	c.Assert(status, check.Equals, http.StatusOK)
1120
-
1121
-	type infoJSON struct {
1122
-		SystemTime string
1123
-	}
1124
-	var info infoJSON
1125
-	err = json.Unmarshal(body, &info)
1126
-	c.Assert(err, check.IsNil, check.Commentf("unable to unmarshal GET /info response"))
1127
-
1128
-	dt, err := time.Parse(time.RFC3339Nano, info.SystemTime)
1129
-	c.Assert(err, check.IsNil, check.Commentf("invalid time format in GET /info response"))
1130
-	return dt
1131
-}
1132
-
1133
-// daemonUnixTime returns the current time on the daemon host with nanoseconds precision.
1134
-// It return the time formatted how the client sends timestamps to the server.
1135
-func daemonUnixTime(c *check.C) string {
1136
-	return parseEventTime(daemonTime(c))
1137
-}
1138
-
1139
-func parseEventTime(t time.Time) string {
1140
-	return fmt.Sprintf("%d.%09d", t.Unix(), int64(t.Nanosecond()))
1141
-}
1142
-
1143
-func setupRegistry(c *check.C, schema1 bool, auth, tokenURL string) *testRegistryV2 {
1144
-	reg, err := newTestRegistryV2(c, schema1, auth, tokenURL)
1145
-	c.Assert(err, check.IsNil)
1146
-
1147
-	// Wait for registry to be ready to serve requests.
1148
-	for i := 0; i != 50; i++ {
1149
-		if err = reg.Ping(); err == nil {
1150
-			break
1151
-		}
1152
-		time.Sleep(100 * time.Millisecond)
1153
-	}
1154
-
1155
-	c.Assert(err, check.IsNil, check.Commentf("Timeout waiting for test registry to become available: %v", err))
1156
-	return reg
1157
-}
1158
-
1159
-func setupNotary(c *check.C) *testNotary {
1160
-	ts, err := newTestNotary(c)
1161
-	c.Assert(err, check.IsNil)
1162
-
1163
-	return ts
1164
-}
1165
-
1166
-// appendBaseEnv appends the minimum set of environment variables to exec the
1167
-// docker cli binary for testing with correct configuration to the given env
1168
-// list.
1169
-func appendBaseEnv(isTLS bool, env ...string) []string {
1170
-	preserveList := []string{
1171
-		// preserve remote test host
1172
-		"DOCKER_HOST",
1173
-
1174
-		// windows: requires preserving SystemRoot, otherwise dial tcp fails
1175
-		// with "GetAddrInfoW: A non-recoverable error occurred during a database lookup."
1176
-		"SystemRoot",
1177
-
1178
-		// testing help text requires the $PATH to dockerd is set
1179
-		"PATH",
1180
-	}
1181
-	if isTLS {
1182
-		preserveList = append(preserveList, "DOCKER_TLS_VERIFY", "DOCKER_CERT_PATH")
1183
-	}
1184
-
1185
-	for _, key := range preserveList {
1186
-		if val := os.Getenv(key); val != "" {
1187
-			env = append(env, fmt.Sprintf("%s=%s", key, val))
1188
-		}
1189
-	}
1190
-	return env
1191
-}
1192
-
1193
-func createTmpFile(c *check.C, content string) string {
1194
-	f, err := ioutil.TempFile("", "testfile")
1195
-	c.Assert(err, check.IsNil)
1196
-
1197
-	filename := f.Name()
1198
-
1199
-	err = ioutil.WriteFile(filename, []byte(content), 0644)
1200
-	c.Assert(err, check.IsNil)
1201
-
1202
-	return filename
1203
-}
1204
-
1205
-func waitForContainer(contID string, args ...string) error {
1206
-	args = append([]string{dockerBinary, "run", "--name", contID}, args...)
1207
-	result := icmd.RunCmd(icmd.Cmd{Command: args})
1208
-	if result.Error != nil {
1209
-		return result.Error
1210
-	}
1211
-	return waitRun(contID)
1212
-}
1213
-
1214
-// waitRestart will wait for the specified container to restart once
1215
-func waitRestart(contID string, duration time.Duration) error {
1216
-	return waitInspect(contID, "{{.RestartCount}}", "1", duration)
1217
-}
1218
-
1219
-// waitRun will wait for the specified container to be running, maximum 5 seconds.
1220
-func waitRun(contID string) error {
1221
-	return waitInspect(contID, "{{.State.Running}}", "true", 5*time.Second)
1222
-}
1223
-
1224
-// waitExited will wait for the specified container to state exit, subject
1225
-// to a maximum time limit in seconds supplied by the caller
1226
-func waitExited(contID string, duration time.Duration) error {
1227
-	return waitInspect(contID, "{{.State.Status}}", "exited", duration)
1228
-}
1229
-
1230
-// waitInspect will wait for the specified container to have the specified string
1231
-// in the inspect output. It will wait until the specified timeout (in seconds)
1232
-// is reached.
1233
-func waitInspect(name, expr, expected string, timeout time.Duration) error {
1234
-	return waitInspectWithArgs(name, expr, expected, timeout)
1235
-}
1236
-
1237
-func waitInspectWithArgs(name, expr, expected string, timeout time.Duration, arg ...string) error {
1238
-	return daemon.WaitInspectWithArgs(dockerBinary, name, expr, expected, timeout, arg...)
1239
-}
1240
-
1241
-func getInspectBody(c *check.C, version, id string) []byte {
1242
-	endpoint := fmt.Sprintf("/%s/containers/%s/json", version, id)
1243
-	status, body, err := sockRequest("GET", endpoint, nil)
1244
-	c.Assert(err, check.IsNil)
1245
-	c.Assert(status, check.Equals, http.StatusOK)
1246
-	return body
1247
-}
1248
-
1249
-// Run a long running idle task in a background container using the
1250
-// system-specific default image and command.
1251
-func runSleepingContainer(c *check.C, extraArgs ...string) (string, int) {
1252
-	return runSleepingContainerInImage(c, defaultSleepImage, extraArgs...)
1253
-}
1254
-
1255
-// Run a long running idle task in a background container using the specified
1256
-// image and the system-specific command.
1257
-func runSleepingContainerInImage(c *check.C, image string, extraArgs ...string) (string, int) {
1258
-	args := []string{"run", "-d"}
1259
-	args = append(args, extraArgs...)
1260
-	args = append(args, image)
1261
-	args = append(args, sleepCommandForDaemonPlatform()...)
1262
-	return dockerCmd(c, args...)
1263
-}
1264
-
1265
-// minimalBaseImage returns the name of the minimal base image for the current
1266
-// daemon platform.
1267
-func minimalBaseImage() string {
1268
-	if daemonPlatform == "windows" {
1269
-		return WindowsBaseImage
1270
-	}
1271
-	return "scratch"
1272
-}
1273
-
1274
-func getGoroutineNumber() (int, error) {
1275
-	i := struct {
1276
-		NGoroutines int
1277
-	}{}
1278
-	status, b, err := sockRequest("GET", "/info", nil)
1279
-	if err != nil {
1280
-		return 0, err
1281
-	}
1282
-	if status != http.StatusOK {
1283
-		return 0, fmt.Errorf("http status code: %d", status)
1284
-	}
1285
-	if err := json.Unmarshal(b, &i); err != nil {
1286
-		return 0, err
1287
-	}
1288
-	return i.NGoroutines, nil
1289
-}
1290
-
1291
-func waitForGoroutines(expected int) error {
1292
-	t := time.After(30 * time.Second)
1293
-	for {
1294
-		select {
1295
-		case <-t:
1296
-			n, err := getGoroutineNumber()
1297
-			if err != nil {
1298
-				return err
1299
-			}
1300
-			if n > expected {
1301
-				return fmt.Errorf("leaked goroutines: expected less than or equal to %d, got: %d", expected, n)
1302
-			}
1303
-		default:
1304
-			n, err := getGoroutineNumber()
1305
-			if err != nil {
1306
-				return err
1307
-			}
1308
-			if n <= expected {
1309
-				return nil
1310
-			}
1311
-			time.Sleep(200 * time.Millisecond)
1312
-		}
1313
-	}
1314
-}
1315
-
1316
-// getErrorMessage returns the error message from an error API response
1317
-func getErrorMessage(c *check.C, body []byte) string {
1318
-	var resp types.ErrorResponse
1319
-	c.Assert(json.Unmarshal(body, &resp), check.IsNil)
1320
-	return strings.TrimSpace(resp.Message)
1321
-}
1322
-
1323
-func waitAndAssert(c *check.C, timeout time.Duration, f checkF, checker check.Checker, args ...interface{}) {
1324
-	after := time.After(timeout)
1325
-	for {
1326
-		v, comment := f(c)
1327
-		assert, _ := checker.Check(append([]interface{}{v}, args...), checker.Info().Params)
1328
-		select {
1329
-		case <-after:
1330
-			assert = true
1331
-		default:
1332
-		}
1333
-		if assert {
1334
-			if comment != nil {
1335
-				args = append(args, comment)
1336
-			}
1337
-			c.Assert(v, checker, args...)
1338
-			return
1339
-		}
1340
-		time.Sleep(100 * time.Millisecond)
1341
-	}
1342
-}
1343
-
1344
-type checkF func(*check.C) (interface{}, check.CommentInterface)
1345
-type reducer func(...interface{}) interface{}
1346
-
1347
-func reducedCheck(r reducer, funcs ...checkF) checkF {
1348
-	return func(c *check.C) (interface{}, check.CommentInterface) {
1349
-		var values []interface{}
1350
-		var comments []string
1351
-		for _, f := range funcs {
1352
-			v, comment := f(c)
1353
-			values = append(values, v)
1354
-			if comment != nil {
1355
-				comments = append(comments, comment.CheckCommentString())
1356
-			}
1357
-		}
1358
-		return r(values...), check.Commentf("%v", strings.Join(comments, ", "))
1359
-	}
1360
-}
1361
-
1362
-func sumAsIntegers(vals ...interface{}) interface{} {
1363
-	var s int
1364
-	for _, v := range vals {
1365
-		s += v.(int)
1366
-	}
1367
-	return s
1368
-}
1369 1
new file mode 100644
... ...
@@ -0,0 +1,1308 @@
0
+package main
1
+
2
+import (
3
+	"bufio"
4
+	"bytes"
5
+	"encoding/json"
6
+	"errors"
7
+	"fmt"
8
+	"io"
9
+	"io/ioutil"
10
+	"net"
11
+	"net/http"
12
+	"net/http/httptest"
13
+	"net/http/httputil"
14
+	"net/url"
15
+	"os"
16
+	"os/exec"
17
+	"path"
18
+	"path/filepath"
19
+	"strconv"
20
+	"strings"
21
+	"time"
22
+
23
+	"github.com/docker/docker/api/types"
24
+	volumetypes "github.com/docker/docker/api/types/volume"
25
+	"github.com/docker/docker/integration-cli/daemon"
26
+	"github.com/docker/docker/opts"
27
+	"github.com/docker/docker/pkg/integration"
28
+	"github.com/docker/docker/pkg/integration/checker"
29
+	icmd "github.com/docker/docker/pkg/integration/cmd"
30
+	"github.com/docker/docker/pkg/ioutils"
31
+	"github.com/docker/docker/pkg/stringutils"
32
+	"github.com/go-check/check"
33
+)
34
+
35
+func daemonHost() string {
36
+	daemonURLStr := "unix://" + opts.DefaultUnixSocket
37
+	if daemonHostVar := os.Getenv("DOCKER_HOST"); daemonHostVar != "" {
38
+		daemonURLStr = daemonHostVar
39
+	}
40
+	return daemonURLStr
41
+}
42
+
43
+// FIXME(vdemeester) should probably completely move to daemon struct/methods
44
+func sockConn(timeout time.Duration, daemonStr string) (net.Conn, error) {
45
+	if daemonStr == "" {
46
+		daemonStr = daemonHost()
47
+	}
48
+	return daemon.SockConn(timeout, daemonStr)
49
+}
50
+
51
+func sockRequest(method, endpoint string, data interface{}) (int, []byte, error) {
52
+	jsonData := bytes.NewBuffer(nil)
53
+	if err := json.NewEncoder(jsonData).Encode(data); err != nil {
54
+		return -1, nil, err
55
+	}
56
+
57
+	res, body, err := sockRequestRaw(method, endpoint, jsonData, "application/json")
58
+	if err != nil {
59
+		return -1, nil, err
60
+	}
61
+	b, err := integration.ReadBody(body)
62
+	return res.StatusCode, b, err
63
+}
64
+
65
+func sockRequestRaw(method, endpoint string, data io.Reader, ct string) (*http.Response, io.ReadCloser, error) {
66
+	return sockRequestRawToDaemon(method, endpoint, data, ct, "")
67
+}
68
+
69
+func sockRequestRawToDaemon(method, endpoint string, data io.Reader, ct, daemon string) (*http.Response, io.ReadCloser, error) {
70
+	req, client, err := newRequestClient(method, endpoint, data, ct, daemon)
71
+	if err != nil {
72
+		return nil, nil, err
73
+	}
74
+
75
+	resp, err := client.Do(req)
76
+	if err != nil {
77
+		client.Close()
78
+		return nil, nil, err
79
+	}
80
+	body := ioutils.NewReadCloserWrapper(resp.Body, func() error {
81
+		defer resp.Body.Close()
82
+		return client.Close()
83
+	})
84
+
85
+	return resp, body, nil
86
+}
87
+
88
+func sockRequestHijack(method, endpoint string, data io.Reader, ct string) (net.Conn, *bufio.Reader, error) {
89
+	req, client, err := newRequestClient(method, endpoint, data, ct, "")
90
+	if err != nil {
91
+		return nil, nil, err
92
+	}
93
+
94
+	client.Do(req)
95
+	conn, br := client.Hijack()
96
+	return conn, br, nil
97
+}
98
+
99
+func newRequestClient(method, endpoint string, data io.Reader, ct, daemon string) (*http.Request, *httputil.ClientConn, error) {
100
+	c, err := sockConn(time.Duration(10*time.Second), daemon)
101
+	if err != nil {
102
+		return nil, nil, fmt.Errorf("could not dial docker daemon: %v", err)
103
+	}
104
+
105
+	client := httputil.NewClientConn(c, nil)
106
+
107
+	req, err := http.NewRequest(method, endpoint, data)
108
+	if err != nil {
109
+		client.Close()
110
+		return nil, nil, fmt.Errorf("could not create new request: %v", err)
111
+	}
112
+
113
+	if ct != "" {
114
+		req.Header.Set("Content-Type", ct)
115
+	}
116
+	return req, client, nil
117
+}
118
+
119
+func deleteContainer(container ...string) error {
120
+	result := icmd.RunCommand(dockerBinary, append([]string{"rm", "-fv"}, container...)...)
121
+	return result.Compare(icmd.Success)
122
+}
123
+
124
+func getAllContainers() (string, error) {
125
+	getContainersCmd := exec.Command(dockerBinary, "ps", "-q", "-a")
126
+	out, exitCode, err := runCommandWithOutput(getContainersCmd)
127
+	if exitCode != 0 && err == nil {
128
+		err = fmt.Errorf("failed to get a list of containers: %v\n", out)
129
+	}
130
+
131
+	return out, err
132
+}
133
+
134
+func deleteAllContainers(c *check.C) {
135
+	containers, err := getAllContainers()
136
+	c.Assert(err, checker.IsNil, check.Commentf("containers: %v", containers))
137
+
138
+	if containers != "" {
139
+		err = deleteContainer(strings.Split(strings.TrimSpace(containers), "\n")...)
140
+		c.Assert(err, checker.IsNil)
141
+	}
142
+}
143
+
144
+func deleteAllNetworks(c *check.C) {
145
+	networks, err := getAllNetworks()
146
+	c.Assert(err, check.IsNil)
147
+	var errs []string
148
+	for _, n := range networks {
149
+		if n.Name == "bridge" || n.Name == "none" || n.Name == "host" {
150
+			continue
151
+		}
152
+		if daemonPlatform == "windows" && strings.ToLower(n.Name) == "nat" {
153
+			// nat is a pre-defined network on Windows and cannot be removed
154
+			continue
155
+		}
156
+		status, b, err := sockRequest("DELETE", "/networks/"+n.Name, nil)
157
+		if err != nil {
158
+			errs = append(errs, err.Error())
159
+			continue
160
+		}
161
+		if status != http.StatusNoContent {
162
+			errs = append(errs, fmt.Sprintf("error deleting network %s: %s", n.Name, string(b)))
163
+		}
164
+	}
165
+	c.Assert(errs, checker.HasLen, 0, check.Commentf(strings.Join(errs, "\n")))
166
+}
167
+
168
+func getAllNetworks() ([]types.NetworkResource, error) {
169
+	var networks []types.NetworkResource
170
+	_, b, err := sockRequest("GET", "/networks", nil)
171
+	if err != nil {
172
+		return nil, err
173
+	}
174
+	if err := json.Unmarshal(b, &networks); err != nil {
175
+		return nil, err
176
+	}
177
+	return networks, nil
178
+}
179
+
180
+func deleteAllPlugins(c *check.C) {
181
+	plugins, err := getAllPlugins()
182
+	c.Assert(err, checker.IsNil)
183
+	var errs []string
184
+	for _, p := range plugins {
185
+		pluginName := p.Name
186
+		status, b, err := sockRequest("DELETE", "/plugins/"+pluginName+"?force=1", nil)
187
+		if err != nil {
188
+			errs = append(errs, err.Error())
189
+			continue
190
+		}
191
+		if status != http.StatusOK {
192
+			errs = append(errs, fmt.Sprintf("error deleting plugin %s: %s", p.Name, string(b)))
193
+		}
194
+	}
195
+	c.Assert(errs, checker.HasLen, 0, check.Commentf(strings.Join(errs, "\n")))
196
+}
197
+
198
+func getAllPlugins() (types.PluginsListResponse, error) {
199
+	var plugins types.PluginsListResponse
200
+	_, b, err := sockRequest("GET", "/plugins", nil)
201
+	if err != nil {
202
+		return nil, err
203
+	}
204
+	if err := json.Unmarshal(b, &plugins); err != nil {
205
+		return nil, err
206
+	}
207
+	return plugins, nil
208
+}
209
+
210
+func deleteAllVolumes(c *check.C) {
211
+	volumes, err := getAllVolumes()
212
+	c.Assert(err, checker.IsNil)
213
+	var errs []string
214
+	for _, v := range volumes {
215
+		status, b, err := sockRequest("DELETE", "/volumes/"+v.Name, nil)
216
+		if err != nil {
217
+			errs = append(errs, err.Error())
218
+			continue
219
+		}
220
+		if status != http.StatusNoContent {
221
+			errs = append(errs, fmt.Sprintf("error deleting volume %s: %s", v.Name, string(b)))
222
+		}
223
+	}
224
+	c.Assert(errs, checker.HasLen, 0, check.Commentf(strings.Join(errs, "\n")))
225
+}
226
+
227
+func getAllVolumes() ([]*types.Volume, error) {
228
+	var volumes volumetypes.VolumesListOKBody
229
+	_, b, err := sockRequest("GET", "/volumes", nil)
230
+	if err != nil {
231
+		return nil, err
232
+	}
233
+	if err := json.Unmarshal(b, &volumes); err != nil {
234
+		return nil, err
235
+	}
236
+	return volumes.Volumes, nil
237
+}
238
+
239
+func deleteAllImages(c *check.C) {
240
+	cmd := exec.Command(dockerBinary, "images", "--digests")
241
+	cmd.Env = appendBaseEnv(true)
242
+	out, err := cmd.CombinedOutput()
243
+	c.Assert(err, checker.IsNil)
244
+	lines := strings.Split(string(out), "\n")[1:]
245
+	imgMap := map[string]struct{}{}
246
+	for _, l := range lines {
247
+		if l == "" {
248
+			continue
249
+		}
250
+		fields := strings.Fields(l)
251
+		imgTag := fields[0] + ":" + fields[1]
252
+		if _, ok := protectedImages[imgTag]; !ok {
253
+			if fields[0] == "<none>" || fields[1] == "<none>" {
254
+				if fields[2] != "<none>" {
255
+					imgMap[fields[0]+"@"+fields[2]] = struct{}{}
256
+				} else {
257
+					imgMap[fields[3]] = struct{}{}
258
+				}
259
+				// continue
260
+			} else {
261
+				imgMap[imgTag] = struct{}{}
262
+			}
263
+		}
264
+	}
265
+	if len(imgMap) != 0 {
266
+		imgs := make([]string, 0, len(imgMap))
267
+		for k := range imgMap {
268
+			imgs = append(imgs, k)
269
+		}
270
+		dockerCmd(c, append([]string{"rmi", "-f"}, imgs...)...)
271
+	}
272
+}
273
+
274
+func getPausedContainers() ([]string, error) {
275
+	getPausedContainersCmd := exec.Command(dockerBinary, "ps", "-f", "status=paused", "-q", "-a")
276
+	out, exitCode, err := runCommandWithOutput(getPausedContainersCmd)
277
+	if exitCode != 0 && err == nil {
278
+		err = fmt.Errorf("failed to get a list of paused containers: %v\n", out)
279
+	}
280
+	if err != nil {
281
+		return nil, err
282
+	}
283
+
284
+	return strings.Fields(out), nil
285
+}
286
+
287
+func unpauseContainer(c *check.C, container string) {
288
+	dockerCmd(c, "unpause", container)
289
+}
290
+
291
+func unpauseAllContainers(c *check.C) {
292
+	containers, err := getPausedContainers()
293
+	c.Assert(err, checker.IsNil, check.Commentf("containers: %v", containers))
294
+	for _, value := range containers {
295
+		unpauseContainer(c, value)
296
+	}
297
+}
298
+
299
+func deleteImages(images ...string) error {
300
+	args := []string{dockerBinary, "rmi", "-f"}
301
+	return icmd.RunCmd(icmd.Cmd{Command: append(args, images...)}).Error
302
+}
303
+
304
+func dockerCmdWithError(args ...string) (string, int, error) {
305
+	if err := validateArgs(args...); err != nil {
306
+		return "", 0, err
307
+	}
308
+	result := icmd.RunCommand(dockerBinary, args...)
309
+	if result.Error != nil {
310
+		return result.Combined(), result.ExitCode, result.Compare(icmd.Success)
311
+	}
312
+	return result.Combined(), result.ExitCode, result.Error
313
+}
314
+
315
+func dockerCmdWithStdoutStderr(c *check.C, args ...string) (string, string, int) {
316
+	if err := validateArgs(args...); err != nil {
317
+		c.Fatalf(err.Error())
318
+	}
319
+
320
+	result := icmd.RunCommand(dockerBinary, args...)
321
+	c.Assert(result, icmd.Matches, icmd.Success)
322
+	return result.Stdout(), result.Stderr(), result.ExitCode
323
+}
324
+
325
+func dockerCmd(c *check.C, args ...string) (string, int) {
326
+	if err := validateArgs(args...); err != nil {
327
+		c.Fatalf(err.Error())
328
+	}
329
+	result := icmd.RunCommand(dockerBinary, args...)
330
+	c.Assert(result, icmd.Matches, icmd.Success)
331
+	return result.Combined(), result.ExitCode
332
+}
333
+
334
+func dockerCmdWithResult(args ...string) *icmd.Result {
335
+	return icmd.RunCommand(dockerBinary, args...)
336
+}
337
+
338
+func binaryWithArgs(args ...string) []string {
339
+	return append([]string{dockerBinary}, args...)
340
+}
341
+
342
+// execute a docker command with a timeout
343
+func dockerCmdWithTimeout(timeout time.Duration, args ...string) *icmd.Result {
344
+	if err := validateArgs(args...); err != nil {
345
+		return &icmd.Result{Error: err}
346
+	}
347
+	return icmd.RunCmd(icmd.Cmd{Command: binaryWithArgs(args...), Timeout: timeout})
348
+}
349
+
350
+// execute a docker command in a directory
351
+func dockerCmdInDir(c *check.C, path string, args ...string) (string, int, error) {
352
+	if err := validateArgs(args...); err != nil {
353
+		c.Fatalf(err.Error())
354
+	}
355
+	result := icmd.RunCmd(icmd.Cmd{Command: binaryWithArgs(args...), Dir: path})
356
+	return result.Combined(), result.ExitCode, result.Error
357
+}
358
+
359
+// validateArgs is a checker to ensure tests are not running commands which are
360
+// not supported on platforms. Specifically on Windows this is 'busybox top'.
361
+func validateArgs(args ...string) error {
362
+	if daemonPlatform != "windows" {
363
+		return nil
364
+	}
365
+	foundBusybox := -1
366
+	for key, value := range args {
367
+		if strings.ToLower(value) == "busybox" {
368
+			foundBusybox = key
369
+		}
370
+		if (foundBusybox != -1) && (key == foundBusybox+1) && (strings.ToLower(value) == "top") {
371
+			return errors.New("cannot use 'busybox top' in tests on Windows. Use runSleepingContainer()")
372
+		}
373
+	}
374
+	return nil
375
+}
376
+
377
+// find the State.ExitCode in container metadata
378
+func findContainerExitCode(c *check.C, name string, vargs ...string) string {
379
+	args := append(vargs, "inspect", "--format='{{ .State.ExitCode }} {{ .State.Error }}'", name)
380
+	cmd := exec.Command(dockerBinary, args...)
381
+	out, _, err := runCommandWithOutput(cmd)
382
+	if err != nil {
383
+		c.Fatal(err, out)
384
+	}
385
+	return out
386
+}
387
+
388
+func findContainerIP(c *check.C, id string, network string) string {
389
+	out, _ := dockerCmd(c, "inspect", fmt.Sprintf("--format='{{ .NetworkSettings.Networks.%s.IPAddress }}'", network), id)
390
+	return strings.Trim(out, " \r\n'")
391
+}
392
+
393
+func getContainerCount() (int, error) {
394
+	const containers = "Containers:"
395
+
396
+	cmd := exec.Command(dockerBinary, "info")
397
+	out, _, err := runCommandWithOutput(cmd)
398
+	if err != nil {
399
+		return 0, err
400
+	}
401
+
402
+	lines := strings.Split(out, "\n")
403
+	for _, line := range lines {
404
+		if strings.Contains(line, containers) {
405
+			output := strings.TrimSpace(line)
406
+			output = strings.TrimLeft(output, containers)
407
+			output = strings.Trim(output, " ")
408
+			containerCount, err := strconv.Atoi(output)
409
+			if err != nil {
410
+				return 0, err
411
+			}
412
+			return containerCount, nil
413
+		}
414
+	}
415
+	return 0, fmt.Errorf("couldn't find the Container count in the output")
416
+}
417
+
418
+// FakeContext creates directories that can be used as a build context
419
+type FakeContext struct {
420
+	Dir string
421
+}
422
+
423
+// Add a file at a path, creating directories where necessary
424
+func (f *FakeContext) Add(file, content string) error {
425
+	return f.addFile(file, []byte(content))
426
+}
427
+
428
+func (f *FakeContext) addFile(file string, content []byte) error {
429
+	fp := filepath.Join(f.Dir, filepath.FromSlash(file))
430
+	dirpath := filepath.Dir(fp)
431
+	if dirpath != "." {
432
+		if err := os.MkdirAll(dirpath, 0755); err != nil {
433
+			return err
434
+		}
435
+	}
436
+	return ioutil.WriteFile(fp, content, 0644)
437
+
438
+}
439
+
440
+// Delete a file at a path
441
+func (f *FakeContext) Delete(file string) error {
442
+	fp := filepath.Join(f.Dir, filepath.FromSlash(file))
443
+	return os.RemoveAll(fp)
444
+}
445
+
446
+// Close deletes the context
447
+func (f *FakeContext) Close() error {
448
+	return os.RemoveAll(f.Dir)
449
+}
450
+
451
+func fakeContextFromNewTempDir() (*FakeContext, error) {
452
+	tmp, err := ioutil.TempDir("", "fake-context")
453
+	if err != nil {
454
+		return nil, err
455
+	}
456
+	if err := os.Chmod(tmp, 0755); err != nil {
457
+		return nil, err
458
+	}
459
+	return fakeContextFromDir(tmp), nil
460
+}
461
+
462
+func fakeContextFromDir(dir string) *FakeContext {
463
+	return &FakeContext{dir}
464
+}
465
+
466
+func fakeContextWithFiles(files map[string]string) (*FakeContext, error) {
467
+	ctx, err := fakeContextFromNewTempDir()
468
+	if err != nil {
469
+		return nil, err
470
+	}
471
+	for file, content := range files {
472
+		if err := ctx.Add(file, content); err != nil {
473
+			ctx.Close()
474
+			return nil, err
475
+		}
476
+	}
477
+	return ctx, nil
478
+}
479
+
480
+func fakeContextAddDockerfile(ctx *FakeContext, dockerfile string) error {
481
+	if err := ctx.Add("Dockerfile", dockerfile); err != nil {
482
+		ctx.Close()
483
+		return err
484
+	}
485
+	return nil
486
+}
487
+
488
+func fakeContext(dockerfile string, files map[string]string) (*FakeContext, error) {
489
+	ctx, err := fakeContextWithFiles(files)
490
+	if err != nil {
491
+		return nil, err
492
+	}
493
+	if err := fakeContextAddDockerfile(ctx, dockerfile); err != nil {
494
+		return nil, err
495
+	}
496
+	return ctx, nil
497
+}
498
+
499
+// FakeStorage is a static file server. It might be running locally or remotely
500
+// on test host.
501
+type FakeStorage interface {
502
+	Close() error
503
+	URL() string
504
+	CtxDir() string
505
+}
506
+
507
+func fakeBinaryStorage(archives map[string]*bytes.Buffer) (FakeStorage, error) {
508
+	ctx, err := fakeContextFromNewTempDir()
509
+	if err != nil {
510
+		return nil, err
511
+	}
512
+	for name, content := range archives {
513
+		if err := ctx.addFile(name, content.Bytes()); err != nil {
514
+			return nil, err
515
+		}
516
+	}
517
+	return fakeStorageWithContext(ctx)
518
+}
519
+
520
+// fakeStorage returns either a local or remote (at daemon machine) file server
521
+func fakeStorage(files map[string]string) (FakeStorage, error) {
522
+	ctx, err := fakeContextWithFiles(files)
523
+	if err != nil {
524
+		return nil, err
525
+	}
526
+	return fakeStorageWithContext(ctx)
527
+}
528
+
529
+// fakeStorageWithContext returns either a local or remote (at daemon machine) file server
530
+func fakeStorageWithContext(ctx *FakeContext) (FakeStorage, error) {
531
+	if isLocalDaemon {
532
+		return newLocalFakeStorage(ctx)
533
+	}
534
+	return newRemoteFileServer(ctx)
535
+}
536
+
537
+// localFileStorage is a file storage on the running machine
538
+type localFileStorage struct {
539
+	*FakeContext
540
+	*httptest.Server
541
+}
542
+
543
+func (s *localFileStorage) URL() string {
544
+	return s.Server.URL
545
+}
546
+
547
+func (s *localFileStorage) CtxDir() string {
548
+	return s.FakeContext.Dir
549
+}
550
+
551
+func (s *localFileStorage) Close() error {
552
+	defer s.Server.Close()
553
+	return s.FakeContext.Close()
554
+}
555
+
556
+func newLocalFakeStorage(ctx *FakeContext) (*localFileStorage, error) {
557
+	handler := http.FileServer(http.Dir(ctx.Dir))
558
+	server := httptest.NewServer(handler)
559
+	return &localFileStorage{
560
+		FakeContext: ctx,
561
+		Server:      server,
562
+	}, nil
563
+}
564
+
565
+// remoteFileServer is a containerized static file server started on the remote
566
+// testing machine to be used in URL-accepting docker build functionality.
567
+type remoteFileServer struct {
568
+	host      string // hostname/port web server is listening to on docker host e.g. 0.0.0.0:43712
569
+	container string
570
+	image     string
571
+	ctx       *FakeContext
572
+}
573
+
574
+func (f *remoteFileServer) URL() string {
575
+	u := url.URL{
576
+		Scheme: "http",
577
+		Host:   f.host}
578
+	return u.String()
579
+}
580
+
581
+func (f *remoteFileServer) CtxDir() string {
582
+	return f.ctx.Dir
583
+}
584
+
585
+func (f *remoteFileServer) Close() error {
586
+	defer func() {
587
+		if f.ctx != nil {
588
+			f.ctx.Close()
589
+		}
590
+		if f.image != "" {
591
+			deleteImages(f.image)
592
+		}
593
+	}()
594
+	if f.container == "" {
595
+		return nil
596
+	}
597
+	return deleteContainer(f.container)
598
+}
599
+
600
+func newRemoteFileServer(ctx *FakeContext) (*remoteFileServer, error) {
601
+	var (
602
+		image     = fmt.Sprintf("fileserver-img-%s", strings.ToLower(stringutils.GenerateRandomAlphaOnlyString(10)))
603
+		container = fmt.Sprintf("fileserver-cnt-%s", strings.ToLower(stringutils.GenerateRandomAlphaOnlyString(10)))
604
+	)
605
+
606
+	if err := ensureHTTPServerImage(); err != nil {
607
+		return nil, err
608
+	}
609
+
610
+	// Build the image
611
+	if err := fakeContextAddDockerfile(ctx, `FROM httpserver
612
+COPY . /static`); err != nil {
613
+		return nil, fmt.Errorf("Cannot add Dockerfile to context: %v", err)
614
+	}
615
+	if _, err := buildImageFromContext(image, ctx, false); err != nil {
616
+		return nil, fmt.Errorf("failed building file storage container image: %v", err)
617
+	}
618
+
619
+	// Start the container
620
+	runCmd := exec.Command(dockerBinary, "run", "-d", "-P", "--name", container, image)
621
+	if out, ec, err := runCommandWithOutput(runCmd); err != nil {
622
+		return nil, fmt.Errorf("failed to start file storage container. ec=%v\nout=%s\nerr=%v", ec, out, err)
623
+	}
624
+
625
+	// Find out the system assigned port
626
+	out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "port", container, "80/tcp"))
627
+	if err != nil {
628
+		return nil, fmt.Errorf("failed to find container port: err=%v\nout=%s", err, out)
629
+	}
630
+
631
+	fileserverHostPort := strings.Trim(out, "\n")
632
+	_, port, err := net.SplitHostPort(fileserverHostPort)
633
+	if err != nil {
634
+		return nil, fmt.Errorf("unable to parse file server host:port: %v", err)
635
+	}
636
+
637
+	dockerHostURL, err := url.Parse(daemonHost())
638
+	if err != nil {
639
+		return nil, fmt.Errorf("unable to parse daemon host URL: %v", err)
640
+	}
641
+
642
+	host, _, err := net.SplitHostPort(dockerHostURL.Host)
643
+	if err != nil {
644
+		return nil, fmt.Errorf("unable to parse docker daemon host:port: %v", err)
645
+	}
646
+
647
+	return &remoteFileServer{
648
+		container: container,
649
+		image:     image,
650
+		host:      fmt.Sprintf("%s:%s", host, port),
651
+		ctx:       ctx}, nil
652
+}
653
+
654
+func inspectFieldAndMarshall(c *check.C, name, field string, output interface{}) {
655
+	str := inspectFieldJSON(c, name, field)
656
+	err := json.Unmarshal([]byte(str), output)
657
+	if c != nil {
658
+		c.Assert(err, check.IsNil, check.Commentf("failed to unmarshal: %v", err))
659
+	}
660
+}
661
+
662
+func inspectFilter(name, filter string) (string, error) {
663
+	format := fmt.Sprintf("{{%s}}", filter)
664
+	inspectCmd := exec.Command(dockerBinary, "inspect", "-f", format, name)
665
+	out, exitCode, err := runCommandWithOutput(inspectCmd)
666
+	if err != nil || exitCode != 0 {
667
+		return "", fmt.Errorf("failed to inspect %s: %s", name, out)
668
+	}
669
+	return strings.TrimSpace(out), nil
670
+}
671
+
672
+func inspectFieldWithError(name, field string) (string, error) {
673
+	return inspectFilter(name, fmt.Sprintf(".%s", field))
674
+}
675
+
676
+func inspectField(c *check.C, name, field string) string {
677
+	out, err := inspectFilter(name, fmt.Sprintf(".%s", field))
678
+	if c != nil {
679
+		c.Assert(err, check.IsNil)
680
+	}
681
+	return out
682
+}
683
+
684
+func inspectFieldJSON(c *check.C, name, field string) string {
685
+	out, err := inspectFilter(name, fmt.Sprintf("json .%s", field))
686
+	if c != nil {
687
+		c.Assert(err, check.IsNil)
688
+	}
689
+	return out
690
+}
691
+
692
+func inspectFieldMap(c *check.C, name, path, field string) string {
693
+	out, err := inspectFilter(name, fmt.Sprintf("index .%s %q", path, field))
694
+	if c != nil {
695
+		c.Assert(err, check.IsNil)
696
+	}
697
+	return out
698
+}
699
+
700
+func inspectMountSourceField(name, destination string) (string, error) {
701
+	m, err := inspectMountPoint(name, destination)
702
+	if err != nil {
703
+		return "", err
704
+	}
705
+	return m.Source, nil
706
+}
707
+
708
+func inspectMountPoint(name, destination string) (types.MountPoint, error) {
709
+	out, err := inspectFilter(name, "json .Mounts")
710
+	if err != nil {
711
+		return types.MountPoint{}, err
712
+	}
713
+
714
+	return inspectMountPointJSON(out, destination)
715
+}
716
+
717
+var errMountNotFound = errors.New("mount point not found")
718
+
719
+func inspectMountPointJSON(j, destination string) (types.MountPoint, error) {
720
+	var mp []types.MountPoint
721
+	if err := json.Unmarshal([]byte(j), &mp); err != nil {
722
+		return types.MountPoint{}, err
723
+	}
724
+
725
+	var m *types.MountPoint
726
+	for _, c := range mp {
727
+		if c.Destination == destination {
728
+			m = &c
729
+			break
730
+		}
731
+	}
732
+
733
+	if m == nil {
734
+		return types.MountPoint{}, errMountNotFound
735
+	}
736
+
737
+	return *m, nil
738
+}
739
+
740
+func inspectImage(name, filter string) (string, error) {
741
+	args := []string{"inspect", "--type", "image"}
742
+	if filter != "" {
743
+		format := fmt.Sprintf("{{%s}}", filter)
744
+		args = append(args, "-f", format)
745
+	}
746
+	args = append(args, name)
747
+	inspectCmd := exec.Command(dockerBinary, args...)
748
+	out, exitCode, err := runCommandWithOutput(inspectCmd)
749
+	if err != nil || exitCode != 0 {
750
+		return "", fmt.Errorf("failed to inspect %s: %s", name, out)
751
+	}
752
+	return strings.TrimSpace(out), nil
753
+}
754
+
755
+func getIDByName(name string) (string, error) {
756
+	return inspectFieldWithError(name, "Id")
757
+}
758
+
759
+func buildImageCmd(name, dockerfile string, useCache bool, buildFlags ...string) *exec.Cmd {
760
+	return daemon.BuildImageCmdWithHost(dockerBinary, name, dockerfile, "", useCache, buildFlags...)
761
+}
762
+
763
+func buildImageWithOut(name, dockerfile string, useCache bool, buildFlags ...string) (string, string, error) {
764
+	buildCmd := buildImageCmd(name, dockerfile, useCache, buildFlags...)
765
+	out, exitCode, err := runCommandWithOutput(buildCmd)
766
+	if err != nil || exitCode != 0 {
767
+		return "", out, fmt.Errorf("failed to build the image: %s", out)
768
+	}
769
+	id, err := getIDByName(name)
770
+	if err != nil {
771
+		return "", out, err
772
+	}
773
+	return id, out, nil
774
+}
775
+
776
+func buildImageWithStdoutStderr(name, dockerfile string, useCache bool, buildFlags ...string) (string, string, string, error) {
777
+	buildCmd := buildImageCmd(name, dockerfile, useCache, buildFlags...)
778
+	result := icmd.RunCmd(transformCmd(buildCmd))
779
+	err := result.Error
780
+	exitCode := result.ExitCode
781
+	if err != nil || exitCode != 0 {
782
+		return "", result.Stdout(), result.Stderr(), fmt.Errorf("failed to build the image: %s", result.Combined())
783
+	}
784
+	id, err := getIDByName(name)
785
+	if err != nil {
786
+		return "", result.Stdout(), result.Stderr(), err
787
+	}
788
+	return id, result.Stdout(), result.Stderr(), nil
789
+}
790
+
791
+func buildImage(name, dockerfile string, useCache bool, buildFlags ...string) (string, error) {
792
+	id, _, err := buildImageWithOut(name, dockerfile, useCache, buildFlags...)
793
+	return id, err
794
+}
795
+
796
+func buildImageFromContext(name string, ctx *FakeContext, useCache bool, buildFlags ...string) (string, error) {
797
+	id, _, err := buildImageFromContextWithOut(name, ctx, useCache, buildFlags...)
798
+	if err != nil {
799
+		return "", err
800
+	}
801
+	return id, nil
802
+}
803
+
804
+func buildImageFromContextWithOut(name string, ctx *FakeContext, useCache bool, buildFlags ...string) (string, string, error) {
805
+	args := []string{"build", "-t", name}
806
+	if !useCache {
807
+		args = append(args, "--no-cache")
808
+	}
809
+	args = append(args, buildFlags...)
810
+	args = append(args, ".")
811
+	buildCmd := exec.Command(dockerBinary, args...)
812
+	buildCmd.Dir = ctx.Dir
813
+	out, exitCode, err := runCommandWithOutput(buildCmd)
814
+	if err != nil || exitCode != 0 {
815
+		return "", "", fmt.Errorf("failed to build the image: %s", out)
816
+	}
817
+	id, err := getIDByName(name)
818
+	if err != nil {
819
+		return "", "", err
820
+	}
821
+	return id, out, nil
822
+}
823
+
824
+func buildImageFromContextWithStdoutStderr(name string, ctx *FakeContext, useCache bool, buildFlags ...string) (string, string, string, error) {
825
+	args := []string{"build", "-t", name}
826
+	if !useCache {
827
+		args = append(args, "--no-cache")
828
+	}
829
+	args = append(args, buildFlags...)
830
+	args = append(args, ".")
831
+
832
+	result := icmd.RunCmd(icmd.Cmd{
833
+		Command: append([]string{dockerBinary}, args...),
834
+		Dir:     ctx.Dir,
835
+	})
836
+	exitCode := result.ExitCode
837
+	err := result.Error
838
+	if err != nil || exitCode != 0 {
839
+		return "", result.Stdout(), result.Stderr(), fmt.Errorf("failed to build the image: %s", result.Combined())
840
+	}
841
+	id, err := getIDByName(name)
842
+	if err != nil {
843
+		return "", result.Stdout(), result.Stderr(), err
844
+	}
845
+	return id, result.Stdout(), result.Stderr(), nil
846
+}
847
+
848
+func buildImageFromGitWithStdoutStderr(name string, ctx *fakeGit, useCache bool, buildFlags ...string) (string, string, string, error) {
849
+	args := []string{"build", "-t", name}
850
+	if !useCache {
851
+		args = append(args, "--no-cache")
852
+	}
853
+	args = append(args, buildFlags...)
854
+	args = append(args, ctx.RepoURL)
855
+	result := icmd.RunCmd(icmd.Cmd{
856
+		Command: append([]string{dockerBinary}, args...),
857
+	})
858
+	exitCode := result.ExitCode
859
+	err := result.Error
860
+	if err != nil || exitCode != 0 {
861
+		return "", result.Stdout(), result.Stderr(), fmt.Errorf("failed to build the image: %s", result.Combined())
862
+	}
863
+	id, err := getIDByName(name)
864
+	if err != nil {
865
+		return "", result.Stdout(), result.Stderr(), err
866
+	}
867
+	return id, result.Stdout(), result.Stderr(), nil
868
+}
869
+
870
+func buildImageFromPath(name, path string, useCache bool, buildFlags ...string) (string, error) {
871
+	args := []string{"build", "-t", name}
872
+	if !useCache {
873
+		args = append(args, "--no-cache")
874
+	}
875
+	args = append(args, buildFlags...)
876
+	args = append(args, path)
877
+	buildCmd := exec.Command(dockerBinary, args...)
878
+	out, exitCode, err := runCommandWithOutput(buildCmd)
879
+	if err != nil || exitCode != 0 {
880
+		return "", fmt.Errorf("failed to build the image: %s", out)
881
+	}
882
+	return getIDByName(name)
883
+}
884
+
885
+type gitServer interface {
886
+	URL() string
887
+	Close() error
888
+}
889
+
890
+type localGitServer struct {
891
+	*httptest.Server
892
+}
893
+
894
+func (r *localGitServer) Close() error {
895
+	r.Server.Close()
896
+	return nil
897
+}
898
+
899
+func (r *localGitServer) URL() string {
900
+	return r.Server.URL
901
+}
902
+
903
+type fakeGit struct {
904
+	root    string
905
+	server  gitServer
906
+	RepoURL string
907
+}
908
+
909
+func (g *fakeGit) Close() {
910
+	g.server.Close()
911
+	os.RemoveAll(g.root)
912
+}
913
+
914
+func newFakeGit(name string, files map[string]string, enforceLocalServer bool) (*fakeGit, error) {
915
+	ctx, err := fakeContextWithFiles(files)
916
+	if err != nil {
917
+		return nil, err
918
+	}
919
+	defer ctx.Close()
920
+	curdir, err := os.Getwd()
921
+	if err != nil {
922
+		return nil, err
923
+	}
924
+	defer os.Chdir(curdir)
925
+
926
+	if output, err := exec.Command("git", "init", ctx.Dir).CombinedOutput(); err != nil {
927
+		return nil, fmt.Errorf("error trying to init repo: %s (%s)", err, output)
928
+	}
929
+	err = os.Chdir(ctx.Dir)
930
+	if err != nil {
931
+		return nil, err
932
+	}
933
+	if output, err := exec.Command("git", "config", "user.name", "Fake User").CombinedOutput(); err != nil {
934
+		return nil, fmt.Errorf("error trying to set 'user.name': %s (%s)", err, output)
935
+	}
936
+	if output, err := exec.Command("git", "config", "user.email", "fake.user@example.com").CombinedOutput(); err != nil {
937
+		return nil, fmt.Errorf("error trying to set 'user.email': %s (%s)", err, output)
938
+	}
939
+	if output, err := exec.Command("git", "add", "*").CombinedOutput(); err != nil {
940
+		return nil, fmt.Errorf("error trying to add files to repo: %s (%s)", err, output)
941
+	}
942
+	if output, err := exec.Command("git", "commit", "-a", "-m", "Initial commit").CombinedOutput(); err != nil {
943
+		return nil, fmt.Errorf("error trying to commit to repo: %s (%s)", err, output)
944
+	}
945
+
946
+	root, err := ioutil.TempDir("", "docker-test-git-repo")
947
+	if err != nil {
948
+		return nil, err
949
+	}
950
+	repoPath := filepath.Join(root, name+".git")
951
+	if output, err := exec.Command("git", "clone", "--bare", ctx.Dir, repoPath).CombinedOutput(); err != nil {
952
+		os.RemoveAll(root)
953
+		return nil, fmt.Errorf("error trying to clone --bare: %s (%s)", err, output)
954
+	}
955
+	err = os.Chdir(repoPath)
956
+	if err != nil {
957
+		os.RemoveAll(root)
958
+		return nil, err
959
+	}
960
+	if output, err := exec.Command("git", "update-server-info").CombinedOutput(); err != nil {
961
+		os.RemoveAll(root)
962
+		return nil, fmt.Errorf("error trying to git update-server-info: %s (%s)", err, output)
963
+	}
964
+	err = os.Chdir(curdir)
965
+	if err != nil {
966
+		os.RemoveAll(root)
967
+		return nil, err
968
+	}
969
+
970
+	var server gitServer
971
+	if !enforceLocalServer {
972
+		// use fakeStorage server, which might be local or remote (at test daemon)
973
+		server, err = fakeStorageWithContext(fakeContextFromDir(root))
974
+		if err != nil {
975
+			return nil, fmt.Errorf("cannot start fake storage: %v", err)
976
+		}
977
+	} else {
978
+		// always start a local http server on CLI test machine
979
+		httpServer := httptest.NewServer(http.FileServer(http.Dir(root)))
980
+		server = &localGitServer{httpServer}
981
+	}
982
+	return &fakeGit{
983
+		root:    root,
984
+		server:  server,
985
+		RepoURL: fmt.Sprintf("%s/%s.git", server.URL(), name),
986
+	}, nil
987
+}
988
+
989
+// Write `content` to the file at path `dst`, creating it if necessary,
990
+// as well as any missing directories.
991
+// The file is truncated if it already exists.
992
+// Fail the test when error occurs.
993
+func writeFile(dst, content string, c *check.C) {
994
+	// Create subdirectories if necessary
995
+	c.Assert(os.MkdirAll(path.Dir(dst), 0700), check.IsNil)
996
+	f, err := os.OpenFile(dst, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0700)
997
+	c.Assert(err, check.IsNil)
998
+	defer f.Close()
999
+	// Write content (truncate if it exists)
1000
+	_, err = io.Copy(f, strings.NewReader(content))
1001
+	c.Assert(err, check.IsNil)
1002
+}
1003
+
1004
+// Return the contents of file at path `src`.
1005
+// Fail the test when error occurs.
1006
+func readFile(src string, c *check.C) (content string) {
1007
+	data, err := ioutil.ReadFile(src)
1008
+	c.Assert(err, check.IsNil)
1009
+
1010
+	return string(data)
1011
+}
1012
+
1013
+func containerStorageFile(containerID, basename string) string {
1014
+	return filepath.Join(containerStoragePath, containerID, basename)
1015
+}
1016
+
1017
+// docker commands that use this function must be run with the '-d' switch.
1018
+func runCommandAndReadContainerFile(filename string, cmd *exec.Cmd) ([]byte, error) {
1019
+	out, _, err := runCommandWithOutput(cmd)
1020
+	if err != nil {
1021
+		return nil, fmt.Errorf("%v: %q", err, out)
1022
+	}
1023
+
1024
+	contID := strings.TrimSpace(out)
1025
+
1026
+	if err := waitRun(contID); err != nil {
1027
+		return nil, fmt.Errorf("%v: %q", contID, err)
1028
+	}
1029
+
1030
+	return readContainerFile(contID, filename)
1031
+}
1032
+
1033
+func readContainerFile(containerID, filename string) ([]byte, error) {
1034
+	f, err := os.Open(containerStorageFile(containerID, filename))
1035
+	if err != nil {
1036
+		return nil, err
1037
+	}
1038
+	defer f.Close()
1039
+
1040
+	content, err := ioutil.ReadAll(f)
1041
+	if err != nil {
1042
+		return nil, err
1043
+	}
1044
+
1045
+	return content, nil
1046
+}
1047
+
1048
+func readContainerFileWithExec(containerID, filename string) ([]byte, error) {
1049
+	out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "exec", containerID, "cat", filename))
1050
+	return []byte(out), err
1051
+}
1052
+
1053
+// daemonTime provides the current time on the daemon host
1054
+func daemonTime(c *check.C) time.Time {
1055
+	if isLocalDaemon {
1056
+		return time.Now()
1057
+	}
1058
+
1059
+	status, body, err := sockRequest("GET", "/info", nil)
1060
+	c.Assert(err, check.IsNil)
1061
+	c.Assert(status, check.Equals, http.StatusOK)
1062
+
1063
+	type infoJSON struct {
1064
+		SystemTime string
1065
+	}
1066
+	var info infoJSON
1067
+	err = json.Unmarshal(body, &info)
1068
+	c.Assert(err, check.IsNil, check.Commentf("unable to unmarshal GET /info response"))
1069
+
1070
+	dt, err := time.Parse(time.RFC3339Nano, info.SystemTime)
1071
+	c.Assert(err, check.IsNil, check.Commentf("invalid time format in GET /info response"))
1072
+	return dt
1073
+}
1074
+
1075
+// daemonUnixTime returns the current time on the daemon host with nanoseconds precision.
1076
+// It return the time formatted how the client sends timestamps to the server.
1077
+func daemonUnixTime(c *check.C) string {
1078
+	return parseEventTime(daemonTime(c))
1079
+}
1080
+
1081
+func parseEventTime(t time.Time) string {
1082
+	return fmt.Sprintf("%d.%09d", t.Unix(), int64(t.Nanosecond()))
1083
+}
1084
+
1085
+func setupRegistry(c *check.C, schema1 bool, auth, tokenURL string) *testRegistryV2 {
1086
+	reg, err := newTestRegistryV2(c, schema1, auth, tokenURL)
1087
+	c.Assert(err, check.IsNil)
1088
+
1089
+	// Wait for registry to be ready to serve requests.
1090
+	for i := 0; i != 50; i++ {
1091
+		if err = reg.Ping(); err == nil {
1092
+			break
1093
+		}
1094
+		time.Sleep(100 * time.Millisecond)
1095
+	}
1096
+
1097
+	c.Assert(err, check.IsNil, check.Commentf("Timeout waiting for test registry to become available: %v", err))
1098
+	return reg
1099
+}
1100
+
1101
+func setupNotary(c *check.C) *testNotary {
1102
+	ts, err := newTestNotary(c)
1103
+	c.Assert(err, check.IsNil)
1104
+
1105
+	return ts
1106
+}
1107
+
1108
+// appendBaseEnv appends the minimum set of environment variables to exec the
1109
+// docker cli binary for testing with correct configuration to the given env
1110
+// list.
1111
+func appendBaseEnv(isTLS bool, env ...string) []string {
1112
+	preserveList := []string{
1113
+		// preserve remote test host
1114
+		"DOCKER_HOST",
1115
+
1116
+		// windows: requires preserving SystemRoot, otherwise dial tcp fails
1117
+		// with "GetAddrInfoW: A non-recoverable error occurred during a database lookup."
1118
+		"SystemRoot",
1119
+
1120
+		// testing help text requires the $PATH to dockerd is set
1121
+		"PATH",
1122
+	}
1123
+	if isTLS {
1124
+		preserveList = append(preserveList, "DOCKER_TLS_VERIFY", "DOCKER_CERT_PATH")
1125
+	}
1126
+
1127
+	for _, key := range preserveList {
1128
+		if val := os.Getenv(key); val != "" {
1129
+			env = append(env, fmt.Sprintf("%s=%s", key, val))
1130
+		}
1131
+	}
1132
+	return env
1133
+}
1134
+
1135
+func createTmpFile(c *check.C, content string) string {
1136
+	f, err := ioutil.TempFile("", "testfile")
1137
+	c.Assert(err, check.IsNil)
1138
+
1139
+	filename := f.Name()
1140
+
1141
+	err = ioutil.WriteFile(filename, []byte(content), 0644)
1142
+	c.Assert(err, check.IsNil)
1143
+
1144
+	return filename
1145
+}
1146
+
1147
+func waitForContainer(contID string, args ...string) error {
1148
+	args = append([]string{dockerBinary, "run", "--name", contID}, args...)
1149
+	result := icmd.RunCmd(icmd.Cmd{Command: args})
1150
+	if result.Error != nil {
1151
+		return result.Error
1152
+	}
1153
+	return waitRun(contID)
1154
+}
1155
+
1156
+// waitRestart will wait for the specified container to restart once
1157
+func waitRestart(contID string, duration time.Duration) error {
1158
+	return waitInspect(contID, "{{.RestartCount}}", "1", duration)
1159
+}
1160
+
1161
+// waitRun will wait for the specified container to be running, maximum 5 seconds.
1162
+func waitRun(contID string) error {
1163
+	return waitInspect(contID, "{{.State.Running}}", "true", 5*time.Second)
1164
+}
1165
+
1166
+// waitExited will wait for the specified container to state exit, subject
1167
+// to a maximum time limit in seconds supplied by the caller
1168
+func waitExited(contID string, duration time.Duration) error {
1169
+	return waitInspect(contID, "{{.State.Status}}", "exited", duration)
1170
+}
1171
+
1172
+// waitInspect will wait for the specified container to have the specified string
1173
+// in the inspect output. It will wait until the specified timeout (in seconds)
1174
+// is reached.
1175
+func waitInspect(name, expr, expected string, timeout time.Duration) error {
1176
+	return waitInspectWithArgs(name, expr, expected, timeout)
1177
+}
1178
+
1179
+func waitInspectWithArgs(name, expr, expected string, timeout time.Duration, arg ...string) error {
1180
+	return daemon.WaitInspectWithArgs(dockerBinary, name, expr, expected, timeout, arg...)
1181
+}
1182
+
1183
+func getInspectBody(c *check.C, version, id string) []byte {
1184
+	endpoint := fmt.Sprintf("/%s/containers/%s/json", version, id)
1185
+	status, body, err := sockRequest("GET", endpoint, nil)
1186
+	c.Assert(err, check.IsNil)
1187
+	c.Assert(status, check.Equals, http.StatusOK)
1188
+	return body
1189
+}
1190
+
1191
+// Run a long running idle task in a background container using the
1192
+// system-specific default image and command.
1193
+func runSleepingContainer(c *check.C, extraArgs ...string) (string, int) {
1194
+	return runSleepingContainerInImage(c, defaultSleepImage, extraArgs...)
1195
+}
1196
+
1197
+// Run a long running idle task in a background container using the specified
1198
+// image and the system-specific command.
1199
+func runSleepingContainerInImage(c *check.C, image string, extraArgs ...string) (string, int) {
1200
+	args := []string{"run", "-d"}
1201
+	args = append(args, extraArgs...)
1202
+	args = append(args, image)
1203
+	args = append(args, sleepCommandForDaemonPlatform()...)
1204
+	return dockerCmd(c, args...)
1205
+}
1206
+
1207
+// minimalBaseImage returns the name of the minimal base image for the current
1208
+// daemon platform.
1209
+func minimalBaseImage() string {
1210
+	return testEnv.MinimalBaseImage()
1211
+}
1212
+
1213
+func getGoroutineNumber() (int, error) {
1214
+	i := struct {
1215
+		NGoroutines int
1216
+	}{}
1217
+	status, b, err := sockRequest("GET", "/info", nil)
1218
+	if err != nil {
1219
+		return 0, err
1220
+	}
1221
+	if status != http.StatusOK {
1222
+		return 0, fmt.Errorf("http status code: %d", status)
1223
+	}
1224
+	if err := json.Unmarshal(b, &i); err != nil {
1225
+		return 0, err
1226
+	}
1227
+	return i.NGoroutines, nil
1228
+}
1229
+
1230
+func waitForGoroutines(expected int) error {
1231
+	t := time.After(30 * time.Second)
1232
+	for {
1233
+		select {
1234
+		case <-t:
1235
+			n, err := getGoroutineNumber()
1236
+			if err != nil {
1237
+				return err
1238
+			}
1239
+			if n > expected {
1240
+				return fmt.Errorf("leaked goroutines: expected less than or equal to %d, got: %d", expected, n)
1241
+			}
1242
+		default:
1243
+			n, err := getGoroutineNumber()
1244
+			if err != nil {
1245
+				return err
1246
+			}
1247
+			if n <= expected {
1248
+				return nil
1249
+			}
1250
+			time.Sleep(200 * time.Millisecond)
1251
+		}
1252
+	}
1253
+}
1254
+
1255
+// getErrorMessage returns the error message from an error API response
1256
+func getErrorMessage(c *check.C, body []byte) string {
1257
+	var resp types.ErrorResponse
1258
+	c.Assert(json.Unmarshal(body, &resp), check.IsNil)
1259
+	return strings.TrimSpace(resp.Message)
1260
+}
1261
+
1262
+func waitAndAssert(c *check.C, timeout time.Duration, f checkF, checker check.Checker, args ...interface{}) {
1263
+	after := time.After(timeout)
1264
+	for {
1265
+		v, comment := f(c)
1266
+		assert, _ := checker.Check(append([]interface{}{v}, args...), checker.Info().Params)
1267
+		select {
1268
+		case <-after:
1269
+			assert = true
1270
+		default:
1271
+		}
1272
+		if assert {
1273
+			if comment != nil {
1274
+				args = append(args, comment)
1275
+			}
1276
+			c.Assert(v, checker, args...)
1277
+			return
1278
+		}
1279
+		time.Sleep(100 * time.Millisecond)
1280
+	}
1281
+}
1282
+
1283
+type checkF func(*check.C) (interface{}, check.CommentInterface)
1284
+type reducer func(...interface{}) interface{}
1285
+
1286
+func reducedCheck(r reducer, funcs ...checkF) checkF {
1287
+	return func(c *check.C) (interface{}, check.CommentInterface) {
1288
+		var values []interface{}
1289
+		var comments []string
1290
+		for _, f := range funcs {
1291
+			v, comment := f(c)
1292
+			values = append(values, v)
1293
+			if comment != nil {
1294
+				comments = append(comments, comment.CheckCommentString())
1295
+			}
1296
+		}
1297
+		return r(values...), check.Commentf("%v", strings.Join(comments, ", "))
1298
+	}
1299
+}
1300
+
1301
+func sumAsIntegers(vals ...interface{}) interface{} {
1302
+	var s int
1303
+	for _, v := range vals {
1304
+		s += v.(int)
1305
+	}
1306
+	return s
1307
+}
0 1308
new file mode 100644
... ...
@@ -0,0 +1,184 @@
0
+package environment
1
+
2
+import (
3
+	"fmt"
4
+	"io/ioutil"
5
+	"os"
6
+	"path/filepath"
7
+	"strconv"
8
+	"strings"
9
+
10
+	"golang.org/x/net/context"
11
+
12
+	"github.com/docker/docker/api/types"
13
+	"github.com/docker/docker/api/types/container"
14
+	"github.com/docker/docker/client"
15
+)
16
+
17
+// Execution holds informations about the test execution environment.
18
+type Execution struct {
19
+	daemonPlatform      string
20
+	localDaemon         bool
21
+	experimentalDaemon  bool
22
+	daemonStorageDriver string
23
+	isolation           container.Isolation
24
+	daemonPid           int
25
+	daemonKernelVersion string
26
+	// For a local daemon on Linux, these values will be used for testing
27
+	// user namespace support as the standard graph path(s) will be
28
+	// appended with the root remapped uid.gid prefix
29
+	dockerBasePath       string
30
+	volumesConfigPath    string
31
+	containerStoragePath string
32
+	// baseImage is the name of the base image for testing
33
+	// Environment variable WINDOWS_BASE_IMAGE can override this
34
+	baseImage string
35
+}
36
+
37
+// New creates a new Execution struct
38
+func New() (*Execution, error) {
39
+	localDaemon := true
40
+	// Deterministically working out the environment in which CI is running
41
+	// to evaluate whether the daemon is local or remote is not possible through
42
+	// a build tag.
43
+	//
44
+	// For example Windows to Linux CI under Jenkins tests the 64-bit
45
+	// Windows binary build with the daemon build tag, but calls a remote
46
+	// Linux daemon.
47
+	//
48
+	// We can't just say if Windows then assume the daemon is local as at
49
+	// some point, we will be testing the Windows CLI against a Windows daemon.
50
+	//
51
+	// Similarly, it will be perfectly valid to also run CLI tests from
52
+	// a Linux CLI (built with the daemon tag) against a Windows daemon.
53
+	if len(os.Getenv("DOCKER_REMOTE_DAEMON")) > 0 {
54
+		localDaemon = false
55
+	}
56
+	info, err := getDaemonDockerInfo()
57
+	if err != nil {
58
+		return nil, err
59
+	}
60
+	daemonPlatform := info.OSType
61
+	if daemonPlatform != "linux" && daemonPlatform != "windows" {
62
+		return nil, fmt.Errorf("Cannot run tests against platform: %s", daemonPlatform)
63
+	}
64
+	baseImage := "scratch"
65
+	volumesConfigPath := filepath.Join(info.DockerRootDir, "volumes")
66
+	containerStoragePath := filepath.Join(info.DockerRootDir, "containers")
67
+	// Make sure in context of daemon, not the local platform. Note we can't
68
+	// use filepath.FromSlash or ToSlash here as they are a no-op on Unix.
69
+	if daemonPlatform == "windows" {
70
+		volumesConfigPath = strings.Replace(volumesConfigPath, `/`, `\`, -1)
71
+		containerStoragePath = strings.Replace(containerStoragePath, `/`, `\`, -1)
72
+
73
+		baseImage = "microsoft/windowsservercore"
74
+		if len(os.Getenv("WINDOWS_BASE_IMAGE")) > 0 {
75
+			baseImage = os.Getenv("WINDOWS_BASE_IMAGE")
76
+			fmt.Println("INFO: Windows Base image is ", baseImage)
77
+		}
78
+	} else {
79
+		volumesConfigPath = strings.Replace(volumesConfigPath, `\`, `/`, -1)
80
+		containerStoragePath = strings.Replace(containerStoragePath, `\`, `/`, -1)
81
+	}
82
+
83
+	var daemonPid int
84
+	dest := os.Getenv("DEST")
85
+	b, err := ioutil.ReadFile(filepath.Join(dest, "docker.pid"))
86
+	if err == nil {
87
+		if p, err := strconv.ParseInt(string(b), 10, 32); err == nil {
88
+			daemonPid = int(p)
89
+		}
90
+	}
91
+	return &Execution{
92
+		localDaemon:          localDaemon,
93
+		daemonPlatform:       daemonPlatform,
94
+		daemonStorageDriver:  info.Driver,
95
+		daemonKernelVersion:  info.KernelVersion,
96
+		dockerBasePath:       info.DockerRootDir,
97
+		volumesConfigPath:    volumesConfigPath,
98
+		containerStoragePath: containerStoragePath,
99
+		isolation:            info.Isolation,
100
+		daemonPid:            daemonPid,
101
+		experimentalDaemon:   info.ExperimentalBuild,
102
+		baseImage:            baseImage,
103
+	}, nil
104
+}
105
+func getDaemonDockerInfo() (types.Info, error) {
106
+	// FIXME(vdemeester) should be safe to use as is
107
+	client, err := client.NewEnvClient()
108
+	if err != nil {
109
+		return types.Info{}, err
110
+	}
111
+	return client.Info(context.Background())
112
+}
113
+
114
+// LocalDaemon is true if the daemon under test is on the same
115
+// host as the CLI.
116
+func (e *Execution) LocalDaemon() bool {
117
+	return e.localDaemon
118
+}
119
+
120
+// DaemonPlatform is held globally so that tests can make intelligent
121
+// decisions on how to configure themselves according to the platform
122
+// of the daemon. This is initialized in docker_utils by sending
123
+// a version call to the daemon and examining the response header.
124
+func (e *Execution) DaemonPlatform() string {
125
+	return e.daemonPlatform
126
+}
127
+
128
+// DockerBasePath is the base path of the docker folder (by default it is -/var/run/docker)
129
+func (e *Execution) DockerBasePath() string {
130
+	return e.dockerBasePath
131
+}
132
+
133
+// VolumesConfigPath is the path of the volume configuration for the testing daemon
134
+func (e *Execution) VolumesConfigPath() string {
135
+	return e.volumesConfigPath
136
+}
137
+
138
+// ContainerStoragePath is the path where the container are stored for the testing daemon
139
+func (e *Execution) ContainerStoragePath() string {
140
+	return e.containerStoragePath
141
+}
142
+
143
+// DaemonStorageDriver is held globally so that tests can know the storage
144
+// driver of the daemon. This is initialized in docker_utils by sending
145
+// a version call to the daemon and examining the response header.
146
+func (e *Execution) DaemonStorageDriver() string {
147
+	return e.daemonStorageDriver
148
+}
149
+
150
+// Isolation is the isolation mode of the daemon under test
151
+func (e *Execution) Isolation() container.Isolation {
152
+	return e.isolation
153
+}
154
+
155
+// DaemonPID is the pid of the main test daemon
156
+func (e *Execution) DaemonPID() int {
157
+	return e.daemonPid
158
+}
159
+
160
+// ExperimentalDaemon tell whether the main daemon has
161
+// experimental features enabled or not
162
+func (e *Execution) ExperimentalDaemon() bool {
163
+	return e.experimentalDaemon
164
+}
165
+
166
+// MinimalBaseImage is the image used for minimal builds (it depends on the platform)
167
+func (e *Execution) MinimalBaseImage() string {
168
+	return e.baseImage
169
+}
170
+
171
+// DaemonKernelVersion is the kernel version of the daemon
172
+func (e *Execution) DaemonKernelVersion() string {
173
+	return e.daemonKernelVersion
174
+}
175
+
176
+// WindowsKernelVersion is used on Windows to distinguish between different
177
+// versions. This is necessary to enable certain tests based on whether
178
+// the platform supports it. For example, Windows Server 2016 TP3 did
179
+// not support volumes, but TP4 did.
180
+func WindowsKernelVersion(kernelVersion string) int {
181
+	winKV, _ := strconv.Atoi(strings.Split(kernelVersion, " ")[1])
182
+	return winKV
183
+}
0 184
deleted file mode 100644
... ...
@@ -1,206 +0,0 @@
1
-package main
2
-
3
-import (
4
-	"bufio"
5
-	"bytes"
6
-	"io"
7
-	"os/exec"
8
-	"regexp"
9
-	"strconv"
10
-	"strings"
11
-
12
-	"github.com/Sirupsen/logrus"
13
-	eventstestutils "github.com/docker/docker/daemon/events/testutils"
14
-	"github.com/docker/docker/pkg/integration/checker"
15
-	"github.com/go-check/check"
16
-)
17
-
18
-// eventMatcher is a function that tries to match an event input.
19
-// It returns true if the event matches and a map with
20
-// a set of key/value to identify the match.
21
-type eventMatcher func(text string) (map[string]string, bool)
22
-
23
-// eventMatchProcessor is a function to handle an event match.
24
-// It receives a map of key/value with the information extracted in a match.
25
-type eventMatchProcessor func(matches map[string]string)
26
-
27
-// eventObserver runs an events commands and observes its output.
28
-type eventObserver struct {
29
-	buffer             *bytes.Buffer
30
-	command            *exec.Cmd
31
-	scanner            *bufio.Scanner
32
-	startTime          string
33
-	disconnectionError error
34
-}
35
-
36
-// newEventObserver creates the observer and initializes the command
37
-// without running it. Users must call `eventObserver.Start` to start the command.
38
-func newEventObserver(c *check.C, args ...string) (*eventObserver, error) {
39
-	since := daemonTime(c).Unix()
40
-	return newEventObserverWithBacklog(c, since, args...)
41
-}
42
-
43
-// newEventObserverWithBacklog creates a new observer changing the start time of the backlog to return.
44
-func newEventObserverWithBacklog(c *check.C, since int64, args ...string) (*eventObserver, error) {
45
-	startTime := strconv.FormatInt(since, 10)
46
-	cmdArgs := []string{"events", "--since", startTime}
47
-	if len(args) > 0 {
48
-		cmdArgs = append(cmdArgs, args...)
49
-	}
50
-	eventsCmd := exec.Command(dockerBinary, cmdArgs...)
51
-	stdout, err := eventsCmd.StdoutPipe()
52
-	if err != nil {
53
-		return nil, err
54
-	}
55
-
56
-	return &eventObserver{
57
-		buffer:    new(bytes.Buffer),
58
-		command:   eventsCmd,
59
-		scanner:   bufio.NewScanner(stdout),
60
-		startTime: startTime,
61
-	}, nil
62
-}
63
-
64
-// Start starts the events command.
65
-func (e *eventObserver) Start() error {
66
-	return e.command.Start()
67
-}
68
-
69
-// Stop stops the events command.
70
-func (e *eventObserver) Stop() {
71
-	e.command.Process.Kill()
72
-	e.command.Process.Release()
73
-}
74
-
75
-// Match tries to match the events output with a given matcher.
76
-func (e *eventObserver) Match(match eventMatcher, process eventMatchProcessor) {
77
-	for e.scanner.Scan() {
78
-		text := e.scanner.Text()
79
-		e.buffer.WriteString(text)
80
-		e.buffer.WriteString("\n")
81
-
82
-		if matches, ok := match(text); ok {
83
-			process(matches)
84
-		}
85
-	}
86
-
87
-	err := e.scanner.Err()
88
-	if err == nil {
89
-		err = io.EOF
90
-	}
91
-
92
-	logrus.Debugf("EventObserver scanner loop finished: %v", err)
93
-	e.disconnectionError = err
94
-}
95
-
96
-func (e *eventObserver) CheckEventError(c *check.C, id, event string, match eventMatcher) {
97
-	var foundEvent bool
98
-	scannerOut := e.buffer.String()
99
-
100
-	if e.disconnectionError != nil {
101
-		until := daemonUnixTime(c)
102
-		out, _ := dockerCmd(c, "events", "--since", e.startTime, "--until", until)
103
-		events := strings.Split(strings.TrimSpace(out), "\n")
104
-		for _, e := range events {
105
-			if _, ok := match(e); ok {
106
-				foundEvent = true
107
-				break
108
-			}
109
-		}
110
-		scannerOut = out
111
-	}
112
-	if !foundEvent {
113
-		c.Fatalf("failed to observe event `%s` for %s. Disconnection error: %v\nout:\n%v", event, id, e.disconnectionError, scannerOut)
114
-	}
115
-}
116
-
117
-// matchEventLine matches a text with the event regular expression.
118
-// It returns the matches and true if the regular expression matches with the given id and event type.
119
-// It returns an empty map and false if there is no match.
120
-func matchEventLine(id, eventType string, actions map[string]chan bool) eventMatcher {
121
-	return func(text string) (map[string]string, bool) {
122
-		matches := eventstestutils.ScanMap(text)
123
-		if len(matches) == 0 {
124
-			return matches, false
125
-		}
126
-
127
-		if matchIDAndEventType(matches, id, eventType) {
128
-			if _, ok := actions[matches["action"]]; ok {
129
-				return matches, true
130
-			}
131
-		}
132
-		return matches, false
133
-	}
134
-}
135
-
136
-// processEventMatch closes an action channel when an event line matches the expected action.
137
-func processEventMatch(actions map[string]chan bool) eventMatchProcessor {
138
-	return func(matches map[string]string) {
139
-		if ch, ok := actions[matches["action"]]; ok {
140
-			ch <- true
141
-		}
142
-	}
143
-}
144
-
145
-// parseEventAction parses an event text and returns the action.
146
-// It fails if the text is not in the event format.
147
-func parseEventAction(c *check.C, text string) string {
148
-	matches := eventstestutils.ScanMap(text)
149
-	return matches["action"]
150
-}
151
-
152
-// eventActionsByIDAndType returns the actions for a given id and type.
153
-// It fails if the text is not in the event format.
154
-func eventActionsByIDAndType(c *check.C, events []string, id, eventType string) []string {
155
-	var filtered []string
156
-	for _, event := range events {
157
-		matches := eventstestutils.ScanMap(event)
158
-		c.Assert(matches, checker.Not(checker.IsNil))
159
-		if matchIDAndEventType(matches, id, eventType) {
160
-			filtered = append(filtered, matches["action"])
161
-		}
162
-	}
163
-	return filtered
164
-}
165
-
166
-// matchIDAndEventType returns true if an event matches a given id and type.
167
-// It also resolves names in the event attributes if the id doesn't match.
168
-func matchIDAndEventType(matches map[string]string, id, eventType string) bool {
169
-	return matchEventID(matches, id) && matches["eventType"] == eventType
170
-}
171
-
172
-func matchEventID(matches map[string]string, id string) bool {
173
-	matchID := matches["id"] == id || strings.HasPrefix(matches["id"], id)
174
-	if !matchID && matches["attributes"] != "" {
175
-		// try matching a name in the attributes
176
-		attributes := map[string]string{}
177
-		for _, a := range strings.Split(matches["attributes"], ", ") {
178
-			kv := strings.Split(a, "=")
179
-			attributes[kv[0]] = kv[1]
180
-		}
181
-		matchID = attributes["name"] == id
182
-	}
183
-	return matchID
184
-}
185
-
186
-func parseEvents(c *check.C, out, match string) {
187
-	events := strings.Split(strings.TrimSpace(out), "\n")
188
-	for _, event := range events {
189
-		matches := eventstestutils.ScanMap(event)
190
-		matched, err := regexp.MatchString(match, matches["action"])
191
-		c.Assert(err, checker.IsNil)
192
-		c.Assert(matched, checker.True, check.Commentf("Matcher: %s did not match %s", match, matches["action"]))
193
-	}
194
-}
195
-
196
-func parseEventsWithID(c *check.C, out, match, id string) {
197
-	events := strings.Split(strings.TrimSpace(out), "\n")
198
-	for _, event := range events {
199
-		matches := eventstestutils.ScanMap(event)
200
-		c.Assert(matchEventID(matches, id), checker.True)
201
-
202
-		matched, err := regexp.MatchString(match, matches["action"])
203
-		c.Assert(err, checker.IsNil)
204
-		c.Assert(matched, checker.True, check.Commentf("Matcher: %s did not match %s", match, matches["action"]))
205
-	}
206
-}
207 1
new file mode 100644
... ...
@@ -0,0 +1,206 @@
0
+package main
1
+
2
+import (
3
+	"bufio"
4
+	"bytes"
5
+	"io"
6
+	"os/exec"
7
+	"regexp"
8
+	"strconv"
9
+	"strings"
10
+
11
+	"github.com/Sirupsen/logrus"
12
+	eventstestutils "github.com/docker/docker/daemon/events/testutils"
13
+	"github.com/docker/docker/pkg/integration/checker"
14
+	"github.com/go-check/check"
15
+)
16
+
17
+// eventMatcher is a function that tries to match an event input.
18
+// It returns true if the event matches and a map with
19
+// a set of key/value to identify the match.
20
+type eventMatcher func(text string) (map[string]string, bool)
21
+
22
+// eventMatchProcessor is a function to handle an event match.
23
+// It receives a map of key/value with the information extracted in a match.
24
+type eventMatchProcessor func(matches map[string]string)
25
+
26
+// eventObserver runs an events commands and observes its output.
27
+type eventObserver struct {
28
+	buffer             *bytes.Buffer
29
+	command            *exec.Cmd
30
+	scanner            *bufio.Scanner
31
+	startTime          string
32
+	disconnectionError error
33
+}
34
+
35
+// newEventObserver creates the observer and initializes the command
36
+// without running it. Users must call `eventObserver.Start` to start the command.
37
+func newEventObserver(c *check.C, args ...string) (*eventObserver, error) {
38
+	since := daemonTime(c).Unix()
39
+	return newEventObserverWithBacklog(c, since, args...)
40
+}
41
+
42
+// newEventObserverWithBacklog creates a new observer changing the start time of the backlog to return.
43
+func newEventObserverWithBacklog(c *check.C, since int64, args ...string) (*eventObserver, error) {
44
+	startTime := strconv.FormatInt(since, 10)
45
+	cmdArgs := []string{"events", "--since", startTime}
46
+	if len(args) > 0 {
47
+		cmdArgs = append(cmdArgs, args...)
48
+	}
49
+	eventsCmd := exec.Command(dockerBinary, cmdArgs...)
50
+	stdout, err := eventsCmd.StdoutPipe()
51
+	if err != nil {
52
+		return nil, err
53
+	}
54
+
55
+	return &eventObserver{
56
+		buffer:    new(bytes.Buffer),
57
+		command:   eventsCmd,
58
+		scanner:   bufio.NewScanner(stdout),
59
+		startTime: startTime,
60
+	}, nil
61
+}
62
+
63
+// Start starts the events command.
64
+func (e *eventObserver) Start() error {
65
+	return e.command.Start()
66
+}
67
+
68
+// Stop stops the events command.
69
+func (e *eventObserver) Stop() {
70
+	e.command.Process.Kill()
71
+	e.command.Process.Release()
72
+}
73
+
74
+// Match tries to match the events output with a given matcher.
75
+func (e *eventObserver) Match(match eventMatcher, process eventMatchProcessor) {
76
+	for e.scanner.Scan() {
77
+		text := e.scanner.Text()
78
+		e.buffer.WriteString(text)
79
+		e.buffer.WriteString("\n")
80
+
81
+		if matches, ok := match(text); ok {
82
+			process(matches)
83
+		}
84
+	}
85
+
86
+	err := e.scanner.Err()
87
+	if err == nil {
88
+		err = io.EOF
89
+	}
90
+
91
+	logrus.Debugf("EventObserver scanner loop finished: %v", err)
92
+	e.disconnectionError = err
93
+}
94
+
95
+func (e *eventObserver) CheckEventError(c *check.C, id, event string, match eventMatcher) {
96
+	var foundEvent bool
97
+	scannerOut := e.buffer.String()
98
+
99
+	if e.disconnectionError != nil {
100
+		until := daemonUnixTime(c)
101
+		out, _ := dockerCmd(c, "events", "--since", e.startTime, "--until", until)
102
+		events := strings.Split(strings.TrimSpace(out), "\n")
103
+		for _, e := range events {
104
+			if _, ok := match(e); ok {
105
+				foundEvent = true
106
+				break
107
+			}
108
+		}
109
+		scannerOut = out
110
+	}
111
+	if !foundEvent {
112
+		c.Fatalf("failed to observe event `%s` for %s. Disconnection error: %v\nout:\n%v", event, id, e.disconnectionError, scannerOut)
113
+	}
114
+}
115
+
116
+// matchEventLine matches a text with the event regular expression.
117
+// It returns the matches and true if the regular expression matches with the given id and event type.
118
+// It returns an empty map and false if there is no match.
119
+func matchEventLine(id, eventType string, actions map[string]chan bool) eventMatcher {
120
+	return func(text string) (map[string]string, bool) {
121
+		matches := eventstestutils.ScanMap(text)
122
+		if len(matches) == 0 {
123
+			return matches, false
124
+		}
125
+
126
+		if matchIDAndEventType(matches, id, eventType) {
127
+			if _, ok := actions[matches["action"]]; ok {
128
+				return matches, true
129
+			}
130
+		}
131
+		return matches, false
132
+	}
133
+}
134
+
135
+// processEventMatch closes an action channel when an event line matches the expected action.
136
+func processEventMatch(actions map[string]chan bool) eventMatchProcessor {
137
+	return func(matches map[string]string) {
138
+		if ch, ok := actions[matches["action"]]; ok {
139
+			ch <- true
140
+		}
141
+	}
142
+}
143
+
144
+// parseEventAction parses an event text and returns the action.
145
+// It fails if the text is not in the event format.
146
+func parseEventAction(c *check.C, text string) string {
147
+	matches := eventstestutils.ScanMap(text)
148
+	return matches["action"]
149
+}
150
+
151
+// eventActionsByIDAndType returns the actions for a given id and type.
152
+// It fails if the text is not in the event format.
153
+func eventActionsByIDAndType(c *check.C, events []string, id, eventType string) []string {
154
+	var filtered []string
155
+	for _, event := range events {
156
+		matches := eventstestutils.ScanMap(event)
157
+		c.Assert(matches, checker.Not(checker.IsNil))
158
+		if matchIDAndEventType(matches, id, eventType) {
159
+			filtered = append(filtered, matches["action"])
160
+		}
161
+	}
162
+	return filtered
163
+}
164
+
165
+// matchIDAndEventType returns true if an event matches a given id and type.
166
+// It also resolves names in the event attributes if the id doesn't match.
167
+func matchIDAndEventType(matches map[string]string, id, eventType string) bool {
168
+	return matchEventID(matches, id) && matches["eventType"] == eventType
169
+}
170
+
171
+func matchEventID(matches map[string]string, id string) bool {
172
+	matchID := matches["id"] == id || strings.HasPrefix(matches["id"], id)
173
+	if !matchID && matches["attributes"] != "" {
174
+		// try matching a name in the attributes
175
+		attributes := map[string]string{}
176
+		for _, a := range strings.Split(matches["attributes"], ", ") {
177
+			kv := strings.Split(a, "=")
178
+			attributes[kv[0]] = kv[1]
179
+		}
180
+		matchID = attributes["name"] == id
181
+	}
182
+	return matchID
183
+}
184
+
185
+func parseEvents(c *check.C, out, match string) {
186
+	events := strings.Split(strings.TrimSpace(out), "\n")
187
+	for _, event := range events {
188
+		matches := eventstestutils.ScanMap(event)
189
+		matched, err := regexp.MatchString(match, matches["action"])
190
+		c.Assert(err, checker.IsNil)
191
+		c.Assert(matched, checker.True, check.Commentf("Matcher: %s did not match %s", match, matches["action"]))
192
+	}
193
+}
194
+
195
+func parseEventsWithID(c *check.C, out, match, id string) {
196
+	events := strings.Split(strings.TrimSpace(out), "\n")
197
+	for _, event := range events {
198
+		matches := eventstestutils.ScanMap(event)
199
+		c.Assert(matchEventID(matches, id), checker.True)
200
+
201
+		matched, err := regexp.MatchString(match, matches["action"])
202
+		c.Assert(err, checker.IsNil)
203
+		c.Assert(matched, checker.True, check.Commentf("Matcher: %s did not match %s", match, matches["action"]))
204
+	}
205
+}
0 206
deleted file mode 100644
... ...
@@ -1,69 +0,0 @@
1
-package main
2
-
3
-import (
4
-	"fmt"
5
-	"io/ioutil"
6
-	"os"
7
-	"os/exec"
8
-	"path/filepath"
9
-	"sync"
10
-)
11
-
12
-var ensureHTTPServerOnce sync.Once
13
-
14
-func ensureHTTPServerImage() error {
15
-	var doIt bool
16
-	ensureHTTPServerOnce.Do(func() {
17
-		doIt = true
18
-	})
19
-
20
-	if !doIt {
21
-		return nil
22
-	}
23
-
24
-	protectedImages["httpserver:latest"] = struct{}{}
25
-
26
-	tmp, err := ioutil.TempDir("", "docker-http-server-test")
27
-	if err != nil {
28
-		return fmt.Errorf("could not build http server: %v", err)
29
-	}
30
-	defer os.RemoveAll(tmp)
31
-
32
-	goos := daemonPlatform
33
-	if goos == "" {
34
-		goos = "linux"
35
-	}
36
-	goarch := os.Getenv("DOCKER_ENGINE_GOARCH")
37
-	if goarch == "" {
38
-		goarch = "amd64"
39
-	}
40
-
41
-	goCmd, lookErr := exec.LookPath("go")
42
-	if lookErr != nil {
43
-		return fmt.Errorf("could not build http server: %v", lookErr)
44
-	}
45
-
46
-	cmd := exec.Command(goCmd, "build", "-o", filepath.Join(tmp, "httpserver"), "github.com/docker/docker/contrib/httpserver")
47
-	cmd.Env = append(os.Environ(), []string{
48
-		"CGO_ENABLED=0",
49
-		"GOOS=" + goos,
50
-		"GOARCH=" + goarch,
51
-	}...)
52
-	var out []byte
53
-	if out, err = cmd.CombinedOutput(); err != nil {
54
-		return fmt.Errorf("could not build http server: %s", string(out))
55
-	}
56
-
57
-	cpCmd, lookErr := exec.LookPath("cp")
58
-	if lookErr != nil {
59
-		return fmt.Errorf("could not build http server: %v", lookErr)
60
-	}
61
-	if out, err = exec.Command(cpCmd, "../contrib/httpserver/Dockerfile", filepath.Join(tmp, "Dockerfile")).CombinedOutput(); err != nil {
62
-		return fmt.Errorf("could not build http server: %v", string(out))
63
-	}
64
-
65
-	if out, err = exec.Command(dockerBinary, "build", "-q", "-t", "httpserver", tmp).CombinedOutput(); err != nil {
66
-		return fmt.Errorf("could not build http server: %v", string(out))
67
-	}
68
-	return nil
69
-}
70 1
deleted file mode 100644
... ...
@@ -1,143 +0,0 @@
1
-package main
2
-
3
-import (
4
-	"fmt"
5
-	"io/ioutil"
6
-	"os"
7
-	"os/exec"
8
-	"path/filepath"
9
-	"runtime"
10
-	"strings"
11
-	"sync"
12
-	"testing"
13
-
14
-	"github.com/docker/docker/integration-cli/fixtures/load"
15
-	"github.com/docker/docker/pkg/integration/checker"
16
-	"github.com/go-check/check"
17
-)
18
-
19
-func ensureFrozenImagesLinux(t *testing.T) {
20
-	images := []string{"busybox:latest", "hello-world:frozen", "debian:jessie"}
21
-	err := load.FrozenImagesLinux(dockerBinary, images...)
22
-	if err != nil {
23
-		t.Log(dockerCmdWithError("images"))
24
-		t.Fatalf("%+v", err)
25
-	}
26
-	for _, img := range images {
27
-		protectedImages[img] = struct{}{}
28
-	}
29
-}
30
-
31
-var ensureSyscallTestOnce sync.Once
32
-
33
-func ensureSyscallTest(c *check.C) {
34
-	var doIt bool
35
-	ensureSyscallTestOnce.Do(func() {
36
-		doIt = true
37
-	})
38
-	if !doIt {
39
-		return
40
-	}
41
-	protectedImages["syscall-test:latest"] = struct{}{}
42
-
43
-	// if no match, must build in docker, which is significantly slower
44
-	// (slower mostly because of the vfs graphdriver)
45
-	if daemonPlatform != runtime.GOOS {
46
-		ensureSyscallTestBuild(c)
47
-		return
48
-	}
49
-
50
-	tmp, err := ioutil.TempDir("", "syscall-test-build")
51
-	c.Assert(err, checker.IsNil, check.Commentf("couldn't create temp dir"))
52
-	defer os.RemoveAll(tmp)
53
-
54
-	gcc, err := exec.LookPath("gcc")
55
-	c.Assert(err, checker.IsNil, check.Commentf("could not find gcc"))
56
-
57
-	tests := []string{"userns", "ns", "acct", "setuid", "setgid", "socket", "raw"}
58
-	for _, test := range tests {
59
-		out, err := exec.Command(gcc, "-g", "-Wall", "-static", fmt.Sprintf("../contrib/syscall-test/%s.c", test), "-o", fmt.Sprintf("%s/%s-test", tmp, test)).CombinedOutput()
60
-		c.Assert(err, checker.IsNil, check.Commentf(string(out)))
61
-	}
62
-
63
-	if runtime.GOOS == "linux" && runtime.GOARCH == "amd64" {
64
-		out, err := exec.Command(gcc, "-s", "-m32", "-nostdlib", "../contrib/syscall-test/exit32.s", "-o", tmp+"/"+"exit32-test").CombinedOutput()
65
-		c.Assert(err, checker.IsNil, check.Commentf(string(out)))
66
-	}
67
-
68
-	dockerFile := filepath.Join(tmp, "Dockerfile")
69
-	content := []byte(`
70
-	FROM debian:jessie
71
-	COPY . /usr/bin/
72
-	`)
73
-	err = ioutil.WriteFile(dockerFile, content, 600)
74
-	c.Assert(err, checker.IsNil)
75
-
76
-	var buildArgs []string
77
-	if arg := os.Getenv("DOCKER_BUILD_ARGS"); strings.TrimSpace(arg) != "" {
78
-		buildArgs = strings.Split(arg, " ")
79
-	}
80
-	buildArgs = append(buildArgs, []string{"-q", "-t", "syscall-test", tmp}...)
81
-	buildArgs = append([]string{"build"}, buildArgs...)
82
-	dockerCmd(c, buildArgs...)
83
-}
84
-
85
-func ensureSyscallTestBuild(c *check.C) {
86
-	err := load.FrozenImagesLinux(dockerBinary, "buildpack-deps:jessie")
87
-	c.Assert(err, checker.IsNil)
88
-
89
-	var buildArgs []string
90
-	if arg := os.Getenv("DOCKER_BUILD_ARGS"); strings.TrimSpace(arg) != "" {
91
-		buildArgs = strings.Split(arg, " ")
92
-	}
93
-	buildArgs = append(buildArgs, []string{"-q", "-t", "syscall-test", "../contrib/syscall-test"}...)
94
-	buildArgs = append([]string{"build"}, buildArgs...)
95
-	dockerCmd(c, buildArgs...)
96
-}
97
-
98
-func ensureNNPTest(c *check.C) {
99
-	protectedImages["nnp-test:latest"] = struct{}{}
100
-	if daemonPlatform != runtime.GOOS {
101
-		ensureNNPTestBuild(c)
102
-		return
103
-	}
104
-
105
-	tmp, err := ioutil.TempDir("", "docker-nnp-test")
106
-	c.Assert(err, checker.IsNil)
107
-
108
-	gcc, err := exec.LookPath("gcc")
109
-	c.Assert(err, checker.IsNil, check.Commentf("could not find gcc"))
110
-
111
-	out, err := exec.Command(gcc, "-g", "-Wall", "-static", "../contrib/nnp-test/nnp-test.c", "-o", filepath.Join(tmp, "nnp-test")).CombinedOutput()
112
-	c.Assert(err, checker.IsNil, check.Commentf(string(out)))
113
-
114
-	dockerfile := filepath.Join(tmp, "Dockerfile")
115
-	content := `
116
-	FROM debian:jessie
117
-	COPY . /usr/bin
118
-	RUN chmod +s /usr/bin/nnp-test
119
-	`
120
-	err = ioutil.WriteFile(dockerfile, []byte(content), 600)
121
-	c.Assert(err, checker.IsNil, check.Commentf("could not write Dockerfile for nnp-test image"))
122
-
123
-	var buildArgs []string
124
-	if arg := os.Getenv("DOCKER_BUILD_ARGS"); strings.TrimSpace(arg) != "" {
125
-		buildArgs = strings.Split(arg, " ")
126
-	}
127
-	buildArgs = append(buildArgs, []string{"-q", "-t", "nnp-test", tmp}...)
128
-	buildArgs = append([]string{"build"}, buildArgs...)
129
-	dockerCmd(c, buildArgs...)
130
-}
131
-
132
-func ensureNNPTestBuild(c *check.C) {
133
-	err := load.FrozenImagesLinux(dockerBinary, "buildpack-deps:jessie")
134
-	c.Assert(err, checker.IsNil)
135
-
136
-	var buildArgs []string
137
-	if arg := os.Getenv("DOCKER_BUILD_ARGS"); strings.TrimSpace(arg) != "" {
138
-		buildArgs = strings.Split(arg, " ")
139
-	}
140
-	buildArgs = append(buildArgs, []string{"-q", "-t", "npp-test", "../contrib/nnp-test"}...)
141
-	buildArgs = append([]string{"build"}, buildArgs...)
142
-	dockerCmd(c, buildArgs...)
143
-}
144 1
new file mode 100644
... ...
@@ -0,0 +1,151 @@
0
+package main
1
+
2
+import (
3
+	"fmt"
4
+	"io/ioutil"
5
+	"os"
6
+	"os/exec"
7
+	"path/filepath"
8
+	"runtime"
9
+	"strings"
10
+	"sync"
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
+type testingT interface {
18
+	logT
19
+	Fatalf(string, ...interface{})
20
+}
21
+
22
+type logT interface {
23
+	Logf(string, ...interface{})
24
+}
25
+
26
+func ensureFrozenImagesLinux(t testingT) {
27
+	images := []string{"busybox:latest", "hello-world:frozen", "debian:jessie"}
28
+	err := load.FrozenImagesLinux(dockerBinary, images...)
29
+	if err != nil {
30
+		t.Logf(dockerCmdWithError("images"))
31
+		t.Fatalf("%+v", err)
32
+	}
33
+	for _, img := range images {
34
+		protectedImages[img] = struct{}{}
35
+	}
36
+}
37
+
38
+var ensureSyscallTestOnce sync.Once
39
+
40
+func ensureSyscallTest(c *check.C) {
41
+	var doIt bool
42
+	ensureSyscallTestOnce.Do(func() {
43
+		doIt = true
44
+	})
45
+	if !doIt {
46
+		return
47
+	}
48
+	protectedImages["syscall-test:latest"] = struct{}{}
49
+
50
+	// if no match, must build in docker, which is significantly slower
51
+	// (slower mostly because of the vfs graphdriver)
52
+	if daemonPlatform != runtime.GOOS {
53
+		ensureSyscallTestBuild(c)
54
+		return
55
+	}
56
+
57
+	tmp, err := ioutil.TempDir("", "syscall-test-build")
58
+	c.Assert(err, checker.IsNil, check.Commentf("couldn't create temp dir"))
59
+	defer os.RemoveAll(tmp)
60
+
61
+	gcc, err := exec.LookPath("gcc")
62
+	c.Assert(err, checker.IsNil, check.Commentf("could not find gcc"))
63
+
64
+	tests := []string{"userns", "ns", "acct", "setuid", "setgid", "socket", "raw"}
65
+	for _, test := range tests {
66
+		out, err := exec.Command(gcc, "-g", "-Wall", "-static", fmt.Sprintf("../contrib/syscall-test/%s.c", test), "-o", fmt.Sprintf("%s/%s-test", tmp, test)).CombinedOutput()
67
+		c.Assert(err, checker.IsNil, check.Commentf(string(out)))
68
+	}
69
+
70
+	if runtime.GOOS == "linux" && runtime.GOARCH == "amd64" {
71
+		out, err := exec.Command(gcc, "-s", "-m32", "-nostdlib", "../contrib/syscall-test/exit32.s", "-o", tmp+"/"+"exit32-test").CombinedOutput()
72
+		c.Assert(err, checker.IsNil, check.Commentf(string(out)))
73
+	}
74
+
75
+	dockerFile := filepath.Join(tmp, "Dockerfile")
76
+	content := []byte(`
77
+	FROM debian:jessie
78
+	COPY . /usr/bin/
79
+	`)
80
+	err = ioutil.WriteFile(dockerFile, content, 600)
81
+	c.Assert(err, checker.IsNil)
82
+
83
+	var buildArgs []string
84
+	if arg := os.Getenv("DOCKER_BUILD_ARGS"); strings.TrimSpace(arg) != "" {
85
+		buildArgs = strings.Split(arg, " ")
86
+	}
87
+	buildArgs = append(buildArgs, []string{"-q", "-t", "syscall-test", tmp}...)
88
+	buildArgs = append([]string{"build"}, buildArgs...)
89
+	dockerCmd(c, buildArgs...)
90
+}
91
+
92
+func ensureSyscallTestBuild(c *check.C) {
93
+	err := load.FrozenImagesLinux(dockerBinary, "buildpack-deps:jessie")
94
+	c.Assert(err, checker.IsNil)
95
+
96
+	var buildArgs []string
97
+	if arg := os.Getenv("DOCKER_BUILD_ARGS"); strings.TrimSpace(arg) != "" {
98
+		buildArgs = strings.Split(arg, " ")
99
+	}
100
+	buildArgs = append(buildArgs, []string{"-q", "-t", "syscall-test", "../contrib/syscall-test"}...)
101
+	buildArgs = append([]string{"build"}, buildArgs...)
102
+	dockerCmd(c, buildArgs...)
103
+}
104
+
105
+func ensureNNPTest(c *check.C) {
106
+	protectedImages["nnp-test:latest"] = struct{}{}
107
+	if daemonPlatform != runtime.GOOS {
108
+		ensureNNPTestBuild(c)
109
+		return
110
+	}
111
+
112
+	tmp, err := ioutil.TempDir("", "docker-nnp-test")
113
+	c.Assert(err, checker.IsNil)
114
+
115
+	gcc, err := exec.LookPath("gcc")
116
+	c.Assert(err, checker.IsNil, check.Commentf("could not find gcc"))
117
+
118
+	out, err := exec.Command(gcc, "-g", "-Wall", "-static", "../contrib/nnp-test/nnp-test.c", "-o", filepath.Join(tmp, "nnp-test")).CombinedOutput()
119
+	c.Assert(err, checker.IsNil, check.Commentf(string(out)))
120
+
121
+	dockerfile := filepath.Join(tmp, "Dockerfile")
122
+	content := `
123
+	FROM debian:jessie
124
+	COPY . /usr/bin
125
+	RUN chmod +s /usr/bin/nnp-test
126
+	`
127
+	err = ioutil.WriteFile(dockerfile, []byte(content), 600)
128
+	c.Assert(err, checker.IsNil, check.Commentf("could not write Dockerfile for nnp-test image"))
129
+
130
+	var buildArgs []string
131
+	if arg := os.Getenv("DOCKER_BUILD_ARGS"); strings.TrimSpace(arg) != "" {
132
+		buildArgs = strings.Split(arg, " ")
133
+	}
134
+	buildArgs = append(buildArgs, []string{"-q", "-t", "nnp-test", tmp}...)
135
+	buildArgs = append([]string{"build"}, buildArgs...)
136
+	dockerCmd(c, buildArgs...)
137
+}
138
+
139
+func ensureNNPTestBuild(c *check.C) {
140
+	err := load.FrozenImagesLinux(dockerBinary, "buildpack-deps:jessie")
141
+	c.Assert(err, checker.IsNil)
142
+
143
+	var buildArgs []string
144
+	if arg := os.Getenv("DOCKER_BUILD_ARGS"); strings.TrimSpace(arg) != "" {
145
+		buildArgs = strings.Split(arg, " ")
146
+	}
147
+	buildArgs = append(buildArgs, []string{"-q", "-t", "npp-test", "../contrib/nnp-test"}...)
148
+	buildArgs = append([]string{"build"}, buildArgs...)
149
+	dockerCmd(c, buildArgs...)
150
+}
0 151
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
deleted file mode 100644
... ...
@@ -1,177 +0,0 @@
1
-package main
2
-
3
-import (
4
-	"fmt"
5
-	"io/ioutil"
6
-	"net/http"
7
-	"os"
8
-	"os/exec"
9
-	"path/filepath"
10
-
11
-	"github.com/docker/distribution/digest"
12
-	"github.com/go-check/check"
13
-)
14
-
15
-const (
16
-	v2binary        = "registry-v2"
17
-	v2binarySchema1 = "registry-v2-schema1"
18
-)
19
-
20
-type testRegistryV2 struct {
21
-	cmd      *exec.Cmd
22
-	dir      string
23
-	auth     string
24
-	username string
25
-	password string
26
-	email    string
27
-}
28
-
29
-func newTestRegistryV2(c *check.C, schema1 bool, auth, tokenURL string) (*testRegistryV2, error) {
30
-	tmp, err := ioutil.TempDir("", "registry-test-")
31
-	if err != nil {
32
-		return nil, err
33
-	}
34
-	template := `version: 0.1
35
-loglevel: debug
36
-storage:
37
-    filesystem:
38
-        rootdirectory: %s
39
-http:
40
-    addr: %s
41
-%s`
42
-	var (
43
-		authTemplate string
44
-		username     string
45
-		password     string
46
-		email        string
47
-	)
48
-	switch auth {
49
-	case "htpasswd":
50
-		htpasswdPath := filepath.Join(tmp, "htpasswd")
51
-		// generated with: htpasswd -Bbn testuser testpassword
52
-		userpasswd := "testuser:$2y$05$sBsSqk0OpSD1uTZkHXc4FeJ0Z70wLQdAX/82UiHuQOKbNbBrzs63m"
53
-		username = "testuser"
54
-		password = "testpassword"
55
-		email = "test@test.org"
56
-		if err := ioutil.WriteFile(htpasswdPath, []byte(userpasswd), os.FileMode(0644)); err != nil {
57
-			return nil, err
58
-		}
59
-		authTemplate = fmt.Sprintf(`auth:
60
-    htpasswd:
61
-        realm: basic-realm
62
-        path: %s
63
-`, htpasswdPath)
64
-	case "token":
65
-		authTemplate = fmt.Sprintf(`auth:
66
-    token:
67
-        realm: %s
68
-        service: "registry"
69
-        issuer: "auth-registry"
70
-        rootcertbundle: "fixtures/registry/cert.pem"
71
-`, tokenURL)
72
-	}
73
-
74
-	confPath := filepath.Join(tmp, "config.yaml")
75
-	config, err := os.Create(confPath)
76
-	if err != nil {
77
-		return nil, err
78
-	}
79
-	defer config.Close()
80
-
81
-	if _, err := fmt.Fprintf(config, template, tmp, privateRegistryURL, authTemplate); err != nil {
82
-		os.RemoveAll(tmp)
83
-		return nil, err
84
-	}
85
-
86
-	binary := v2binary
87
-	if schema1 {
88
-		binary = v2binarySchema1
89
-	}
90
-	cmd := exec.Command(binary, confPath)
91
-	if err := cmd.Start(); err != nil {
92
-		os.RemoveAll(tmp)
93
-		if os.IsNotExist(err) {
94
-			c.Skip(err.Error())
95
-		}
96
-		return nil, err
97
-	}
98
-	return &testRegistryV2{
99
-		cmd:      cmd,
100
-		dir:      tmp,
101
-		auth:     auth,
102
-		username: username,
103
-		password: password,
104
-		email:    email,
105
-	}, nil
106
-}
107
-
108
-func (t *testRegistryV2) Ping() error {
109
-	// We always ping through HTTP for our test registry.
110
-	resp, err := http.Get(fmt.Sprintf("http://%s/v2/", privateRegistryURL))
111
-	if err != nil {
112
-		return err
113
-	}
114
-	resp.Body.Close()
115
-
116
-	fail := resp.StatusCode != http.StatusOK
117
-	if t.auth != "" {
118
-		// unauthorized is a _good_ status when pinging v2/ and it needs auth
119
-		fail = fail && resp.StatusCode != http.StatusUnauthorized
120
-	}
121
-	if fail {
122
-		return fmt.Errorf("registry ping replied with an unexpected status code %d", resp.StatusCode)
123
-	}
124
-	return nil
125
-}
126
-
127
-func (t *testRegistryV2) Close() {
128
-	t.cmd.Process.Kill()
129
-	os.RemoveAll(t.dir)
130
-}
131
-
132
-func (t *testRegistryV2) getBlobFilename(blobDigest digest.Digest) string {
133
-	// Split the digest into its algorithm and hex components.
134
-	dgstAlg, dgstHex := blobDigest.Algorithm(), blobDigest.Hex()
135
-
136
-	// The path to the target blob data looks something like:
137
-	//   baseDir + "docker/registry/v2/blobs/sha256/a3/a3ed...46d4/data"
138
-	return fmt.Sprintf("%s/docker/registry/v2/blobs/%s/%s/%s/data", t.dir, dgstAlg, dgstHex[:2], dgstHex)
139
-}
140
-
141
-func (t *testRegistryV2) readBlobContents(c *check.C, blobDigest digest.Digest) []byte {
142
-	// Load the target manifest blob.
143
-	manifestBlob, err := ioutil.ReadFile(t.getBlobFilename(blobDigest))
144
-	if err != nil {
145
-		c.Fatalf("unable to read blob: %s", err)
146
-	}
147
-
148
-	return manifestBlob
149
-}
150
-
151
-func (t *testRegistryV2) writeBlobContents(c *check.C, blobDigest digest.Digest, data []byte) {
152
-	if err := ioutil.WriteFile(t.getBlobFilename(blobDigest), data, os.FileMode(0644)); err != nil {
153
-		c.Fatalf("unable to write malicious data blob: %s", err)
154
-	}
155
-}
156
-
157
-func (t *testRegistryV2) tempMoveBlobData(c *check.C, blobDigest digest.Digest) (undo func()) {
158
-	tempFile, err := ioutil.TempFile("", "registry-temp-blob-")
159
-	if err != nil {
160
-		c.Fatalf("unable to get temporary blob file: %s", err)
161
-	}
162
-	tempFile.Close()
163
-
164
-	blobFilename := t.getBlobFilename(blobDigest)
165
-
166
-	// Move the existing data file aside, so that we can replace it with a
167
-	// another blob of data.
168
-	if err := os.Rename(blobFilename, tempFile.Name()); err != nil {
169
-		os.Remove(tempFile.Name())
170
-		c.Fatalf("unable to move data blob: %s", err)
171
-	}
172
-
173
-	return func() {
174
-		os.Rename(tempFile.Name(), blobFilename)
175
-		os.Remove(tempFile.Name())
176
-	}
177
-}
178 1
deleted file mode 100644
... ...
@@ -1,55 +0,0 @@
1
-package main
2
-
3
-import (
4
-	"net/http"
5
-	"net/http/httptest"
6
-	"regexp"
7
-	"strings"
8
-	"sync"
9
-
10
-	"github.com/go-check/check"
11
-)
12
-
13
-type handlerFunc func(w http.ResponseWriter, r *http.Request)
14
-
15
-type testRegistry struct {
16
-	server   *httptest.Server
17
-	hostport string
18
-	handlers map[string]handlerFunc
19
-	mu       sync.Mutex
20
-}
21
-
22
-func (tr *testRegistry) registerHandler(path string, h handlerFunc) {
23
-	tr.mu.Lock()
24
-	defer tr.mu.Unlock()
25
-	tr.handlers[path] = h
26
-}
27
-
28
-func newTestRegistry(c *check.C) (*testRegistry, error) {
29
-	testReg := &testRegistry{handlers: make(map[string]handlerFunc)}
30
-
31
-	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
32
-		url := r.URL.String()
33
-
34
-		var matched bool
35
-		var err error
36
-		for re, function := range testReg.handlers {
37
-			matched, err = regexp.MatchString(re, url)
38
-			if err != nil {
39
-				c.Fatal("Error with handler regexp")
40
-			}
41
-			if matched {
42
-				function(w, r)
43
-				break
44
-			}
45
-		}
46
-
47
-		if !matched {
48
-			c.Fatalf("Unable to match %s with regexp", url)
49
-		}
50
-	}))
51
-
52
-	testReg.server = ts
53
-	testReg.hostport = strings.Replace(ts.URL, "http://", "", 1)
54
-	return testReg, nil
55
-}
56 1
new file mode 100644
... ...
@@ -0,0 +1,55 @@
0
+package main
1
+
2
+import (
3
+	"net/http"
4
+	"net/http/httptest"
5
+	"regexp"
6
+	"strings"
7
+	"sync"
8
+
9
+	"github.com/go-check/check"
10
+)
11
+
12
+type handlerFunc func(w http.ResponseWriter, r *http.Request)
13
+
14
+type testRegistry struct {
15
+	server   *httptest.Server
16
+	hostport string
17
+	handlers map[string]handlerFunc
18
+	mu       sync.Mutex
19
+}
20
+
21
+func (tr *testRegistry) registerHandler(path string, h handlerFunc) {
22
+	tr.mu.Lock()
23
+	defer tr.mu.Unlock()
24
+	tr.handlers[path] = h
25
+}
26
+
27
+func newTestRegistry(c *check.C) (*testRegistry, error) {
28
+	testReg := &testRegistry{handlers: make(map[string]handlerFunc)}
29
+
30
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
31
+		url := r.URL.String()
32
+
33
+		var matched bool
34
+		var err error
35
+		for re, function := range testReg.handlers {
36
+			matched, err = regexp.MatchString(re, url)
37
+			if err != nil {
38
+				c.Fatal("Error with handler regexp")
39
+			}
40
+			if matched {
41
+				function(w, r)
42
+				break
43
+			}
44
+		}
45
+
46
+		if !matched {
47
+			c.Fatalf("Unable to match %s with regexp", url)
48
+		}
49
+	}))
50
+
51
+	testReg.server = ts
52
+	testReg.hostport = strings.Replace(ts.URL, "http://", "", 1)
53
+	return testReg, nil
54
+}
0 55
new file mode 100644
... ...
@@ -0,0 +1,177 @@
0
+package main
1
+
2
+import (
3
+	"fmt"
4
+	"io/ioutil"
5
+	"net/http"
6
+	"os"
7
+	"os/exec"
8
+	"path/filepath"
9
+
10
+	"github.com/docker/distribution/digest"
11
+	"github.com/go-check/check"
12
+)
13
+
14
+const (
15
+	v2binary        = "registry-v2"
16
+	v2binarySchema1 = "registry-v2-schema1"
17
+)
18
+
19
+type testRegistryV2 struct {
20
+	cmd      *exec.Cmd
21
+	dir      string
22
+	auth     string
23
+	username string
24
+	password string
25
+	email    string
26
+}
27
+
28
+func newTestRegistryV2(c *check.C, schema1 bool, auth, tokenURL string) (*testRegistryV2, error) {
29
+	tmp, err := ioutil.TempDir("", "registry-test-")
30
+	if err != nil {
31
+		return nil, err
32
+	}
33
+	template := `version: 0.1
34
+loglevel: debug
35
+storage:
36
+    filesystem:
37
+        rootdirectory: %s
38
+http:
39
+    addr: %s
40
+%s`
41
+	var (
42
+		authTemplate string
43
+		username     string
44
+		password     string
45
+		email        string
46
+	)
47
+	switch auth {
48
+	case "htpasswd":
49
+		htpasswdPath := filepath.Join(tmp, "htpasswd")
50
+		// generated with: htpasswd -Bbn testuser testpassword
51
+		userpasswd := "testuser:$2y$05$sBsSqk0OpSD1uTZkHXc4FeJ0Z70wLQdAX/82UiHuQOKbNbBrzs63m"
52
+		username = "testuser"
53
+		password = "testpassword"
54
+		email = "test@test.org"
55
+		if err := ioutil.WriteFile(htpasswdPath, []byte(userpasswd), os.FileMode(0644)); err != nil {
56
+			return nil, err
57
+		}
58
+		authTemplate = fmt.Sprintf(`auth:
59
+    htpasswd:
60
+        realm: basic-realm
61
+        path: %s
62
+`, htpasswdPath)
63
+	case "token":
64
+		authTemplate = fmt.Sprintf(`auth:
65
+    token:
66
+        realm: %s
67
+        service: "registry"
68
+        issuer: "auth-registry"
69
+        rootcertbundle: "fixtures/registry/cert.pem"
70
+`, tokenURL)
71
+	}
72
+
73
+	confPath := filepath.Join(tmp, "config.yaml")
74
+	config, err := os.Create(confPath)
75
+	if err != nil {
76
+		return nil, err
77
+	}
78
+	defer config.Close()
79
+
80
+	if _, err := fmt.Fprintf(config, template, tmp, privateRegistryURL, authTemplate); err != nil {
81
+		os.RemoveAll(tmp)
82
+		return nil, err
83
+	}
84
+
85
+	binary := v2binary
86
+	if schema1 {
87
+		binary = v2binarySchema1
88
+	}
89
+	cmd := exec.Command(binary, confPath)
90
+	if err := cmd.Start(); err != nil {
91
+		os.RemoveAll(tmp)
92
+		if os.IsNotExist(err) {
93
+			c.Skip(err.Error())
94
+		}
95
+		return nil, err
96
+	}
97
+	return &testRegistryV2{
98
+		cmd:      cmd,
99
+		dir:      tmp,
100
+		auth:     auth,
101
+		username: username,
102
+		password: password,
103
+		email:    email,
104
+	}, nil
105
+}
106
+
107
+func (t *testRegistryV2) Ping() error {
108
+	// We always ping through HTTP for our test registry.
109
+	resp, err := http.Get(fmt.Sprintf("http://%s/v2/", privateRegistryURL))
110
+	if err != nil {
111
+		return err
112
+	}
113
+	resp.Body.Close()
114
+
115
+	fail := resp.StatusCode != http.StatusOK
116
+	if t.auth != "" {
117
+		// unauthorized is a _good_ status when pinging v2/ and it needs auth
118
+		fail = fail && resp.StatusCode != http.StatusUnauthorized
119
+	}
120
+	if fail {
121
+		return fmt.Errorf("registry ping replied with an unexpected status code %d", resp.StatusCode)
122
+	}
123
+	return nil
124
+}
125
+
126
+func (t *testRegistryV2) Close() {
127
+	t.cmd.Process.Kill()
128
+	os.RemoveAll(t.dir)
129
+}
130
+
131
+func (t *testRegistryV2) getBlobFilename(blobDigest digest.Digest) string {
132
+	// Split the digest into its algorithm and hex components.
133
+	dgstAlg, dgstHex := blobDigest.Algorithm(), blobDigest.Hex()
134
+
135
+	// The path to the target blob data looks something like:
136
+	//   baseDir + "docker/registry/v2/blobs/sha256/a3/a3ed...46d4/data"
137
+	return fmt.Sprintf("%s/docker/registry/v2/blobs/%s/%s/%s/data", t.dir, dgstAlg, dgstHex[:2], dgstHex)
138
+}
139
+
140
+func (t *testRegistryV2) readBlobContents(c *check.C, blobDigest digest.Digest) []byte {
141
+	// Load the target manifest blob.
142
+	manifestBlob, err := ioutil.ReadFile(t.getBlobFilename(blobDigest))
143
+	if err != nil {
144
+		c.Fatalf("unable to read blob: %s", err)
145
+	}
146
+
147
+	return manifestBlob
148
+}
149
+
150
+func (t *testRegistryV2) writeBlobContents(c *check.C, blobDigest digest.Digest, data []byte) {
151
+	if err := ioutil.WriteFile(t.getBlobFilename(blobDigest), data, os.FileMode(0644)); err != nil {
152
+		c.Fatalf("unable to write malicious data blob: %s", err)
153
+	}
154
+}
155
+
156
+func (t *testRegistryV2) tempMoveBlobData(c *check.C, blobDigest digest.Digest) (undo func()) {
157
+	tempFile, err := ioutil.TempFile("", "registry-temp-blob-")
158
+	if err != nil {
159
+		c.Fatalf("unable to get temporary blob file: %s", err)
160
+	}
161
+	tempFile.Close()
162
+
163
+	blobFilename := t.getBlobFilename(blobDigest)
164
+
165
+	// Move the existing data file aside, so that we can replace it with a
166
+	// another blob of data.
167
+	if err := os.Rename(blobFilename, tempFile.Name()); err != nil {
168
+		os.Remove(tempFile.Name())
169
+		c.Fatalf("unable to move data blob: %s", err)
170
+	}
171
+
172
+	return func() {
173
+		os.Rename(tempFile.Name(), blobFilename)
174
+		os.Remove(tempFile.Name())
175
+	}
176
+}
0 177
deleted file mode 100644
... ...
@@ -1,11 +0,0 @@
1
-package main
2
-
3
-// sleepCommandForDaemonPlatform is a helper function that determines what
4
-// the command is for a sleeping container based on the daemon platform.
5
-// The Windows busybox image does not have a `top` command.
6
-func sleepCommandForDaemonPlatform() []string {
7
-	if daemonPlatform == "windows" {
8
-		return []string{"sleep", "240"}
9
-	}
10
-	return []string{"top"}
11
-}
12 1
deleted file mode 100644
... ...
@@ -1,8 +0,0 @@
1
-// +build !test_no_exec
2
-
3
-package main
4
-
5
-const (
6
-	// indicates docker daemon tested supports 'docker exec'
7
-	supportsExec = true
8
-)
9 1
new file mode 100644
... ...
@@ -0,0 +1,8 @@
0
+// +build !test_no_exec
1
+
2
+package main
3
+
4
+const (
5
+	// indicates docker daemon tested supports 'docker exec'
6
+	supportsExec = true
7
+)
0 8
deleted file mode 100644
... ...
@@ -1,8 +0,0 @@
1
-// +build test_no_exec
2
-
3
-package main
4
-
5
-const (
6
-	// indicates docker daemon tested supports 'docker exec'
7
-	supportsExec = false
8
-)
9 1
new file mode 100644
... ...
@@ -0,0 +1,8 @@
0
+// +build test_no_exec
1
+
2
+package main
3
+
4
+const (
5
+	// indicates docker daemon tested supports 'docker exec'
6
+	supportsExec = false
7
+)
0 8
deleted file mode 100644
... ...
@@ -1,8 +0,0 @@
1
-// +build !seccomp
2
-
3
-package main
4
-
5
-const (
6
-	// indicates docker daemon built with seccomp support
7
-	supportsSeccomp = false
8
-)
9 1
new file mode 100644
... ...
@@ -0,0 +1,8 @@
0
+// +build !seccomp
1
+
2
+package main
3
+
4
+const (
5
+	// indicates docker daemon built with seccomp support
6
+	supportsSeccomp = false
7
+)
0 8
deleted file mode 100644
... ...
@@ -1,8 +0,0 @@
1
-// +build seccomp
2
-
3
-package main
4
-
5
-const (
6
-	// indicates docker daemon built with seccomp support
7
-	supportsSeccomp = true
8
-)
9 1
new file mode 100644
... ...
@@ -0,0 +1,8 @@
0
+// +build seccomp
1
+
2
+package main
3
+
4
+const (
5
+	// indicates docker daemon built with seccomp support
6
+	supportsSeccomp = true
7
+)
0 8
new file mode 100644
... ...
@@ -0,0 +1,11 @@
0
+package main
1
+
2
+// sleepCommandForDaemonPlatform is a helper function that determines what
3
+// the command is for a sleeping container based on the daemon platform.
4
+// The Windows busybox image does not have a `top` command.
5
+func sleepCommandForDaemonPlatform() []string {
6
+	if daemonPlatform == "windows" {
7
+		return []string{"sleep", "240"}
8
+	}
9
+	return []string{"top"}
10
+}
0 11
deleted file mode 100644
... ...
@@ -1,14 +0,0 @@
1
-// +build !windows
2
-
3
-package main
4
-
5
-const (
6
-	// identifies if test suite is running on a unix platform
7
-	isUnixCli = true
8
-
9
-	expectedFileChmod = "-rw-r--r--"
10
-
11
-	// On Unix variants, the busybox image comes with the `top` command which
12
-	// runs indefinitely while still being interruptible by a signal.
13
-	defaultSleepImage = "busybox"
14
-)
15 1
new file mode 100644
... ...
@@ -0,0 +1,14 @@
0
+// +build !windows
1
+
2
+package main
3
+
4
+const (
5
+	// identifies if test suite is running on a unix platform
6
+	isUnixCli = true
7
+
8
+	expectedFileChmod = "-rw-r--r--"
9
+
10
+	// On Unix variants, the busybox image comes with the `top` command which
11
+	// runs indefinitely while still being interruptible by a signal.
12
+	defaultSleepImage = "busybox"
13
+)
0 14
deleted file mode 100644
... ...
@@ -1,15 +0,0 @@
1
-// +build windows
2
-
3
-package main
4
-
5
-const (
6
-	// identifies if test suite is running on a unix platform
7
-	isUnixCli = false
8
-
9
-	// this is the expected file permission set on windows: gh#11395
10
-	expectedFileChmod = "-rwxr-xr-x"
11
-
12
-	// On Windows, the busybox image doesn't have the `top` command, so we rely
13
-	// on `sleep` with a high duration.
14
-	defaultSleepImage = "busybox"
15
-)
16 1
new file mode 100644
... ...
@@ -0,0 +1,15 @@
0
+// +build windows
1
+
2
+package main
3
+
4
+const (
5
+	// identifies if test suite is running on a unix platform
6
+	isUnixCli = false
7
+
8
+	// this is the expected file permission set on windows: gh#11395
9
+	expectedFileChmod = "-rwxr-xr-x"
10
+
11
+	// On Windows, the busybox image doesn't have the `top` command, so we rely
12
+	// on `sleep` with a high duration.
13
+	defaultSleepImage = "busybox"
14
+)
0 15
deleted file mode 100644
... ...
@@ -1,344 +0,0 @@
1
-package main
2
-
3
-import (
4
-	"fmt"
5
-	"io/ioutil"
6
-	"net"
7
-	"net/http"
8
-	"os"
9
-	"os/exec"
10
-	"path/filepath"
11
-	"strings"
12
-	"time"
13
-
14
-	cliconfig "github.com/docker/docker/cli/config"
15
-	"github.com/docker/docker/pkg/integration/checker"
16
-	"github.com/docker/go-connections/tlsconfig"
17
-	"github.com/go-check/check"
18
-)
19
-
20
-var notaryBinary = "notary"
21
-var notaryServerBinary = "notary-server"
22
-
23
-type keyPair struct {
24
-	Public  string
25
-	Private string
26
-}
27
-
28
-type testNotary struct {
29
-	cmd  *exec.Cmd
30
-	dir  string
31
-	keys []keyPair
32
-}
33
-
34
-const notaryHost = "localhost:4443"
35
-const notaryURL = "https://" + notaryHost
36
-
37
-func newTestNotary(c *check.C) (*testNotary, error) {
38
-	// generate server config
39
-	template := `{
40
-	"server": {
41
-		"http_addr": "%s",
42
-		"tls_key_file": "%s",
43
-		"tls_cert_file": "%s"
44
-	},
45
-	"trust_service": {
46
-		"type": "local",
47
-		"hostname": "",
48
-		"port": "",
49
-		"key_algorithm": "ed25519"
50
-	},
51
-	"logging": {
52
-		"level": "debug"
53
-	},
54
-	"storage": {
55
-        "backend": "memory"
56
-    }
57
-}`
58
-	tmp, err := ioutil.TempDir("", "notary-test-")
59
-	if err != nil {
60
-		return nil, err
61
-	}
62
-	confPath := filepath.Join(tmp, "config.json")
63
-	config, err := os.Create(confPath)
64
-	if err != nil {
65
-		return nil, err
66
-	}
67
-	defer config.Close()
68
-
69
-	workingDir, err := os.Getwd()
70
-	if err != nil {
71
-		return nil, err
72
-	}
73
-	if _, err := fmt.Fprintf(config, template, notaryHost, filepath.Join(workingDir, "fixtures/notary/localhost.key"), filepath.Join(workingDir, "fixtures/notary/localhost.cert")); err != nil {
74
-		os.RemoveAll(tmp)
75
-		return nil, err
76
-	}
77
-
78
-	// generate client config
79
-	clientConfPath := filepath.Join(tmp, "client-config.json")
80
-	clientConfig, err := os.Create(clientConfPath)
81
-	if err != nil {
82
-		return nil, err
83
-	}
84
-	defer clientConfig.Close()
85
-
86
-	template = `{
87
-	"trust_dir" : "%s",
88
-	"remote_server": {
89
-		"url": "%s",
90
-		"skipTLSVerify": true
91
-	}
92
-}`
93
-	if _, err = fmt.Fprintf(clientConfig, template, filepath.Join(cliconfig.Dir(), "trust"), notaryURL); err != nil {
94
-		os.RemoveAll(tmp)
95
-		return nil, err
96
-	}
97
-
98
-	// load key fixture filenames
99
-	var keys []keyPair
100
-	for i := 1; i < 5; i++ {
101
-		keys = append(keys, keyPair{
102
-			Public:  filepath.Join(workingDir, fmt.Sprintf("fixtures/notary/delgkey%v.crt", i)),
103
-			Private: filepath.Join(workingDir, fmt.Sprintf("fixtures/notary/delgkey%v.key", i)),
104
-		})
105
-	}
106
-
107
-	// run notary-server
108
-	cmd := exec.Command(notaryServerBinary, "-config", confPath)
109
-	if err := cmd.Start(); err != nil {
110
-		os.RemoveAll(tmp)
111
-		if os.IsNotExist(err) {
112
-			c.Skip(err.Error())
113
-		}
114
-		return nil, err
115
-	}
116
-
117
-	testNotary := &testNotary{
118
-		cmd:  cmd,
119
-		dir:  tmp,
120
-		keys: keys,
121
-	}
122
-
123
-	// Wait for notary to be ready to serve requests.
124
-	for i := 1; i <= 20; i++ {
125
-		if err = testNotary.Ping(); err == nil {
126
-			break
127
-		}
128
-		time.Sleep(10 * time.Millisecond * time.Duration(i*i))
129
-	}
130
-
131
-	if err != nil {
132
-		c.Fatalf("Timeout waiting for test notary to become available: %s", err)
133
-	}
134
-
135
-	return testNotary, nil
136
-}
137
-
138
-func (t *testNotary) Ping() error {
139
-	tlsConfig := tlsconfig.ClientDefault()
140
-	tlsConfig.InsecureSkipVerify = true
141
-	client := http.Client{
142
-		Transport: &http.Transport{
143
-			Proxy: http.ProxyFromEnvironment,
144
-			Dial: (&net.Dialer{
145
-				Timeout:   30 * time.Second,
146
-				KeepAlive: 30 * time.Second,
147
-			}).Dial,
148
-			TLSHandshakeTimeout: 10 * time.Second,
149
-			TLSClientConfig:     tlsConfig,
150
-		},
151
-	}
152
-	resp, err := client.Get(fmt.Sprintf("%s/v2/", notaryURL))
153
-	if err != nil {
154
-		return err
155
-	}
156
-	if resp.StatusCode != http.StatusOK {
157
-		return fmt.Errorf("notary ping replied with an unexpected status code %d", resp.StatusCode)
158
-	}
159
-	return nil
160
-}
161
-
162
-func (t *testNotary) Close() {
163
-	t.cmd.Process.Kill()
164
-	os.RemoveAll(t.dir)
165
-}
166
-
167
-func (s *DockerTrustSuite) trustedCmd(cmd *exec.Cmd) {
168
-	pwd := "12345678"
169
-	trustCmdEnv(cmd, notaryURL, pwd, pwd)
170
-}
171
-
172
-func (s *DockerTrustSuite) trustedCmdWithServer(cmd *exec.Cmd, server string) {
173
-	pwd := "12345678"
174
-	trustCmdEnv(cmd, server, pwd, pwd)
175
-}
176
-
177
-func (s *DockerTrustSuite) trustedCmdWithPassphrases(cmd *exec.Cmd, rootPwd, repositoryPwd string) {
178
-	trustCmdEnv(cmd, notaryURL, rootPwd, repositoryPwd)
179
-}
180
-
181
-func trustCmdEnv(cmd *exec.Cmd, server, rootPwd, repositoryPwd string) {
182
-	env := []string{
183
-		"DOCKER_CONTENT_TRUST=1",
184
-		fmt.Sprintf("DOCKER_CONTENT_TRUST_SERVER=%s", server),
185
-		fmt.Sprintf("DOCKER_CONTENT_TRUST_ROOT_PASSPHRASE=%s", rootPwd),
186
-		fmt.Sprintf("DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE=%s", repositoryPwd),
187
-	}
188
-	cmd.Env = append(os.Environ(), env...)
189
-}
190
-
191
-func (s *DockerTrustSuite) setupTrustedImage(c *check.C, name string) string {
192
-	repoName := fmt.Sprintf("%v/dockercli/%s:latest", privateRegistryURL, name)
193
-	// tag the image and upload it to the private registry
194
-	dockerCmd(c, "tag", "busybox", repoName)
195
-
196
-	pushCmd := exec.Command(dockerBinary, "push", repoName)
197
-	s.trustedCmd(pushCmd)
198
-	out, _, err := runCommandWithOutput(pushCmd)
199
-
200
-	if err != nil {
201
-		c.Fatalf("Error running trusted push: %s\n%s", err, out)
202
-	}
203
-	if !strings.Contains(string(out), "Signing and pushing trust metadata") {
204
-		c.Fatalf("Missing expected output on trusted push:\n%s", out)
205
-	}
206
-
207
-	if out, status := dockerCmd(c, "rmi", repoName); status != 0 {
208
-		c.Fatalf("Error removing image %q\n%s", repoName, out)
209
-	}
210
-
211
-	return repoName
212
-}
213
-
214
-func (s *DockerTrustSuite) setupTrustedplugin(c *check.C, source, name string) string {
215
-	repoName := fmt.Sprintf("%v/dockercli/%s:latest", privateRegistryURL, name)
216
-	// tag the image and upload it to the private registry
217
-	dockerCmd(c, "plugin", "install", "--grant-all-permissions", "--alias", repoName, source)
218
-
219
-	pushCmd := exec.Command(dockerBinary, "plugin", "push", repoName)
220
-	s.trustedCmd(pushCmd)
221
-	out, _, err := runCommandWithOutput(pushCmd)
222
-
223
-	if err != nil {
224
-		c.Fatalf("Error running trusted plugin push: %s\n%s", err, out)
225
-	}
226
-	if !strings.Contains(string(out), "Signing and pushing trust metadata") {
227
-		c.Fatalf("Missing expected output on trusted push:\n%s", out)
228
-	}
229
-
230
-	if out, status := dockerCmd(c, "plugin", "rm", "-f", repoName); status != 0 {
231
-		c.Fatalf("Error removing plugin %q\n%s", repoName, out)
232
-	}
233
-
234
-	return repoName
235
-}
236
-
237
-func notaryClientEnv(cmd *exec.Cmd) {
238
-	pwd := "12345678"
239
-	env := []string{
240
-		fmt.Sprintf("NOTARY_ROOT_PASSPHRASE=%s", pwd),
241
-		fmt.Sprintf("NOTARY_TARGETS_PASSPHRASE=%s", pwd),
242
-		fmt.Sprintf("NOTARY_SNAPSHOT_PASSPHRASE=%s", pwd),
243
-		fmt.Sprintf("NOTARY_DELEGATION_PASSPHRASE=%s", pwd),
244
-	}
245
-	cmd.Env = append(os.Environ(), env...)
246
-}
247
-
248
-func (s *DockerTrustSuite) notaryInitRepo(c *check.C, repoName string) {
249
-	initCmd := exec.Command(notaryBinary, "-c", filepath.Join(s.not.dir, "client-config.json"), "init", repoName)
250
-	notaryClientEnv(initCmd)
251
-	out, _, err := runCommandWithOutput(initCmd)
252
-	if err != nil {
253
-		c.Fatalf("Error initializing notary repository: %s\n", out)
254
-	}
255
-}
256
-
257
-func (s *DockerTrustSuite) notaryCreateDelegation(c *check.C, repoName, role string, pubKey string, paths ...string) {
258
-	pathsArg := "--all-paths"
259
-	if len(paths) > 0 {
260
-		pathsArg = "--paths=" + strings.Join(paths, ",")
261
-	}
262
-
263
-	delgCmd := exec.Command(notaryBinary, "-c", filepath.Join(s.not.dir, "client-config.json"),
264
-		"delegation", "add", repoName, role, pubKey, pathsArg)
265
-	notaryClientEnv(delgCmd)
266
-	out, _, err := runCommandWithOutput(delgCmd)
267
-	if err != nil {
268
-		c.Fatalf("Error adding %s role to notary repository: %s\n", role, out)
269
-	}
270
-}
271
-
272
-func (s *DockerTrustSuite) notaryPublish(c *check.C, repoName string) {
273
-	pubCmd := exec.Command(notaryBinary, "-c", filepath.Join(s.not.dir, "client-config.json"), "publish", repoName)
274
-	notaryClientEnv(pubCmd)
275
-	out, _, err := runCommandWithOutput(pubCmd)
276
-	if err != nil {
277
-		c.Fatalf("Error publishing notary repository: %s\n", out)
278
-	}
279
-}
280
-
281
-func (s *DockerTrustSuite) notaryImportKey(c *check.C, repoName, role string, privKey string) {
282
-	impCmd := exec.Command(notaryBinary, "-c", filepath.Join(s.not.dir, "client-config.json"), "key",
283
-		"import", privKey, "-g", repoName, "-r", role)
284
-	notaryClientEnv(impCmd)
285
-	out, _, err := runCommandWithOutput(impCmd)
286
-	if err != nil {
287
-		c.Fatalf("Error importing key to notary repository: %s\n", out)
288
-	}
289
-}
290
-
291
-func (s *DockerTrustSuite) notaryListTargetsInRole(c *check.C, repoName, role string) map[string]string {
292
-	listCmd := exec.Command(notaryBinary, "-c", filepath.Join(s.not.dir, "client-config.json"), "list",
293
-		repoName, "-r", role)
294
-	notaryClientEnv(listCmd)
295
-	out, _, err := runCommandWithOutput(listCmd)
296
-	if err != nil {
297
-		c.Fatalf("Error listing targets in notary repository: %s\n", out)
298
-	}
299
-
300
-	// should look something like:
301
-	//    NAME                                 DIGEST                                SIZE (BYTES)    ROLE
302
-	// ------------------------------------------------------------------------------------------------------
303
-	//   latest   24a36bbc059b1345b7e8be0df20f1b23caa3602e85d42fff7ecd9d0bd255de56   1377           targets
304
-
305
-	targets := make(map[string]string)
306
-
307
-	// no target
308
-	lines := strings.Split(strings.TrimSpace(out), "\n")
309
-	if len(lines) == 1 && strings.Contains(out, "No targets present in this repository.") {
310
-		return targets
311
-	}
312
-
313
-	// otherwise, there is at least one target
314
-	c.Assert(len(lines), checker.GreaterOrEqualThan, 3)
315
-
316
-	for _, line := range lines[2:] {
317
-		tokens := strings.Fields(line)
318
-		c.Assert(tokens, checker.HasLen, 4)
319
-		targets[tokens[0]] = tokens[3]
320
-	}
321
-
322
-	return targets
323
-}
324
-
325
-func (s *DockerTrustSuite) assertTargetInRoles(c *check.C, repoName, target string, roles ...string) {
326
-	// check all the roles
327
-	for _, role := range roles {
328
-		targets := s.notaryListTargetsInRole(c, repoName, role)
329
-		roleName, ok := targets[target]
330
-		c.Assert(ok, checker.True)
331
-		c.Assert(roleName, checker.Equals, role)
332
-	}
333
-}
334
-
335
-func (s *DockerTrustSuite) assertTargetNotInRoles(c *check.C, repoName, target string, roles ...string) {
336
-	targets := s.notaryListTargetsInRole(c, repoName, "targets")
337
-
338
-	roleName, ok := targets[target]
339
-	if ok {
340
-		for _, role := range roles {
341
-			c.Assert(roleName, checker.Not(checker.Equals), role)
342
-		}
343
-	}
344
-}
345 1
new file mode 100644
... ...
@@ -0,0 +1,344 @@
0
+package main
1
+
2
+import (
3
+	"fmt"
4
+	"io/ioutil"
5
+	"net"
6
+	"net/http"
7
+	"os"
8
+	"os/exec"
9
+	"path/filepath"
10
+	"strings"
11
+	"time"
12
+
13
+	cliconfig "github.com/docker/docker/cli/config"
14
+	"github.com/docker/docker/pkg/integration/checker"
15
+	"github.com/docker/go-connections/tlsconfig"
16
+	"github.com/go-check/check"
17
+)
18
+
19
+var notaryBinary = "notary"
20
+var notaryServerBinary = "notary-server"
21
+
22
+type keyPair struct {
23
+	Public  string
24
+	Private string
25
+}
26
+
27
+type testNotary struct {
28
+	cmd  *exec.Cmd
29
+	dir  string
30
+	keys []keyPair
31
+}
32
+
33
+const notaryHost = "localhost:4443"
34
+const notaryURL = "https://" + notaryHost
35
+
36
+func newTestNotary(c *check.C) (*testNotary, error) {
37
+	// generate server config
38
+	template := `{
39
+	"server": {
40
+		"http_addr": "%s",
41
+		"tls_key_file": "%s",
42
+		"tls_cert_file": "%s"
43
+	},
44
+	"trust_service": {
45
+		"type": "local",
46
+		"hostname": "",
47
+		"port": "",
48
+		"key_algorithm": "ed25519"
49
+	},
50
+	"logging": {
51
+		"level": "debug"
52
+	},
53
+	"storage": {
54
+        "backend": "memory"
55
+    }
56
+}`
57
+	tmp, err := ioutil.TempDir("", "notary-test-")
58
+	if err != nil {
59
+		return nil, err
60
+	}
61
+	confPath := filepath.Join(tmp, "config.json")
62
+	config, err := os.Create(confPath)
63
+	if err != nil {
64
+		return nil, err
65
+	}
66
+	defer config.Close()
67
+
68
+	workingDir, err := os.Getwd()
69
+	if err != nil {
70
+		return nil, err
71
+	}
72
+	if _, err := fmt.Fprintf(config, template, notaryHost, filepath.Join(workingDir, "fixtures/notary/localhost.key"), filepath.Join(workingDir, "fixtures/notary/localhost.cert")); err != nil {
73
+		os.RemoveAll(tmp)
74
+		return nil, err
75
+	}
76
+
77
+	// generate client config
78
+	clientConfPath := filepath.Join(tmp, "client-config.json")
79
+	clientConfig, err := os.Create(clientConfPath)
80
+	if err != nil {
81
+		return nil, err
82
+	}
83
+	defer clientConfig.Close()
84
+
85
+	template = `{
86
+	"trust_dir" : "%s",
87
+	"remote_server": {
88
+		"url": "%s",
89
+		"skipTLSVerify": true
90
+	}
91
+}`
92
+	if _, err = fmt.Fprintf(clientConfig, template, filepath.Join(cliconfig.Dir(), "trust"), notaryURL); err != nil {
93
+		os.RemoveAll(tmp)
94
+		return nil, err
95
+	}
96
+
97
+	// load key fixture filenames
98
+	var keys []keyPair
99
+	for i := 1; i < 5; i++ {
100
+		keys = append(keys, keyPair{
101
+			Public:  filepath.Join(workingDir, fmt.Sprintf("fixtures/notary/delgkey%v.crt", i)),
102
+			Private: filepath.Join(workingDir, fmt.Sprintf("fixtures/notary/delgkey%v.key", i)),
103
+		})
104
+	}
105
+
106
+	// run notary-server
107
+	cmd := exec.Command(notaryServerBinary, "-config", confPath)
108
+	if err := cmd.Start(); err != nil {
109
+		os.RemoveAll(tmp)
110
+		if os.IsNotExist(err) {
111
+			c.Skip(err.Error())
112
+		}
113
+		return nil, err
114
+	}
115
+
116
+	testNotary := &testNotary{
117
+		cmd:  cmd,
118
+		dir:  tmp,
119
+		keys: keys,
120
+	}
121
+
122
+	// Wait for notary to be ready to serve requests.
123
+	for i := 1; i <= 20; i++ {
124
+		if err = testNotary.Ping(); err == nil {
125
+			break
126
+		}
127
+		time.Sleep(10 * time.Millisecond * time.Duration(i*i))
128
+	}
129
+
130
+	if err != nil {
131
+		c.Fatalf("Timeout waiting for test notary to become available: %s", err)
132
+	}
133
+
134
+	return testNotary, nil
135
+}
136
+
137
+func (t *testNotary) Ping() error {
138
+	tlsConfig := tlsconfig.ClientDefault()
139
+	tlsConfig.InsecureSkipVerify = true
140
+	client := http.Client{
141
+		Transport: &http.Transport{
142
+			Proxy: http.ProxyFromEnvironment,
143
+			Dial: (&net.Dialer{
144
+				Timeout:   30 * time.Second,
145
+				KeepAlive: 30 * time.Second,
146
+			}).Dial,
147
+			TLSHandshakeTimeout: 10 * time.Second,
148
+			TLSClientConfig:     tlsConfig,
149
+		},
150
+	}
151
+	resp, err := client.Get(fmt.Sprintf("%s/v2/", notaryURL))
152
+	if err != nil {
153
+		return err
154
+	}
155
+	if resp.StatusCode != http.StatusOK {
156
+		return fmt.Errorf("notary ping replied with an unexpected status code %d", resp.StatusCode)
157
+	}
158
+	return nil
159
+}
160
+
161
+func (t *testNotary) Close() {
162
+	t.cmd.Process.Kill()
163
+	os.RemoveAll(t.dir)
164
+}
165
+
166
+func (s *DockerTrustSuite) trustedCmd(cmd *exec.Cmd) {
167
+	pwd := "12345678"
168
+	trustCmdEnv(cmd, notaryURL, pwd, pwd)
169
+}
170
+
171
+func (s *DockerTrustSuite) trustedCmdWithServer(cmd *exec.Cmd, server string) {
172
+	pwd := "12345678"
173
+	trustCmdEnv(cmd, server, pwd, pwd)
174
+}
175
+
176
+func (s *DockerTrustSuite) trustedCmdWithPassphrases(cmd *exec.Cmd, rootPwd, repositoryPwd string) {
177
+	trustCmdEnv(cmd, notaryURL, rootPwd, repositoryPwd)
178
+}
179
+
180
+func trustCmdEnv(cmd *exec.Cmd, server, rootPwd, repositoryPwd string) {
181
+	env := []string{
182
+		"DOCKER_CONTENT_TRUST=1",
183
+		fmt.Sprintf("DOCKER_CONTENT_TRUST_SERVER=%s", server),
184
+		fmt.Sprintf("DOCKER_CONTENT_TRUST_ROOT_PASSPHRASE=%s", rootPwd),
185
+		fmt.Sprintf("DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE=%s", repositoryPwd),
186
+	}
187
+	cmd.Env = append(os.Environ(), env...)
188
+}
189
+
190
+func (s *DockerTrustSuite) setupTrustedImage(c *check.C, name string) string {
191
+	repoName := fmt.Sprintf("%v/dockercli/%s:latest", privateRegistryURL, name)
192
+	// tag the image and upload it to the private registry
193
+	dockerCmd(c, "tag", "busybox", repoName)
194
+
195
+	pushCmd := exec.Command(dockerBinary, "push", repoName)
196
+	s.trustedCmd(pushCmd)
197
+	out, _, err := runCommandWithOutput(pushCmd)
198
+
199
+	if err != nil {
200
+		c.Fatalf("Error running trusted push: %s\n%s", err, out)
201
+	}
202
+	if !strings.Contains(string(out), "Signing and pushing trust metadata") {
203
+		c.Fatalf("Missing expected output on trusted push:\n%s", out)
204
+	}
205
+
206
+	if out, status := dockerCmd(c, "rmi", repoName); status != 0 {
207
+		c.Fatalf("Error removing image %q\n%s", repoName, out)
208
+	}
209
+
210
+	return repoName
211
+}
212
+
213
+func (s *DockerTrustSuite) setupTrustedplugin(c *check.C, source, name string) string {
214
+	repoName := fmt.Sprintf("%v/dockercli/%s:latest", privateRegistryURL, name)
215
+	// tag the image and upload it to the private registry
216
+	dockerCmd(c, "plugin", "install", "--grant-all-permissions", "--alias", repoName, source)
217
+
218
+	pushCmd := exec.Command(dockerBinary, "plugin", "push", repoName)
219
+	s.trustedCmd(pushCmd)
220
+	out, _, err := runCommandWithOutput(pushCmd)
221
+
222
+	if err != nil {
223
+		c.Fatalf("Error running trusted plugin push: %s\n%s", err, out)
224
+	}
225
+	if !strings.Contains(string(out), "Signing and pushing trust metadata") {
226
+		c.Fatalf("Missing expected output on trusted push:\n%s", out)
227
+	}
228
+
229
+	if out, status := dockerCmd(c, "plugin", "rm", "-f", repoName); status != 0 {
230
+		c.Fatalf("Error removing plugin %q\n%s", repoName, out)
231
+	}
232
+
233
+	return repoName
234
+}
235
+
236
+func notaryClientEnv(cmd *exec.Cmd) {
237
+	pwd := "12345678"
238
+	env := []string{
239
+		fmt.Sprintf("NOTARY_ROOT_PASSPHRASE=%s", pwd),
240
+		fmt.Sprintf("NOTARY_TARGETS_PASSPHRASE=%s", pwd),
241
+		fmt.Sprintf("NOTARY_SNAPSHOT_PASSPHRASE=%s", pwd),
242
+		fmt.Sprintf("NOTARY_DELEGATION_PASSPHRASE=%s", pwd),
243
+	}
244
+	cmd.Env = append(os.Environ(), env...)
245
+}
246
+
247
+func (s *DockerTrustSuite) notaryInitRepo(c *check.C, repoName string) {
248
+	initCmd := exec.Command(notaryBinary, "-c", filepath.Join(s.not.dir, "client-config.json"), "init", repoName)
249
+	notaryClientEnv(initCmd)
250
+	out, _, err := runCommandWithOutput(initCmd)
251
+	if err != nil {
252
+		c.Fatalf("Error initializing notary repository: %s\n", out)
253
+	}
254
+}
255
+
256
+func (s *DockerTrustSuite) notaryCreateDelegation(c *check.C, repoName, role string, pubKey string, paths ...string) {
257
+	pathsArg := "--all-paths"
258
+	if len(paths) > 0 {
259
+		pathsArg = "--paths=" + strings.Join(paths, ",")
260
+	}
261
+
262
+	delgCmd := exec.Command(notaryBinary, "-c", filepath.Join(s.not.dir, "client-config.json"),
263
+		"delegation", "add", repoName, role, pubKey, pathsArg)
264
+	notaryClientEnv(delgCmd)
265
+	out, _, err := runCommandWithOutput(delgCmd)
266
+	if err != nil {
267
+		c.Fatalf("Error adding %s role to notary repository: %s\n", role, out)
268
+	}
269
+}
270
+
271
+func (s *DockerTrustSuite) notaryPublish(c *check.C, repoName string) {
272
+	pubCmd := exec.Command(notaryBinary, "-c", filepath.Join(s.not.dir, "client-config.json"), "publish", repoName)
273
+	notaryClientEnv(pubCmd)
274
+	out, _, err := runCommandWithOutput(pubCmd)
275
+	if err != nil {
276
+		c.Fatalf("Error publishing notary repository: %s\n", out)
277
+	}
278
+}
279
+
280
+func (s *DockerTrustSuite) notaryImportKey(c *check.C, repoName, role string, privKey string) {
281
+	impCmd := exec.Command(notaryBinary, "-c", filepath.Join(s.not.dir, "client-config.json"), "key",
282
+		"import", privKey, "-g", repoName, "-r", role)
283
+	notaryClientEnv(impCmd)
284
+	out, _, err := runCommandWithOutput(impCmd)
285
+	if err != nil {
286
+		c.Fatalf("Error importing key to notary repository: %s\n", out)
287
+	}
288
+}
289
+
290
+func (s *DockerTrustSuite) notaryListTargetsInRole(c *check.C, repoName, role string) map[string]string {
291
+	listCmd := exec.Command(notaryBinary, "-c", filepath.Join(s.not.dir, "client-config.json"), "list",
292
+		repoName, "-r", role)
293
+	notaryClientEnv(listCmd)
294
+	out, _, err := runCommandWithOutput(listCmd)
295
+	if err != nil {
296
+		c.Fatalf("Error listing targets in notary repository: %s\n", out)
297
+	}
298
+
299
+	// should look something like:
300
+	//    NAME                                 DIGEST                                SIZE (BYTES)    ROLE
301
+	// ------------------------------------------------------------------------------------------------------
302
+	//   latest   24a36bbc059b1345b7e8be0df20f1b23caa3602e85d42fff7ecd9d0bd255de56   1377           targets
303
+
304
+	targets := make(map[string]string)
305
+
306
+	// no target
307
+	lines := strings.Split(strings.TrimSpace(out), "\n")
308
+	if len(lines) == 1 && strings.Contains(out, "No targets present in this repository.") {
309
+		return targets
310
+	}
311
+
312
+	// otherwise, there is at least one target
313
+	c.Assert(len(lines), checker.GreaterOrEqualThan, 3)
314
+
315
+	for _, line := range lines[2:] {
316
+		tokens := strings.Fields(line)
317
+		c.Assert(tokens, checker.HasLen, 4)
318
+		targets[tokens[0]] = tokens[3]
319
+	}
320
+
321
+	return targets
322
+}
323
+
324
+func (s *DockerTrustSuite) assertTargetInRoles(c *check.C, repoName, target string, roles ...string) {
325
+	// check all the roles
326
+	for _, role := range roles {
327
+		targets := s.notaryListTargetsInRole(c, repoName, role)
328
+		roleName, ok := targets[target]
329
+		c.Assert(ok, checker.True)
330
+		c.Assert(roleName, checker.Equals, role)
331
+	}
332
+}
333
+
334
+func (s *DockerTrustSuite) assertTargetNotInRoles(c *check.C, repoName, target string, roles ...string) {
335
+	targets := s.notaryListTargetsInRole(c, repoName, "targets")
336
+
337
+	roleName, ok := targets[target]
338
+	if ok {
339
+		for _, role := range roles {
340
+			c.Assert(roleName, checker.Not(checker.Equals), role)
341
+		}
342
+	}
343
+}
0 344
deleted file mode 100644
... ...
@@ -1,30 +0,0 @@
1
-package main
2
-
3
-import (
4
-	"github.com/docker/docker/pkg/integration/cmd"
5
-	"os/exec"
6
-)
7
-
8
-func getPrefixAndSlashFromDaemonPlatform() (prefix, slash string) {
9
-	if daemonPlatform == "windows" {
10
-		return "c:", `\`
11
-	}
12
-	return "", "/"
13
-}
14
-
15
-// TODO: update code to call cmd.RunCmd directly, and remove this function
16
-func runCommandWithOutput(execCmd *exec.Cmd) (string, int, error) {
17
-	result := cmd.RunCmd(transformCmd(execCmd))
18
-	return result.Combined(), result.ExitCode, result.Error
19
-}
20
-
21
-// Temporary shim for migrating commands to the new function
22
-func transformCmd(execCmd *exec.Cmd) cmd.Cmd {
23
-	return cmd.Cmd{
24
-		Command: execCmd.Args,
25
-		Env:     execCmd.Env,
26
-		Dir:     execCmd.Dir,
27
-		Stdin:   execCmd.Stdin,
28
-		Stdout:  execCmd.Stdout,
29
-	}
30
-}
31 1
new file mode 100644
... ...
@@ -0,0 +1,30 @@
0
+package main
1
+
2
+import (
3
+	"github.com/docker/docker/pkg/integration/cmd"
4
+	"os/exec"
5
+)
6
+
7
+func getPrefixAndSlashFromDaemonPlatform() (prefix, slash string) {
8
+	if daemonPlatform == "windows" {
9
+		return "c:", `\`
10
+	}
11
+	return "", "/"
12
+}
13
+
14
+// TODO: update code to call cmd.RunCmd directly, and remove this function
15
+func runCommandWithOutput(execCmd *exec.Cmd) (string, int, error) {
16
+	result := cmd.RunCmd(transformCmd(execCmd))
17
+	return result.Combined(), result.ExitCode, result.Error
18
+}
19
+
20
+// Temporary shim for migrating commands to the new function
21
+func transformCmd(execCmd *exec.Cmd) cmd.Cmd {
22
+	return cmd.Cmd{
23
+		Command: execCmd.Args,
24
+		Env:     execCmd.Env,
25
+		Dir:     execCmd.Dir,
26
+		Stdin:   execCmd.Stdin,
27
+		Stdout:  execCmd.Stdout,
28
+	}
29
+}