1package main
2
3import (
4	"bufio"
5	"bytes"
6	"context"
7	"encoding/json"
8	"fmt"
9	"io"
10	"io/ioutil"
11	"net"
12	"os"
13	"os/exec"
14	"path"
15	"path/filepath"
16	"reflect"
17	"regexp"
18	"runtime"
19	"sort"
20	"strconv"
21	"strings"
22	"sync"
23	"time"
24
25	"github.com/docker/docker/client"
26	"github.com/docker/docker/integration-cli/checker"
27	"github.com/docker/docker/integration-cli/cli"
28	"github.com/docker/docker/integration-cli/cli/build"
29	"github.com/docker/docker/internal/test/fakecontext"
30	"github.com/docker/docker/internal/testutil"
31	"github.com/docker/docker/pkg/mount"
32	"github.com/docker/docker/pkg/parsers/kernel"
33	"github.com/docker/docker/pkg/stringid"
34	"github.com/docker/docker/runconfig"
35	"github.com/docker/go-connections/nat"
36	"github.com/docker/libnetwork/resolvconf"
37	"github.com/docker/libnetwork/types"
38	"github.com/go-check/check"
39	"gotest.tools/icmd"
40)
41
42// "test123" should be printed by docker run
43func (s *DockerSuite) TestRunEchoStdout(c *check.C) {
44	out, _ := dockerCmd(c, "run", "busybox", "echo", "test123")
45	if out != "test123\n" {
46		c.Fatalf("container should've printed 'test123', got '%s'", out)
47	}
48}
49
50// "test" should be printed
51func (s *DockerSuite) TestRunEchoNamedContainer(c *check.C) {
52	out, _ := dockerCmd(c, "run", "--name", "testfoonamedcontainer", "busybox", "echo", "test")
53	if out != "test\n" {
54		c.Errorf("container should've printed 'test'")
55	}
56}
57
58// docker run should not leak file descriptors. This test relies on Unix
59// specific functionality and cannot run on Windows.
60func (s *DockerSuite) TestRunLeakyFileDescriptors(c *check.C) {
61	testRequires(c, DaemonIsLinux)
62	out, _ := dockerCmd(c, "run", "busybox", "ls", "-C", "/proc/self/fd")
63
64	// normally, we should only get 0, 1, and 2, but 3 gets created by "ls" when it does "opendir" on the "fd" directory
65	if out != "0  1  2  3\n" {
66		c.Errorf("container should've printed '0  1  2  3', not: %s", out)
67	}
68}
69
70// it should be possible to lookup Google DNS
71// this will fail when Internet access is unavailable
72func (s *DockerSuite) TestRunLookupGoogleDNS(c *check.C) {
73	testRequires(c, Network, NotArm)
74	if testEnv.OSType == "windows" {
75		// nslookup isn't present in Windows busybox. Is built-in. Further,
76		// nslookup isn't present in nanoserver. Hence just use PowerShell...
77		dockerCmd(c, "run", testEnv.PlatformDefaults.BaseImage, "powershell", "Resolve-DNSName", "google.com")
78	} else {
79		dockerCmd(c, "run", "busybox", "nslookup", "google.com")
80	}
81
82}
83
84// the exit code should be 0
85func (s *DockerSuite) TestRunExitCodeZero(c *check.C) {
86	dockerCmd(c, "run", "busybox", "true")
87}
88
89// the exit code should be 1
90func (s *DockerSuite) TestRunExitCodeOne(c *check.C) {
91	_, exitCode, err := dockerCmdWithError("run", "busybox", "false")
92	c.Assert(err, checker.NotNil)
93	c.Assert(exitCode, checker.Equals, 1)
94}
95
96// it should be possible to pipe in data via stdin to a process running in a container
97func (s *DockerSuite) TestRunStdinPipe(c *check.C) {
98	// TODO Windows: This needs some work to make compatible.
99	testRequires(c, DaemonIsLinux)
100	result := icmd.RunCmd(icmd.Cmd{
101		Command: []string{dockerBinary, "run", "-i", "-a", "stdin", "busybox", "cat"},
102		Stdin:   strings.NewReader("blahblah"),
103	})
104	result.Assert(c, icmd.Success)
105	out := result.Stdout()
106
107	out = strings.TrimSpace(out)
108	dockerCmd(c, "wait", out)
109
110	logsOut, _ := dockerCmd(c, "logs", out)
111
112	containerLogs := strings.TrimSpace(logsOut)
113	if containerLogs != "blahblah" {
114		c.Errorf("logs didn't print the container's logs %s", containerLogs)
115	}
116
117	dockerCmd(c, "rm", out)
118}
119
120// the container's ID should be printed when starting a container in detached mode
121func (s *DockerSuite) TestRunDetachedContainerIDPrinting(c *check.C) {
122	out, _ := dockerCmd(c, "run", "-d", "busybox", "true")
123
124	out = strings.TrimSpace(out)
125	dockerCmd(c, "wait", out)
126
127	rmOut, _ := dockerCmd(c, "rm", out)
128
129	rmOut = strings.TrimSpace(rmOut)
130	if rmOut != out {
131		c.Errorf("rm didn't print the container ID %s %s", out, rmOut)
132	}
133}
134
135// the working directory should be set correctly
136func (s *DockerSuite) TestRunWorkingDirectory(c *check.C) {
137	dir := "/root"
138	image := "busybox"
139	if testEnv.OSType == "windows" {
140		dir = `C:/Windows`
141	}
142
143	// First with -w
144	out, _ := dockerCmd(c, "run", "-w", dir, image, "pwd")
145	out = strings.TrimSpace(out)
146	if out != dir {
147		c.Errorf("-w failed to set working directory")
148	}
149
150	// Then with --workdir
151	out, _ = dockerCmd(c, "run", "--workdir", dir, image, "pwd")
152	out = strings.TrimSpace(out)
153	if out != dir {
154		c.Errorf("--workdir failed to set working directory")
155	}
156}
157
158// pinging Google's DNS resolver should fail when we disable the networking
159func (s *DockerSuite) TestRunWithoutNetworking(c *check.C) {
160	count := "-c"
161	image := "busybox"
162	if testEnv.OSType == "windows" {
163		count = "-n"
164		image = testEnv.PlatformDefaults.BaseImage
165	}
166
167	// First using the long form --net
168	out, exitCode, err := dockerCmdWithError("run", "--net=none", image, "ping", count, "1", "8.8.8.8")
169	if err != nil && exitCode != 1 {
170		c.Fatal(out, err)
171	}
172	if exitCode != 1 {
173		c.Errorf("--net=none should've disabled the network; the container shouldn't have been able to ping 8.8.8.8")
174	}
175}
176
177//test --link use container name to link target
178func (s *DockerSuite) TestRunLinksContainerWithContainerName(c *check.C) {
179	// TODO Windows: This test cannot run on a Windows daemon as the networking
180	// settings are not populated back yet on inspect.
181	testRequires(c, DaemonIsLinux)
182	dockerCmd(c, "run", "-i", "-t", "-d", "--name", "parent", "busybox")
183
184	ip := inspectField(c, "parent", "NetworkSettings.Networks.bridge.IPAddress")
185
186	out, _ := dockerCmd(c, "run", "--link", "parent:test", "busybox", "/bin/cat", "/etc/hosts")
187	if !strings.Contains(out, ip+"	test") {
188		c.Fatalf("use a container name to link target failed")
189	}
190}
191
192//test --link use container id to link target
193func (s *DockerSuite) TestRunLinksContainerWithContainerID(c *check.C) {
194	// TODO Windows: This test cannot run on a Windows daemon as the networking
195	// settings are not populated back yet on inspect.
196	testRequires(c, DaemonIsLinux)
197	cID, _ := dockerCmd(c, "run", "-i", "-t", "-d", "busybox")
198
199	cID = strings.TrimSpace(cID)
200	ip := inspectField(c, cID, "NetworkSettings.Networks.bridge.IPAddress")
201
202	out, _ := dockerCmd(c, "run", "--link", cID+":test", "busybox", "/bin/cat", "/etc/hosts")
203	if !strings.Contains(out, ip+"	test") {
204		c.Fatalf("use a container id to link target failed")
205	}
206}
207
208func (s *DockerSuite) TestUserDefinedNetworkLinks(c *check.C) {
209	testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm)
210	dockerCmd(c, "network", "create", "-d", "bridge", "udlinkNet")
211
212	dockerCmd(c, "run", "-d", "--net=udlinkNet", "--name=first", "busybox", "top")
213	c.Assert(waitRun("first"), check.IsNil)
214
215	// run a container in user-defined network udlinkNet with a link for an existing container
216	// and a link for a container that doesn't exist
217	dockerCmd(c, "run", "-d", "--net=udlinkNet", "--name=second", "--link=first:foo",
218		"--link=third:bar", "busybox", "top")
219	c.Assert(waitRun("second"), check.IsNil)
220
221	// ping to first and its alias foo must succeed
222	_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
223	c.Assert(err, check.IsNil)
224	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo")
225	c.Assert(err, check.IsNil)
226
227	// ping to third and its alias must fail
228	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "third")
229	c.Assert(err, check.NotNil)
230	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "bar")
231	c.Assert(err, check.NotNil)
232
233	// start third container now
234	dockerCmd(c, "run", "-d", "--net=udlinkNet", "--name=third", "busybox", "top")
235	c.Assert(waitRun("third"), check.IsNil)
236
237	// ping to third and its alias must succeed now
238	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "third")
239	c.Assert(err, check.IsNil)
240	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "bar")
241	c.Assert(err, check.IsNil)
242}
243
244func (s *DockerSuite) TestUserDefinedNetworkLinksWithRestart(c *check.C) {
245	testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm)
246	dockerCmd(c, "network", "create", "-d", "bridge", "udlinkNet")
247
248	dockerCmd(c, "run", "-d", "--net=udlinkNet", "--name=first", "busybox", "top")
249	c.Assert(waitRun("first"), check.IsNil)
250
251	dockerCmd(c, "run", "-d", "--net=udlinkNet", "--name=second", "--link=first:foo",
252		"busybox", "top")
253	c.Assert(waitRun("second"), check.IsNil)
254
255	// ping to first and its alias foo must succeed
256	_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
257	c.Assert(err, check.IsNil)
258	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo")
259	c.Assert(err, check.IsNil)
260
261	// Restart first container
262	dockerCmd(c, "restart", "first")
263	c.Assert(waitRun("first"), check.IsNil)
264
265	// ping to first and its alias foo must still succeed
266	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
267	c.Assert(err, check.IsNil)
268	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo")
269	c.Assert(err, check.IsNil)
270
271	// Restart second container
272	dockerCmd(c, "restart", "second")
273	c.Assert(waitRun("second"), check.IsNil)
274
275	// ping to first and its alias foo must still succeed
276	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
277	c.Assert(err, check.IsNil)
278	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo")
279	c.Assert(err, check.IsNil)
280}
281
282func (s *DockerSuite) TestRunWithNetAliasOnDefaultNetworks(c *check.C) {
283	testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm)
284
285	defaults := []string{"bridge", "host", "none"}
286	for _, net := range defaults {
287		out, _, err := dockerCmdWithError("run", "-d", "--net", net, "--net-alias", "alias_"+net, "busybox", "top")
288		c.Assert(err, checker.NotNil)
289		c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkAndAlias.Error())
290	}
291}
292
293func (s *DockerSuite) TestUserDefinedNetworkAlias(c *check.C) {
294	testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm)
295	dockerCmd(c, "network", "create", "-d", "bridge", "net1")
296
297	cid1, _ := dockerCmd(c, "run", "-d", "--net=net1", "--name=first", "--net-alias=foo1", "--net-alias=foo2", "busybox:glibc", "top")
298	c.Assert(waitRun("first"), check.IsNil)
299
300	// Check if default short-id alias is added automatically
301	id := strings.TrimSpace(cid1)
302	aliases := inspectField(c, id, "NetworkSettings.Networks.net1.Aliases")
303	c.Assert(aliases, checker.Contains, stringid.TruncateID(id))
304
305	cid2, _ := dockerCmd(c, "run", "-d", "--net=net1", "--name=second", "busybox:glibc", "top")
306	c.Assert(waitRun("second"), check.IsNil)
307
308	// Check if default short-id alias is added automatically
309	id = strings.TrimSpace(cid2)
310	aliases = inspectField(c, id, "NetworkSettings.Networks.net1.Aliases")
311	c.Assert(aliases, checker.Contains, stringid.TruncateID(id))
312
313	// ping to first and its network-scoped aliases
314	_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
315	c.Assert(err, check.IsNil)
316	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo1")
317	c.Assert(err, check.IsNil)
318	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo2")
319	c.Assert(err, check.IsNil)
320	// ping first container's short-id alias
321	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", stringid.TruncateID(cid1))
322	c.Assert(err, check.IsNil)
323
324	// Restart first container
325	dockerCmd(c, "restart", "first")
326	c.Assert(waitRun("first"), check.IsNil)
327
328	// ping to first and its network-scoped aliases must succeed
329	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
330	c.Assert(err, check.IsNil)
331	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo1")
332	c.Assert(err, check.IsNil)
333	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo2")
334	c.Assert(err, check.IsNil)
335	// ping first container's short-id alias
336	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", stringid.TruncateID(cid1))
337	c.Assert(err, check.IsNil)
338}
339
340// Issue 9677.
341func (s *DockerSuite) TestRunWithDaemonFlags(c *check.C) {
342	out, _, err := dockerCmdWithError("--exec-opt", "foo=bar", "run", "-i", "busybox", "true")
343	c.Assert(err, checker.NotNil)
344	c.Assert(out, checker.Contains, "unknown flag: --exec-opt")
345}
346
347// Regression test for #4979
348func (s *DockerSuite) TestRunWithVolumesFromExited(c *check.C) {
349
350	var (
351		out      string
352		exitCode int
353	)
354
355	// Create a file in a volume
356	if testEnv.OSType == "windows" {
357		out, exitCode = dockerCmd(c, "run", "--name", "test-data", "--volume", `c:\some\dir`, testEnv.PlatformDefaults.BaseImage, "cmd", "/c", `echo hello > c:\some\dir\file`)
358	} else {
359		out, exitCode = dockerCmd(c, "run", "--name", "test-data", "--volume", "/some/dir", "busybox", "touch", "/some/dir/file")
360	}
361	if exitCode != 0 {
362		c.Fatal("1", out, exitCode)
363	}
364
365	// Read the file from another container using --volumes-from to access the volume in the second container
366	if testEnv.OSType == "windows" {
367		out, exitCode = dockerCmd(c, "run", "--volumes-from", "test-data", testEnv.PlatformDefaults.BaseImage, "cmd", "/c", `type c:\some\dir\file`)
368	} else {
369		out, exitCode = dockerCmd(c, "run", "--volumes-from", "test-data", "busybox", "cat", "/some/dir/file")
370	}
371	if exitCode != 0 {
372		c.Fatal("2", out, exitCode)
373	}
374}
375
376// Volume path is a symlink which also exists on the host, and the host side is a file not a dir
377// But the volume call is just a normal volume, not a bind mount
378func (s *DockerSuite) TestRunCreateVolumesInSymlinkDir(c *check.C) {
379	var (
380		dockerFile    string
381		containerPath string
382		cmd           string
383	)
384	// This test cannot run on a Windows daemon as
385	// Windows does not support symlinks inside a volume path
386	testRequires(c, SameHostDaemon, DaemonIsLinux)
387	name := "test-volume-symlink"
388
389	dir, err := ioutil.TempDir("", name)
390	if err != nil {
391		c.Fatal(err)
392	}
393	defer os.RemoveAll(dir)
394
395	// In the case of Windows to Windows CI, if the machine is setup so that
396	// the temp directory is not the C: drive, this test is invalid and will
397	// not work.
398	if testEnv.OSType == "windows" && strings.ToLower(dir[:1]) != "c" {
399		c.Skip("Requires TEMP to point to C: drive")
400	}
401
402	f, err := os.OpenFile(filepath.Join(dir, "test"), os.O_CREATE, 0700)
403	if err != nil {
404		c.Fatal(err)
405	}
406	f.Close()
407
408	if testEnv.OSType == "windows" {
409		dockerFile = fmt.Sprintf("FROM %s\nRUN mkdir %s\nRUN mklink /D c:\\test %s", testEnv.PlatformDefaults.BaseImage, dir, dir)
410		containerPath = `c:\test\test`
411		cmd = "tasklist"
412	} else {
413		dockerFile = fmt.Sprintf("FROM busybox\nRUN mkdir -p %s\nRUN ln -s %s /test", dir, dir)
414		containerPath = "/test/test"
415		cmd = "true"
416	}
417	buildImageSuccessfully(c, name, build.WithDockerfile(dockerFile))
418	dockerCmd(c, "run", "-v", containerPath, name, cmd)
419}
420
421// Volume path is a symlink in the container
422func (s *DockerSuite) TestRunCreateVolumesInSymlinkDir2(c *check.C) {
423	var (
424		dockerFile    string
425		containerPath string
426		cmd           string
427	)
428	// This test cannot run on a Windows daemon as
429	// Windows does not support symlinks inside a volume path
430	testRequires(c, SameHostDaemon, DaemonIsLinux)
431	name := "test-volume-symlink2"
432
433	if testEnv.OSType == "windows" {
434		dockerFile = fmt.Sprintf("FROM %s\nRUN mkdir c:\\%s\nRUN mklink /D c:\\test c:\\%s", testEnv.PlatformDefaults.BaseImage, name, name)
435		containerPath = `c:\test\test`
436		cmd = "tasklist"
437	} else {
438		dockerFile = fmt.Sprintf("FROM busybox\nRUN mkdir -p /%s\nRUN ln -s /%s /test", name, name)
439		containerPath = "/test/test"
440		cmd = "true"
441	}
442	buildImageSuccessfully(c, name, build.WithDockerfile(dockerFile))
443	dockerCmd(c, "run", "-v", containerPath, name, cmd)
444}
445
446func (s *DockerSuite) TestRunVolumesMountedAsReadonly(c *check.C) {
447	if _, code, err := dockerCmdWithError("run", "-v", "/test:/test:ro", "busybox", "touch", "/test/somefile"); err == nil || code == 0 {
448		c.Fatalf("run should fail because volume is ro: exit code %d", code)
449	}
450}
451
452func (s *DockerSuite) TestRunVolumesFromInReadonlyModeFails(c *check.C) {
453	var (
454		volumeDir string
455		fileInVol string
456	)
457	if testEnv.OSType == "windows" {
458		volumeDir = `c:/test` // Forward-slash as using busybox
459		fileInVol = `c:/test/file`
460	} else {
461		testRequires(c, DaemonIsLinux)
462		volumeDir = "/test"
463		fileInVol = `/test/file`
464	}
465	dockerCmd(c, "run", "--name", "parent", "-v", volumeDir, "busybox", "true")
466
467	if _, code, err := dockerCmdWithError("run", "--volumes-from", "parent:ro", "busybox", "touch", fileInVol); err == nil || code == 0 {
468		c.Fatalf("run should fail because volume is ro: exit code %d", code)
469	}
470}
471
472// Regression test for #1201
473func (s *DockerSuite) TestRunVolumesFromInReadWriteMode(c *check.C) {
474	var (
475		volumeDir string
476		fileInVol string
477	)
478	if testEnv.OSType == "windows" {
479		volumeDir = `c:/test` // Forward-slash as using busybox
480		fileInVol = `c:/test/file`
481	} else {
482		volumeDir = "/test"
483		fileInVol = "/test/file"
484	}
485
486	dockerCmd(c, "run", "--name", "parent", "-v", volumeDir, "busybox", "true")
487	dockerCmd(c, "run", "--volumes-from", "parent:rw", "busybox", "touch", fileInVol)
488
489	if out, _, err := dockerCmdWithError("run", "--volumes-from", "parent:bar", "busybox", "touch", fileInVol); err == nil || !strings.Contains(out, `invalid mode: bar`) {
490		c.Fatalf("running --volumes-from parent:bar should have failed with invalid mode: %q", out)
491	}
492
493	dockerCmd(c, "run", "--volumes-from", "parent", "busybox", "touch", fileInVol)
494}
495
496func (s *DockerSuite) TestVolumesFromGetsProperMode(c *check.C) {
497	testRequires(c, SameHostDaemon)
498	prefix, slash := getPrefixAndSlashFromDaemonPlatform()
499	hostpath := RandomTmpDirPath("test", testEnv.OSType)
500	if err := os.MkdirAll(hostpath, 0755); err != nil {
501		c.Fatalf("Failed to create %s: %q", hostpath, err)
502	}
503	defer os.RemoveAll(hostpath)
504
505	dockerCmd(c, "run", "--name", "parent", "-v", hostpath+":"+prefix+slash+"test:ro", "busybox", "true")
506
507	// Expect this "rw" mode to be be ignored since the inherited volume is "ro"
508	if _, _, err := dockerCmdWithError("run", "--volumes-from", "parent:rw", "busybox", "touch", prefix+slash+"test"+slash+"file"); err == nil {
509		c.Fatal("Expected volumes-from to inherit read-only volume even when passing in `rw`")
510	}
511
512	dockerCmd(c, "run", "--name", "parent2", "-v", hostpath+":"+prefix+slash+"test:ro", "busybox", "true")
513
514	// Expect this to be read-only since both are "ro"
515	if _, _, err := dockerCmdWithError("run", "--volumes-from", "parent2:ro", "busybox", "touch", prefix+slash+"test"+slash+"file"); err == nil {
516		c.Fatal("Expected volumes-from to inherit read-only volume even when passing in `ro`")
517	}
518}
519
520// Test for GH#10618
521func (s *DockerSuite) TestRunNoDupVolumes(c *check.C) {
522	path1 := RandomTmpDirPath("test1", testEnv.OSType)
523	path2 := RandomTmpDirPath("test2", testEnv.OSType)
524
525	someplace := ":/someplace"
526	if testEnv.OSType == "windows" {
527		// Windows requires that the source directory exists before calling HCS
528		testRequires(c, SameHostDaemon)
529		someplace = `:c:\someplace`
530		if err := os.MkdirAll(path1, 0755); err != nil {
531			c.Fatalf("Failed to create %s: %q", path1, err)
532		}
533		defer os.RemoveAll(path1)
534		if err := os.MkdirAll(path2, 0755); err != nil {
535			c.Fatalf("Failed to create %s: %q", path1, err)
536		}
537		defer os.RemoveAll(path2)
538	}
539	mountstr1 := path1 + someplace
540	mountstr2 := path2 + someplace
541
542	if out, _, err := dockerCmdWithError("run", "-v", mountstr1, "-v", mountstr2, "busybox", "true"); err == nil {
543		c.Fatal("Expected error about duplicate mount definitions")
544	} else {
545		if !strings.Contains(out, "Duplicate mount point") {
546			c.Fatalf("Expected 'duplicate mount point' error, got %v", out)
547		}
548	}
549
550	// Test for https://github.com/docker/docker/issues/22093
551	volumename1 := "test1"
552	volumename2 := "test2"
553	volume1 := volumename1 + someplace
554	volume2 := volumename2 + someplace
555	if out, _, err := dockerCmdWithError("run", "-v", volume1, "-v", volume2, "busybox", "true"); err == nil {
556		c.Fatal("Expected error about duplicate mount definitions")
557	} else {
558		if !strings.Contains(out, "Duplicate mount point") {
559			c.Fatalf("Expected 'duplicate mount point' error, got %v", out)
560		}
561	}
562	// create failed should have create volume volumename1 or volumename2
563	// we should remove volumename2 or volumename2 successfully
564	out, _ := dockerCmd(c, "volume", "ls")
565	if strings.Contains(out, volumename1) {
566		dockerCmd(c, "volume", "rm", volumename1)
567	} else {
568		dockerCmd(c, "volume", "rm", volumename2)
569	}
570}
571
572// Test for #1351
573func (s *DockerSuite) TestRunApplyVolumesFromBeforeVolumes(c *check.C) {
574	prefix := ""
575	if testEnv.OSType == "windows" {
576		prefix = `c:`
577	}
578	dockerCmd(c, "run", "--name", "parent", "-v", prefix+"/test", "busybox", "touch", prefix+"/test/foo")
579	dockerCmd(c, "run", "--volumes-from", "parent", "-v", prefix+"/test", "busybox", "cat", prefix+"/test/foo")
580}
581
582func (s *DockerSuite) TestRunMultipleVolumesFrom(c *check.C) {
583	prefix := ""
584	if testEnv.OSType == "windows" {
585		prefix = `c:`
586	}
587	dockerCmd(c, "run", "--name", "parent1", "-v", prefix+"/test", "busybox", "touch", prefix+"/test/foo")
588	dockerCmd(c, "run", "--name", "parent2", "-v", prefix+"/other", "busybox", "touch", prefix+"/other/bar")
589	dockerCmd(c, "run", "--volumes-from", "parent1", "--volumes-from", "parent2", "busybox", "sh", "-c", "cat /test/foo && cat /other/bar")
590}
591
592// this tests verifies the ID format for the container
593func (s *DockerSuite) TestRunVerifyContainerID(c *check.C) {
594	out, exit, err := dockerCmdWithError("run", "-d", "busybox", "true")
595	if err != nil {
596		c.Fatal(err)
597	}
598	if exit != 0 {
599		c.Fatalf("expected exit code 0 received %d", exit)
600	}
601
602	match, err := regexp.MatchString("^[0-9a-f]{64}$", strings.TrimSuffix(out, "\n"))
603	if err != nil {
604		c.Fatal(err)
605	}
606	if !match {
607		c.Fatalf("Invalid container ID: %s", out)
608	}
609}
610
611// Test that creating a container with a volume doesn't crash. Regression test for #995.
612func (s *DockerSuite) TestRunCreateVolume(c *check.C) {
613	prefix := ""
614	if testEnv.OSType == "windows" {
615		prefix = `c:`
616	}
617	dockerCmd(c, "run", "-v", prefix+"/var/lib/data", "busybox", "true")
618}
619
620// Test that creating a volume with a symlink in its path works correctly. Test for #5152.
621// Note that this bug happens only with symlinks with a target that starts with '/'.
622func (s *DockerSuite) TestRunCreateVolumeWithSymlink(c *check.C) {
623	// Cannot run on Windows as relies on Linux-specific functionality (sh -c mount...)
624	testRequires(c, DaemonIsLinux)
625	workingDirectory, err := ioutil.TempDir("", "TestRunCreateVolumeWithSymlink")
626	c.Assert(err, checker.IsNil)
627	image := "docker-test-createvolumewithsymlink"
628
629	buildCmd := exec.Command(dockerBinary, "build", "-t", image, "-")
630	buildCmd.Stdin = strings.NewReader(`FROM busybox
631		RUN ln -s home /bar`)
632	buildCmd.Dir = workingDirectory
633	err = buildCmd.Run()
634	if err != nil {
635		c.Fatalf("could not build '%s': %v", image, err)
636	}
637
638	_, exitCode, err := dockerCmdWithError("run", "-v", "/bar/foo", "--name", "test-createvolumewithsymlink", image, "sh", "-c", "mount | grep -q /home/foo")
639	if err != nil || exitCode != 0 {
640		c.Fatalf("[run] err: %v, exitcode: %d", err, exitCode)
641	}
642
643	volPath, err := inspectMountSourceField("test-createvolumewithsymlink", "/bar/foo")
644	c.Assert(err, checker.IsNil)
645
646	_, exitCode, err = dockerCmdWithError("rm", "-v", "test-createvolumewithsymlink")
647	if err != nil || exitCode != 0 {
648		c.Fatalf("[rm] err: %v, exitcode: %d", err, exitCode)
649	}
650
651	_, err = os.Stat(volPath)
652	if !os.IsNotExist(err) {
653		c.Fatalf("[open] (expecting 'file does not exist' error) err: %v, volPath: %s", err, volPath)
654	}
655}
656
657// Tests that a volume path that has a symlink exists in a container mounting it with `--volumes-from`.
658func (s *DockerSuite) TestRunVolumesFromSymlinkPath(c *check.C) {
659	// This test cannot run on a Windows daemon as
660	// Windows does not support symlinks inside a volume path
661	testRequires(c, DaemonIsLinux)
662
663	workingDirectory, err := ioutil.TempDir("", "TestRunVolumesFromSymlinkPath")
664	c.Assert(err, checker.IsNil)
665	name := "docker-test-volumesfromsymlinkpath"
666	prefix := ""
667	dfContents := `FROM busybox
668		RUN ln -s home /foo
669		VOLUME ["/foo/bar"]`
670
671	if testEnv.OSType == "windows" {
672		prefix = `c:`
673		dfContents = `FROM ` + testEnv.PlatformDefaults.BaseImage + `
674	    RUN mkdir c:\home
675		RUN mklink /D c:\foo c:\home
676		VOLUME ["c:/foo/bar"]
677		ENTRYPOINT c:\windows\system32\cmd.exe`
678	}
679
680	buildCmd := exec.Command(dockerBinary, "build", "-t", name, "-")
681	buildCmd.Stdin = strings.NewReader(dfContents)
682	buildCmd.Dir = workingDirectory
683	err = buildCmd.Run()
684	if err != nil {
685		c.Fatalf("could not build 'docker-test-volumesfromsymlinkpath': %v", err)
686	}
687
688	out, exitCode, err := dockerCmdWithError("run", "--name", "test-volumesfromsymlinkpath", name)
689	if err != nil || exitCode != 0 {
690		c.Fatalf("[run] (volume) err: %v, exitcode: %d, out: %s", err, exitCode, out)
691	}
692
693	_, exitCode, err = dockerCmdWithError("run", "--volumes-from", "test-volumesfromsymlinkpath", "busybox", "sh", "-c", "ls "+prefix+"/foo | grep -q bar")
694	if err != nil || exitCode != 0 {
695		c.Fatalf("[run] err: %v, exitcode: %d", err, exitCode)
696	}
697}
698
699func (s *DockerSuite) TestRunExitCode(c *check.C) {
700	var (
701		exit int
702		err  error
703	)
704
705	_, exit, err = dockerCmdWithError("run", "busybox", "/bin/sh", "-c", "exit 72")
706
707	if err == nil {
708		c.Fatal("should not have a non nil error")
709	}
710	if exit != 72 {
711		c.Fatalf("expected exit code 72 received %d", exit)
712	}
713}
714
715func (s *DockerSuite) TestRunUserDefaults(c *check.C) {
716	expected := "uid=0(root) gid=0(root)"
717	if testEnv.OSType == "windows" {
718		expected = "uid=1000(ContainerAdministrator) gid=1000(ContainerAdministrator)"
719	}
720	out, _ := dockerCmd(c, "run", "busybox", "id")
721	if !strings.Contains(out, expected) {
722		c.Fatalf("expected '%s' got %s", expected, out)
723	}
724}
725
726func (s *DockerSuite) TestRunUserByName(c *check.C) {
727	// TODO Windows: This test cannot run on a Windows daemon as Windows does
728	// not support the use of -u
729	testRequires(c, DaemonIsLinux)
730	out, _ := dockerCmd(c, "run", "-u", "root", "busybox", "id")
731	if !strings.Contains(out, "uid=0(root) gid=0(root)") {
732		c.Fatalf("expected root user got %s", out)
733	}
734}
735
736func (s *DockerSuite) TestRunUserByID(c *check.C) {
737	// TODO Windows: This test cannot run on a Windows daemon as Windows does
738	// not support the use of -u
739	testRequires(c, DaemonIsLinux)
740	out, _ := dockerCmd(c, "run", "-u", "1", "busybox", "id")
741	if !strings.Contains(out, "uid=1(daemon) gid=1(daemon)") {
742		c.Fatalf("expected daemon user got %s", out)
743	}
744}
745
746func (s *DockerSuite) TestRunUserByIDBig(c *check.C) {
747	// TODO Windows: This test cannot run on a Windows daemon as Windows does
748	// not support the use of -u
749	testRequires(c, DaemonIsLinux, NotArm)
750	out, _, err := dockerCmdWithError("run", "-u", "2147483648", "busybox", "id")
751	if err == nil {
752		c.Fatal("No error, but must be.", out)
753	}
754	if !strings.Contains(strings.ToLower(out), "uids and gids must be in range") {
755		c.Fatalf("expected error about uids range, got %s", out)
756	}
757}
758
759func (s *DockerSuite) TestRunUserByIDNegative(c *check.C) {
760	// TODO Windows: This test cannot run on a Windows daemon as Windows does
761	// not support the use of -u
762	testRequires(c, DaemonIsLinux)
763	out, _, err := dockerCmdWithError("run", "-u", "-1", "busybox", "id")
764	if err == nil {
765		c.Fatal("No error, but must be.", out)
766	}
767	if !strings.Contains(strings.ToLower(out), "uids and gids must be in range") {
768		c.Fatalf("expected error about uids range, got %s", out)
769	}
770}
771
772func (s *DockerSuite) TestRunUserByIDZero(c *check.C) {
773	// TODO Windows: This test cannot run on a Windows daemon as Windows does
774	// not support the use of -u
775	testRequires(c, DaemonIsLinux)
776	out, _, err := dockerCmdWithError("run", "-u", "0", "busybox", "id")
777	if err != nil {
778		c.Fatal(err, out)
779	}
780	if !strings.Contains(out, "uid=0(root) gid=0(root) groups=10(wheel)") {
781		c.Fatalf("expected daemon user got %s", out)
782	}
783}
784
785func (s *DockerSuite) TestRunUserNotFound(c *check.C) {
786	// TODO Windows: This test cannot run on a Windows daemon as Windows does
787	// not support the use of -u
788	testRequires(c, DaemonIsLinux)
789	_, _, err := dockerCmdWithError("run", "-u", "notme", "busybox", "id")
790	if err == nil {
791		c.Fatal("unknown user should cause container to fail")
792	}
793}
794
795func (s *DockerSuite) TestRunTwoConcurrentContainers(c *check.C) {
796	sleepTime := "2"
797	group := sync.WaitGroup{}
798	group.Add(2)
799
800	errChan := make(chan error, 2)
801	for i := 0; i < 2; i++ {
802		go func() {
803			defer group.Done()
804			_, _, err := dockerCmdWithError("run", "busybox", "sleep", sleepTime)
805			errChan <- err
806		}()
807	}
808
809	group.Wait()
810	close(errChan)
811
812	for err := range errChan {
813		c.Assert(err, check.IsNil)
814	}
815}
816
817func (s *DockerSuite) TestRunEnvironment(c *check.C) {
818	// TODO Windows: Environment handling is different between Linux and
819	// Windows and this test relies currently on unix functionality.
820	testRequires(c, DaemonIsLinux)
821	result := icmd.RunCmd(icmd.Cmd{
822		Command: []string{dockerBinary, "run", "-h", "testing", "-e=FALSE=true", "-e=TRUE", "-e=TRICKY", "-e=HOME=", "busybox", "env"},
823		Env: append(os.Environ(),
824			"TRUE=false",
825			"TRICKY=tri\ncky\n",
826		),
827	})
828	result.Assert(c, icmd.Success)
829
830	actualEnv := strings.Split(strings.TrimSuffix(result.Stdout(), "\n"), "\n")
831	sort.Strings(actualEnv)
832
833	goodEnv := []string{
834		// The first two should not be tested here, those are "inherent" environment variable. This test validates
835		// the -e behavior, not the default environment variable (that could be subject to change)
836		"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
837		"HOSTNAME=testing",
838		"FALSE=true",
839		"TRUE=false",
840		"TRICKY=tri",
841		"cky",
842		"",
843		"HOME=/root",
844	}
845	sort.Strings(goodEnv)
846	if len(goodEnv) != len(actualEnv) {
847		c.Fatalf("Wrong environment: should be %d variables, not %d: %q", len(goodEnv), len(actualEnv), strings.Join(actualEnv, ", "))
848	}
849	for i := range goodEnv {
850		if actualEnv[i] != goodEnv[i] {
851			c.Fatalf("Wrong environment variable: should be %s, not %s", goodEnv[i], actualEnv[i])
852		}
853	}
854}
855
856func (s *DockerSuite) TestRunEnvironmentErase(c *check.C) {
857	// TODO Windows: Environment handling is different between Linux and
858	// Windows and this test relies currently on unix functionality.
859	testRequires(c, DaemonIsLinux)
860
861	// Test to make sure that when we use -e on env vars that are
862	// not set in our local env that they're removed (if present) in
863	// the container
864
865	result := icmd.RunCmd(icmd.Cmd{
866		Command: []string{dockerBinary, "run", "-e", "FOO", "-e", "HOSTNAME", "busybox", "env"},
867		Env:     appendBaseEnv(true),
868	})
869	result.Assert(c, icmd.Success)
870
871	actualEnv := strings.Split(strings.TrimSpace(result.Combined()), "\n")
872	sort.Strings(actualEnv)
873
874	goodEnv := []string{
875		"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
876		"HOME=/root",
877	}
878	sort.Strings(goodEnv)
879	if len(goodEnv) != len(actualEnv) {
880		c.Fatalf("Wrong environment: should be %d variables, not %d: %q", len(goodEnv), len(actualEnv), strings.Join(actualEnv, ", "))
881	}
882	for i := range goodEnv {
883		if actualEnv[i] != goodEnv[i] {
884			c.Fatalf("Wrong environment variable: should be %s, not %s", goodEnv[i], actualEnv[i])
885		}
886	}
887}
888
889func (s *DockerSuite) TestRunEnvironmentOverride(c *check.C) {
890	// TODO Windows: Environment handling is different between Linux and
891	// Windows and this test relies currently on unix functionality.
892	testRequires(c, DaemonIsLinux)
893
894	// Test to make sure that when we use -e on env vars that are
895	// already in the env that we're overriding them
896
897	result := icmd.RunCmd(icmd.Cmd{
898		Command: []string{dockerBinary, "run", "-e", "HOSTNAME", "-e", "HOME=/root2", "busybox", "env"},
899		Env:     appendBaseEnv(true, "HOSTNAME=bar"),
900	})
901	result.Assert(c, icmd.Success)
902
903	actualEnv := strings.Split(strings.TrimSpace(result.Combined()), "\n")
904	sort.Strings(actualEnv)
905
906	goodEnv := []string{
907		"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
908		"HOME=/root2",
909		"HOSTNAME=bar",
910	}
911	sort.Strings(goodEnv)
912	if len(goodEnv) != len(actualEnv) {
913		c.Fatalf("Wrong environment: should be %d variables, not %d: %q", len(goodEnv), len(actualEnv), strings.Join(actualEnv, ", "))
914	}
915	for i := range goodEnv {
916		if actualEnv[i] != goodEnv[i] {
917			c.Fatalf("Wrong environment variable: should be %s, not %s", goodEnv[i], actualEnv[i])
918		}
919	}
920}
921
922func (s *DockerSuite) TestRunContainerNetwork(c *check.C) {
923	if testEnv.OSType == "windows" {
924		// Windows busybox does not have ping. Use built in ping instead.
925		dockerCmd(c, "run", testEnv.PlatformDefaults.BaseImage, "ping", "-n", "1", "127.0.0.1")
926	} else {
927		dockerCmd(c, "run", "busybox", "ping", "-c", "1", "127.0.0.1")
928	}
929}
930
931func (s *DockerSuite) TestRunNetHostNotAllowedWithLinks(c *check.C) {
932	// TODO Windows: This is Linux specific as --link is not supported and
933	// this will be deprecated in favor of container networking model.
934	testRequires(c, DaemonIsLinux, NotUserNamespace)
935	dockerCmd(c, "run", "--name", "linked", "busybox", "true")
936
937	_, _, err := dockerCmdWithError("run", "--net=host", "--link", "linked:linked", "busybox", "true")
938	if err == nil {
939		c.Fatal("Expected error")
940	}
941}
942
943// #7851 hostname outside container shows FQDN, inside only shortname
944// For testing purposes it is not required to set host's hostname directly
945// and use "--net=host" (as the original issue submitter did), as the same
946// codepath is executed with "docker run -h <hostname>".  Both were manually
947// tested, but this testcase takes the simpler path of using "run -h .."
948func (s *DockerSuite) TestRunFullHostnameSet(c *check.C) {
949	// TODO Windows: -h is not yet functional.
950	testRequires(c, DaemonIsLinux)
951	out, _ := dockerCmd(c, "run", "-h", "foo.bar.baz", "busybox", "hostname")
952	if actual := strings.Trim(out, "\r\n"); actual != "foo.bar.baz" {
953		c.Fatalf("expected hostname 'foo.bar.baz', received %s", actual)
954	}
955}
956
957func (s *DockerSuite) TestRunPrivilegedCanMknod(c *check.C) {
958	// Not applicable for Windows as Windows daemon does not support
959	// the concept of --privileged, and mknod is a Unix concept.
960	testRequires(c, DaemonIsLinux, NotUserNamespace)
961	out, _ := dockerCmd(c, "run", "--privileged", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok")
962	if actual := strings.Trim(out, "\r\n"); actual != "ok" {
963		c.Fatalf("expected output ok received %s", actual)
964	}
965}
966
967func (s *DockerSuite) TestRunUnprivilegedCanMknod(c *check.C) {
968	// Not applicable for Windows as Windows daemon does not support
969	// the concept of --privileged, and mknod is a Unix concept.
970	testRequires(c, DaemonIsLinux, NotUserNamespace)
971	out, _ := dockerCmd(c, "run", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok")
972	if actual := strings.Trim(out, "\r\n"); actual != "ok" {
973		c.Fatalf("expected output ok received %s", actual)
974	}
975}
976
977func (s *DockerSuite) TestRunCapDropInvalid(c *check.C) {
978	// Not applicable for Windows as there is no concept of --cap-drop
979	testRequires(c, DaemonIsLinux)
980	out, _, err := dockerCmdWithError("run", "--cap-drop=CHPASS", "busybox", "ls")
981	if err == nil {
982		c.Fatal(err, out)
983	}
984}
985
986func (s *DockerSuite) TestRunCapDropCannotMknod(c *check.C) {
987	// Not applicable for Windows as there is no concept of --cap-drop or mknod
988	testRequires(c, DaemonIsLinux)
989	out, _, err := dockerCmdWithError("run", "--cap-drop=MKNOD", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok")
990
991	if err == nil {
992		c.Fatal(err, out)
993	}
994	if actual := strings.Trim(out, "\r\n"); actual == "ok" {
995		c.Fatalf("expected output not ok received %s", actual)
996	}
997}
998
999func (s *DockerSuite) TestRunCapDropCannotMknodLowerCase(c *check.C) {
1000	// Not applicable for Windows as there is no concept of --cap-drop or mknod
1001	testRequires(c, DaemonIsLinux)
1002	out, _, err := dockerCmdWithError("run", "--cap-drop=mknod", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok")
1003
1004	if err == nil {
1005		c.Fatal(err, out)
1006	}
1007	if actual := strings.Trim(out, "\r\n"); actual == "ok" {
1008		c.Fatalf("expected output not ok received %s", actual)
1009	}
1010}
1011
1012func (s *DockerSuite) TestRunCapDropALLCannotMknod(c *check.C) {
1013	// Not applicable for Windows as there is no concept of --cap-drop or mknod
1014	testRequires(c, DaemonIsLinux)
1015	out, _, err := dockerCmdWithError("run", "--cap-drop=ALL", "--cap-add=SETGID", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok")
1016	if err == nil {
1017		c.Fatal(err, out)
1018	}
1019	if actual := strings.Trim(out, "\r\n"); actual == "ok" {
1020		c.Fatalf("expected output not ok received %s", actual)
1021	}
1022}
1023
1024func (s *DockerSuite) TestRunCapDropALLAddMknodCanMknod(c *check.C) {
1025	// Not applicable for Windows as there is no concept of --cap-drop or mknod
1026	testRequires(c, DaemonIsLinux, NotUserNamespace)
1027	out, _ := dockerCmd(c, "run", "--cap-drop=ALL", "--cap-add=MKNOD", "--cap-add=SETGID", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok")
1028
1029	if actual := strings.Trim(out, "\r\n"); actual != "ok" {
1030		c.Fatalf("expected output ok received %s", actual)
1031	}
1032}
1033
1034func (s *DockerSuite) TestRunCapAddInvalid(c *check.C) {
1035	// Not applicable for Windows as there is no concept of --cap-add
1036	testRequires(c, DaemonIsLinux)
1037	out, _, err := dockerCmdWithError("run", "--cap-add=CHPASS", "busybox", "ls")
1038	if err == nil {
1039		c.Fatal(err, out)
1040	}
1041}
1042
1043func (s *DockerSuite) TestRunCapAddCanDownInterface(c *check.C) {
1044	// Not applicable for Windows as there is no concept of --cap-add
1045	testRequires(c, DaemonIsLinux)
1046	out, _ := dockerCmd(c, "run", "--cap-add=NET_ADMIN", "busybox", "sh", "-c", "ip link set eth0 down && echo ok")
1047
1048	if actual := strings.Trim(out, "\r\n"); actual != "ok" {
1049		c.Fatalf("expected output ok received %s", actual)
1050	}
1051}
1052
1053func (s *DockerSuite) TestRunCapAddALLCanDownInterface(c *check.C) {
1054	// Not applicable for Windows as there is no concept of --cap-add
1055	testRequires(c, DaemonIsLinux)
1056	out, _ := dockerCmd(c, "run", "--cap-add=ALL", "busybox", "sh", "-c", "ip link set eth0 down && echo ok")
1057
1058	if actual := strings.Trim(out, "\r\n"); actual != "ok" {
1059		c.Fatalf("expected output ok received %s", actual)
1060	}
1061}
1062
1063func (s *DockerSuite) TestRunCapAddALLDropNetAdminCanDownInterface(c *check.C) {
1064	// Not applicable for Windows as there is no concept of --cap-add
1065	testRequires(c, DaemonIsLinux)
1066	out, _, err := dockerCmdWithError("run", "--cap-add=ALL", "--cap-drop=NET_ADMIN", "busybox", "sh", "-c", "ip link set eth0 down && echo ok")
1067	if err == nil {
1068		c.Fatal(err, out)
1069	}
1070	if actual := strings.Trim(out, "\r\n"); actual == "ok" {
1071		c.Fatalf("expected output not ok received %s", actual)
1072	}
1073}
1074
1075func (s *DockerSuite) TestRunGroupAdd(c *check.C) {
1076	// Not applicable for Windows as there is no concept of --group-add
1077	testRequires(c, DaemonIsLinux)
1078	out, _ := dockerCmd(c, "run", "--group-add=audio", "--group-add=staff", "--group-add=777", "busybox", "sh", "-c", "id")
1079
1080	groupsList := "uid=0(root) gid=0(root) groups=10(wheel),29(audio),50(staff),777"
1081	if actual := strings.Trim(out, "\r\n"); actual != groupsList {
1082		c.Fatalf("expected output %s received %s", groupsList, actual)
1083	}
1084}
1085
1086func (s *DockerSuite) TestRunPrivilegedCanMount(c *check.C) {
1087	// Not applicable for Windows as there is no concept of --privileged
1088	testRequires(c, DaemonIsLinux, NotUserNamespace)
1089	out, _ := dockerCmd(c, "run", "--privileged", "busybox", "sh", "-c", "mount -t tmpfs none /tmp && echo ok")
1090
1091	if actual := strings.Trim(out, "\r\n"); actual != "ok" {
1092		c.Fatalf("expected output ok received %s", actual)
1093	}
1094}
1095
1096func (s *DockerSuite) TestRunUnprivilegedCannotMount(c *check.C) {
1097	// Not applicable for Windows as there is no concept of unprivileged
1098	testRequires(c, DaemonIsLinux)
1099	out, _, err := dockerCmdWithError("run", "busybox", "sh", "-c", "mount -t tmpfs none /tmp && echo ok")
1100
1101	if err == nil {
1102		c.Fatal(err, out)
1103	}
1104	if actual := strings.Trim(out, "\r\n"); actual == "ok" {
1105		c.Fatalf("expected output not ok received %s", actual)
1106	}
1107}
1108
1109func (s *DockerSuite) TestRunSysNotWritableInNonPrivilegedContainers(c *check.C) {
1110	// Not applicable for Windows as there is no concept of unprivileged
1111	testRequires(c, DaemonIsLinux, NotArm)
1112	if _, code, err := dockerCmdWithError("run", "busybox", "touch", "/sys/kernel/profiling"); err == nil || code == 0 {
1113		c.Fatal("sys should not be writable in a non privileged container")
1114	}
1115}
1116
1117func (s *DockerSuite) TestRunSysWritableInPrivilegedContainers(c *check.C) {
1118	// Not applicable for Windows as there is no concept of unprivileged
1119	testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm)
1120	if _, code, err := dockerCmdWithError("run", "--privileged", "busybox", "touch", "/sys/kernel/profiling"); err != nil || code != 0 {
1121		c.Fatalf("sys should be writable in privileged container")
1122	}
1123}
1124
1125func (s *DockerSuite) TestRunProcNotWritableInNonPrivilegedContainers(c *check.C) {
1126	// Not applicable for Windows as there is no concept of unprivileged
1127	testRequires(c, DaemonIsLinux)
1128	if _, code, err := dockerCmdWithError("run", "busybox", "touch", "/proc/sysrq-trigger"); err == nil || code == 0 {
1129		c.Fatal("proc should not be writable in a non privileged container")
1130	}
1131}
1132
1133func (s *DockerSuite) TestRunProcWritableInPrivilegedContainers(c *check.C) {
1134	// Not applicable for Windows as there is no concept of --privileged
1135	testRequires(c, DaemonIsLinux, NotUserNamespace)
1136	if _, code := dockerCmd(c, "run", "--privileged", "busybox", "sh", "-c", "touch /proc/sysrq-trigger"); code != 0 {
1137		c.Fatalf("proc should be writable in privileged container")
1138	}
1139}
1140
1141func (s *DockerSuite) TestRunDeviceNumbers(c *check.C) {
1142	// Not applicable on Windows as /dev/ is a Unix specific concept
1143	// TODO: NotUserNamespace could be removed here if "root" "root" is replaced w user
1144	testRequires(c, DaemonIsLinux, NotUserNamespace)
1145	out, _ := dockerCmd(c, "run", "busybox", "sh", "-c", "ls -l /dev/null")
1146	deviceLineFields := strings.Fields(out)
1147	deviceLineFields[6] = ""
1148	deviceLineFields[7] = ""
1149	deviceLineFields[8] = ""
1150	expected := []string{"crw-rw-rw-", "1", "root", "root", "1,", "3", "", "", "", "/dev/null"}
1151
1152	if !(reflect.DeepEqual(deviceLineFields, expected)) {
1153		c.Fatalf("expected output\ncrw-rw-rw- 1 root root 1, 3 May 24 13:29 /dev/null\n received\n %s\n", out)
1154	}
1155}
1156
1157func (s *DockerSuite) TestRunThatCharacterDevicesActLikeCharacterDevices(c *check.C) {
1158	// Not applicable on Windows as /dev/ is a Unix specific concept
1159	testRequires(c, DaemonIsLinux)
1160	out, _ := dockerCmd(c, "run", "busybox", "sh", "-c", "dd if=/dev/zero of=/zero bs=1k count=5 2> /dev/null ; du -h /zero")
1161	if actual := strings.Trim(out, "\r\n"); actual[0] == '0' {
1162		c.Fatalf("expected a new file called /zero to be create that is greater than 0 bytes long, but du says: %s", actual)
1163	}
1164}
1165
1166func (s *DockerSuite) TestRunUnprivilegedWithChroot(c *check.C) {
1167	// Not applicable on Windows as it does not support chroot
1168	testRequires(c, DaemonIsLinux)
1169	dockerCmd(c, "run", "busybox", "chroot", "/", "true")
1170}
1171
1172func (s *DockerSuite) TestRunAddingOptionalDevices(c *check.C) {
1173	// Not applicable on Windows as Windows does not support --device
1174	testRequires(c, DaemonIsLinux, NotUserNamespace)
1175	out, _ := dockerCmd(c, "run", "--device", "/dev/zero:/dev/nulo", "busybox", "sh", "-c", "ls /dev/nulo")
1176	if actual := strings.Trim(out, "\r\n"); actual != "/dev/nulo" {
1177		c.Fatalf("expected output /dev/nulo, received %s", actual)
1178	}
1179}
1180
1181func (s *DockerSuite) TestRunAddingOptionalDevicesNoSrc(c *check.C) {
1182	// Not applicable on Windows as Windows does not support --device
1183	testRequires(c, DaemonIsLinux, NotUserNamespace)
1184	out, _ := dockerCmd(c, "run", "--device", "/dev/zero:rw", "busybox", "sh", "-c", "ls /dev/zero")
1185	if actual := strings.Trim(out, "\r\n"); actual != "/dev/zero" {
1186		c.Fatalf("expected output /dev/zero, received %s", actual)
1187	}
1188}
1189
1190func (s *DockerSuite) TestRunAddingOptionalDevicesInvalidMode(c *check.C) {
1191	// Not applicable on Windows as Windows does not support --device
1192	testRequires(c, DaemonIsLinux, NotUserNamespace)
1193	_, _, err := dockerCmdWithError("run", "--device", "/dev/zero:ro", "busybox", "sh", "-c", "ls /dev/zero")
1194	if err == nil {
1195		c.Fatalf("run container with device mode ro should fail")
1196	}
1197}
1198
1199func (s *DockerSuite) TestRunModeHostname(c *check.C) {
1200	// Not applicable on Windows as Windows does not support -h
1201	testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace)
1202
1203	out, _ := dockerCmd(c, "run", "-h=testhostname", "busybox", "cat", "/etc/hostname")
1204
1205	if actual := strings.Trim(out, "\r\n"); actual != "testhostname" {
1206		c.Fatalf("expected 'testhostname', but says: %q", actual)
1207	}
1208
1209	out, _ = dockerCmd(c, "run", "--net=host", "busybox", "cat", "/etc/hostname")
1210
1211	hostname, err := os.Hostname()
1212	if err != nil {
1213		c.Fatal(err)
1214	}
1215	if actual := strings.Trim(out, "\r\n"); actual != hostname {
1216		c.Fatalf("expected %q, but says: %q", hostname, actual)
1217	}
1218}
1219
1220func (s *DockerSuite) TestRunRootWorkdir(c *check.C) {
1221	out, _ := dockerCmd(c, "run", "--workdir", "/", "busybox", "pwd")
1222	expected := "/\n"
1223	if testEnv.OSType == "windows" {
1224		expected = "C:" + expected
1225	}
1226	if out != expected {
1227		c.Fatalf("pwd returned %q (expected %s)", s, expected)
1228	}
1229}
1230
1231func (s *DockerSuite) TestRunAllowBindMountingRoot(c *check.C) {
1232	if testEnv.OSType == "windows" {
1233		// Windows busybox will fail with Permission Denied on items such as pagefile.sys
1234		dockerCmd(c, "run", "-v", `c:\:c:\host`, testEnv.PlatformDefaults.BaseImage, "cmd", "-c", "dir", `c:\host`)
1235	} else {
1236		dockerCmd(c, "run", "-v", "/:/host", "busybox", "ls", "/host")
1237	}
1238}
1239
1240func (s *DockerSuite) TestRunDisallowBindMountingRootToRoot(c *check.C) {
1241	mount := "/:/"
1242	targetDir := "/host"
1243	if testEnv.OSType == "windows" {
1244		mount = `c:\:c\`
1245		targetDir = "c:/host" // Forward slash as using busybox
1246	}
1247	out, _, err := dockerCmdWithError("run", "-v", mount, "busybox", "ls", targetDir)
1248	if err == nil {
1249		c.Fatal(out, err)
1250	}
1251}
1252
1253// Verify that a container gets default DNS when only localhost resolvers exist
1254func (s *DockerSuite) TestRunDNSDefaultOptions(c *check.C) {
1255	// Not applicable on Windows as this is testing Unix specific functionality
1256	testRequires(c, SameHostDaemon, DaemonIsLinux)
1257
1258	// preserve original resolv.conf for restoring after test
1259	origResolvConf, err := ioutil.ReadFile("/etc/resolv.conf")
1260	if os.IsNotExist(err) {
1261		c.Fatalf("/etc/resolv.conf does not exist")
1262	}
1263	// defer restored original conf
1264	defer func() {
1265		if err := ioutil.WriteFile("/etc/resolv.conf", origResolvConf, 0644); err != nil {
1266			c.Fatal(err)
1267		}
1268	}()
1269
1270	// test 3 cases: standard IPv4 localhost, commented out localhost, and IPv6 localhost
1271	// 2 are removed from the file at container start, and the 3rd (commented out) one is ignored by
1272	// GetNameservers(), leading to a replacement of nameservers with the default set
1273	tmpResolvConf := []byte("nameserver 127.0.0.1\n#nameserver 127.0.2.1\nnameserver ::1")
1274	if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf, 0644); err != nil {
1275		c.Fatal(err)
1276	}
1277
1278	actual, _ := dockerCmd(c, "run", "busybox", "cat", "/etc/resolv.conf")
1279	// check that the actual defaults are appended to the commented out
1280	// localhost resolver (which should be preserved)
1281	// NOTE: if we ever change the defaults from google dns, this will break
1282	expected := "#nameserver 127.0.2.1\n\nnameserver 8.8.8.8\nnameserver 8.8.4.4\n"
1283	if actual != expected {
1284		c.Fatalf("expected resolv.conf be: %q, but was: %q", expected, actual)
1285	}
1286}
1287
1288func (s *DockerSuite) TestRunDNSOptions(c *check.C) {
1289	// Not applicable on Windows as Windows does not support --dns*, or
1290	// the Unix-specific functionality of resolv.conf.
1291	testRequires(c, DaemonIsLinux)
1292	result := cli.DockerCmd(c, "run", "--dns=127.0.0.1", "--dns-search=mydomain", "--dns-opt=ndots:9", "busybox", "cat", "/etc/resolv.conf")
1293
1294	// The client will get a warning on stderr when setting DNS to a localhost address; verify this:
1295	if !strings.Contains(result.Stderr(), "Localhost DNS setting") {
1296		c.Fatalf("Expected warning on stderr about localhost resolver, but got %q", result.Stderr())
1297	}
1298
1299	actual := strings.Replace(strings.Trim(result.Stdout(), "\r\n"), "\n", " ", -1)
1300	if actual != "search mydomain nameserver 127.0.0.1 options ndots:9" {
1301		c.Fatalf("expected 'search mydomain nameserver 127.0.0.1 options ndots:9', but says: %q", actual)
1302	}
1303
1304	out := cli.DockerCmd(c, "run", "--dns=1.1.1.1", "--dns-search=.", "--dns-opt=ndots:3", "busybox", "cat", "/etc/resolv.conf").Combined()
1305
1306	actual = strings.Replace(strings.Trim(strings.Trim(out, "\r\n"), " "), "\n", " ", -1)
1307	if actual != "nameserver 1.1.1.1 options ndots:3" {
1308		c.Fatalf("expected 'nameserver 1.1.1.1 options ndots:3', but says: %q", actual)
1309	}
1310}
1311
1312func (s *DockerSuite) TestRunDNSRepeatOptions(c *check.C) {
1313	testRequires(c, DaemonIsLinux)
1314	out := cli.DockerCmd(c, "run", "--dns=1.1.1.1", "--dns=2.2.2.2", "--dns-search=mydomain", "--dns-search=mydomain2", "--dns-opt=ndots:9", "--dns-opt=timeout:3", "busybox", "cat", "/etc/resolv.conf").Stdout()
1315
1316	actual := strings.Replace(strings.Trim(out, "\r\n"), "\n", " ", -1)
1317	if actual != "search mydomain mydomain2 nameserver 1.1.1.1 nameserver 2.2.2.2 options ndots:9 timeout:3" {
1318		c.Fatalf("expected 'search mydomain mydomain2 nameserver 1.1.1.1 nameserver 2.2.2.2 options ndots:9 timeout:3', but says: %q", actual)
1319	}
1320}
1321
1322func (s *DockerSuite) TestRunDNSOptionsBasedOnHostResolvConf(c *check.C) {
1323	// Not applicable on Windows as testing Unix specific functionality
1324	testRequires(c, SameHostDaemon, DaemonIsLinux)
1325
1326	origResolvConf, err := ioutil.ReadFile("/etc/resolv.conf")
1327	if os.IsNotExist(err) {
1328		c.Fatalf("/etc/resolv.conf does not exist")
1329	}
1330
1331	hostNameservers := resolvconf.GetNameservers(origResolvConf, types.IP)
1332	hostSearch := resolvconf.GetSearchDomains(origResolvConf)
1333
1334	var out string
1335	out, _ = dockerCmd(c, "run", "--dns=127.0.0.1", "busybox", "cat", "/etc/resolv.conf")
1336
1337	if actualNameservers := resolvconf.GetNameservers([]byte(out), types.IP); string(actualNameservers[0]) != "127.0.0.1" {
1338		c.Fatalf("expected '127.0.0.1', but says: %q", string(actualNameservers[0]))
1339	}
1340
1341	actualSearch := resolvconf.GetSearchDomains([]byte(out))
1342	if len(actualSearch) != len(hostSearch) {
1343		c.Fatalf("expected %q search domain(s), but it has: %q", len(hostSearch), len(actualSearch))
1344	}
1345	for i := range actualSearch {
1346		if actualSearch[i] != hostSearch[i] {
1347			c.Fatalf("expected %q domain, but says: %q", actualSearch[i], hostSearch[i])
1348		}
1349	}
1350
1351	out, _ = dockerCmd(c, "run", "--dns-search=mydomain", "busybox", "cat", "/etc/resolv.conf")
1352
1353	actualNameservers := resolvconf.GetNameservers([]byte(out), types.IP)
1354	if len(actualNameservers) != len(hostNameservers) {
1355		c.Fatalf("expected %q nameserver(s), but it has: %q", len(hostNameservers), len(actualNameservers))
1356	}
1357	for i := range actualNameservers {
1358		if actualNameservers[i] != hostNameservers[i] {
1359			c.Fatalf("expected %q nameserver, but says: %q", actualNameservers[i], hostNameservers[i])
1360		}
1361	}
1362
1363	if actualSearch = resolvconf.GetSearchDomains([]byte(out)); string(actualSearch[0]) != "mydomain" {
1364		c.Fatalf("expected 'mydomain', but says: %q", string(actualSearch[0]))
1365	}
1366
1367	// test with file
1368	tmpResolvConf := []byte("search example.com\nnameserver 12.34.56.78\nnameserver 127.0.0.1")
1369	if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf, 0644); err != nil {
1370		c.Fatal(err)
1371	}
1372	// put the old resolvconf back
1373	defer func() {
1374		if err := ioutil.WriteFile("/etc/resolv.conf", origResolvConf, 0644); err != nil {
1375			c.Fatal(err)
1376		}
1377	}()
1378
1379	resolvConf, err := ioutil.ReadFile("/etc/resolv.conf")
1380	if os.IsNotExist(err) {
1381		c.Fatalf("/etc/resolv.conf does not exist")
1382	}
1383
1384	hostSearch = resolvconf.GetSearchDomains(resolvConf)
1385
1386	out, _ = dockerCmd(c, "run", "busybox", "cat", "/etc/resolv.conf")
1387	if actualNameservers = resolvconf.GetNameservers([]byte(out), types.IP); string(actualNameservers[0]) != "12.34.56.78" || len(actualNameservers) != 1 {
1388		c.Fatalf("expected '12.34.56.78', but has: %v", actualNameservers)
1389	}
1390
1391	actualSearch = resolvconf.GetSearchDomains([]byte(out))
1392	if len(actualSearch) != len(hostSearch) {
1393		c.Fatalf("expected %q search domain(s), but it has: %q", len(hostSearch), len(actualSearch))
1394	}
1395	for i := range actualSearch {
1396		if actualSearch[i] != hostSearch[i] {
1397			c.Fatalf("expected %q domain, but says: %q", actualSearch[i], hostSearch[i])
1398		}
1399	}
1400}
1401
1402// Test to see if a non-root user can resolve a DNS name. Also
1403// check if the container resolv.conf file has at least 0644 perm.
1404func (s *DockerSuite) TestRunNonRootUserResolvName(c *check.C) {
1405	// Not applicable on Windows as Windows does not support --user
1406	testRequires(c, SameHostDaemon, Network, DaemonIsLinux, NotArm)
1407
1408	dockerCmd(c, "run", "--name=testperm", "--user=nobody", "busybox", "nslookup", "apt.dockerproject.org")
1409
1410	cID := getIDByName(c, "testperm")
1411
1412	fmode := (os.FileMode)(0644)
1413	finfo, err := os.Stat(containerStorageFile(cID, "resolv.conf"))
1414	if err != nil {
1415		c.Fatal(err)
1416	}
1417
1418	if (finfo.Mode() & fmode) != fmode {
1419		c.Fatalf("Expected container resolv.conf mode to be at least %s, instead got %s", fmode.String(), finfo.Mode().String())
1420	}
1421}
1422
1423// Test if container resolv.conf gets updated the next time it restarts
1424// if host /etc/resolv.conf has changed. This only applies if the container
1425// uses the host's /etc/resolv.conf and does not have any dns options provided.
1426func (s *DockerSuite) TestRunResolvconfUpdate(c *check.C) {
1427	// Not applicable on Windows as testing unix specific functionality
1428	testRequires(c, SameHostDaemon, DaemonIsLinux)
1429	c.Skip("Unstable test, to be re-activated once #19937 is resolved")
1430
1431	tmpResolvConf := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\n")
1432	tmpLocalhostResolvConf := []byte("nameserver 127.0.0.1")
1433
1434	//take a copy of resolv.conf for restoring after test completes
1435	resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf")
1436	if err != nil {
1437		c.Fatal(err)
1438	}
1439
1440	// This test case is meant to test monitoring resolv.conf when it is
1441	// a regular file not a bind mounc. So we unmount resolv.conf and replace
1442	// it with a file containing the original settings.
1443	mounted, err := mount.Mounted("/etc/resolv.conf")
1444	if err != nil {
1445		c.Fatal(err)
1446	}
1447	if mounted {
1448		icmd.RunCommand("umount", "/etc/resolv.conf").Assert(c, icmd.Success)
1449	}
1450
1451	//cleanup
1452	defer func() {
1453		if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil {
1454			c.Fatal(err)
1455		}
1456	}()
1457
1458	//1. test that a restarting container gets an updated resolv.conf
1459	dockerCmd(c, "run", "--name=first", "busybox", "true")
1460	containerID1 := getIDByName(c, "first")
1461
1462	// replace resolv.conf with our temporary copy
1463	bytesResolvConf := []byte(tmpResolvConf)
1464	if err := ioutil.WriteFile("/etc/resolv.conf", bytesResolvConf, 0644); err != nil {
1465		c.Fatal(err)
1466	}
1467
1468	// start the container again to pickup changes
1469	dockerCmd(c, "start", "first")
1470
1471	// check for update in container
1472	containerResolv := readContainerFile(c, containerID1, "resolv.conf")
1473	if !bytes.Equal(containerResolv, bytesResolvConf) {
1474		c.Fatalf("Restarted container does not have updated resolv.conf; expected %q, got %q", tmpResolvConf, string(containerResolv))
1475	}
1476
1477	/*	//make a change to resolv.conf (in this case replacing our tmp copy with orig copy)
1478		if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil {
1479						c.Fatal(err)
1480								} */
1481	//2. test that a restarting container does not receive resolv.conf updates
1482	//   if it modified the container copy of the starting point resolv.conf
1483	dockerCmd(c, "run", "--name=second", "busybox", "sh", "-c", "echo 'search mylittlepony.com' >>/etc/resolv.conf")
1484	containerID2 := getIDByName(c, "second")
1485
1486	//make a change to resolv.conf (in this case replacing our tmp copy with orig copy)
1487	if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil {
1488		c.Fatal(err)
1489	}
1490
1491	// start the container again
1492	dockerCmd(c, "start", "second")
1493
1494	// check for update in container
1495	containerResolv = readContainerFile(c, containerID2, "resolv.conf")
1496	if bytes.Equal(containerResolv, resolvConfSystem) {
1497		c.Fatalf("Container's resolv.conf should not have been updated with host resolv.conf: %q", string(containerResolv))
1498	}
1499
1500	//3. test that a running container's resolv.conf is not modified while running
1501	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
1502	runningContainerID := strings.TrimSpace(out)
1503
1504	// replace resolv.conf
1505	if err := ioutil.WriteFile("/etc/resolv.conf", bytesResolvConf, 0644); err != nil {
1506		c.Fatal(err)
1507	}
1508
1509	// check for update in container
1510	containerResolv = readContainerFile(c, runningContainerID, "resolv.conf")
1511	if bytes.Equal(containerResolv, bytesResolvConf) {
1512		c.Fatalf("Running container should not have updated resolv.conf; expected %q, got %q", string(resolvConfSystem), string(containerResolv))
1513	}
1514
1515	//4. test that a running container's resolv.conf is updated upon restart
1516	//   (the above container is still running..)
1517	dockerCmd(c, "restart", runningContainerID)
1518
1519	// check for update in container
1520	containerResolv = readContainerFile(c, runningContainerID, "resolv.conf")
1521	if !bytes.Equal(containerResolv, bytesResolvConf) {
1522		c.Fatalf("Restarted container should have updated resolv.conf; expected %q, got %q", string(bytesResolvConf), string(containerResolv))
1523	}
1524
1525	//5. test that additions of a localhost resolver are cleaned from
1526	//   host resolv.conf before updating container's resolv.conf copies
1527
1528	// replace resolv.conf with a localhost-only nameserver copy
1529	bytesResolvConf = []byte(tmpLocalhostResolvConf)
1530	if err = ioutil.WriteFile("/etc/resolv.conf", bytesResolvConf, 0644); err != nil {
1531		c.Fatal(err)
1532	}
1533
1534	// start the container again to pickup changes
1535	dockerCmd(c, "start", "first")
1536
1537	// our first exited container ID should have been updated, but with default DNS
1538	// after the cleanup of resolv.conf found only a localhost nameserver:
1539	containerResolv = readContainerFile(c, containerID1, "resolv.conf")
1540	expected := "\nnameserver 8.8.8.8\nnameserver 8.8.4.4\n"
1541	if !bytes.Equal(containerResolv, []byte(expected)) {
1542		c.Fatalf("Container does not have cleaned/replaced DNS in resolv.conf; expected %q, got %q", expected, string(containerResolv))
1543	}
1544
1545	//6. Test that replacing (as opposed to modifying) resolv.conf triggers an update
1546	//   of containers' resolv.conf.
1547
1548	// Restore the original resolv.conf
1549	if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil {
1550		c.Fatal(err)
1551	}
1552
1553	// Run the container so it picks up the old settings
1554	dockerCmd(c, "run", "--name=third", "busybox", "true")
1555	containerID3 := getIDByName(c, "third")
1556
1557	// Create a modified resolv.conf.aside and override resolv.conf with it
1558	bytesResolvConf = []byte(tmpResolvConf)
1559	if err := ioutil.WriteFile("/etc/resolv.conf.aside", bytesResolvConf, 0644); err != nil {
1560		c.Fatal(err)
1561	}
1562
1563	err = os.Rename("/etc/resolv.conf.aside", "/etc/resolv.conf")
1564	if err != nil {
1565		c.Fatal(err)
1566	}
1567
1568	// start the container again to pickup changes
1569	dockerCmd(c, "start", "third")
1570
1571	// check for update in container
1572	containerResolv = readContainerFile(c, containerID3, "resolv.conf")
1573	if !bytes.Equal(containerResolv, bytesResolvConf) {
1574		c.Fatalf("Stopped container does not have updated resolv.conf; expected\n%q\n got\n%q", tmpResolvConf, string(containerResolv))
1575	}
1576
1577	//cleanup, restore original resolv.conf happens in defer func()
1578}
1579
1580func (s *DockerSuite) TestRunAddHost(c *check.C) {
1581	// Not applicable on Windows as it does not support --add-host
1582	testRequires(c, DaemonIsLinux)
1583	out, _ := dockerCmd(c, "run", "--add-host=extra:86.75.30.9", "busybox", "grep", "extra", "/etc/hosts")
1584
1585	actual := strings.Trim(out, "\r\n")
1586	if actual != "86.75.30.9\textra" {
1587		c.Fatalf("expected '86.75.30.9\textra', but says: %q", actual)
1588	}
1589}
1590
1591// Regression test for #6983
1592func (s *DockerSuite) TestRunAttachStdErrOnlyTTYMode(c *check.C) {
1593	_, exitCode := dockerCmd(c, "run", "-t", "-a", "stderr", "busybox", "true")
1594	if exitCode != 0 {
1595		c.Fatalf("Container should have exited with error code 0")
1596	}
1597}
1598
1599// Regression test for #6983
1600func (s *DockerSuite) TestRunAttachStdOutOnlyTTYMode(c *check.C) {
1601	_, exitCode := dockerCmd(c, "run", "-t", "-a", "stdout", "busybox", "true")
1602	if exitCode != 0 {
1603		c.Fatalf("Container should have exited with error code 0")
1604	}
1605}
1606
1607// Regression test for #6983
1608func (s *DockerSuite) TestRunAttachStdOutAndErrTTYMode(c *check.C) {
1609	_, exitCode := dockerCmd(c, "run", "-t", "-a", "stdout", "-a", "stderr", "busybox", "true")
1610	if exitCode != 0 {
1611		c.Fatalf("Container should have exited with error code 0")
1612	}
1613}
1614
1615// Test for #10388 - this will run the same test as TestRunAttachStdOutAndErrTTYMode
1616// but using --attach instead of -a to make sure we read the flag correctly
1617func (s *DockerSuite) TestRunAttachWithDetach(c *check.C) {
1618	icmd.RunCommand(dockerBinary, "run", "-d", "--attach", "stdout", "busybox", "true").Assert(c, icmd.Expected{
1619		ExitCode: 1,
1620		Error:    "exit status 1",
1621		Err:      "Conflicting options: -a and -d",
1622	})
1623}
1624
1625func (s *DockerSuite) TestRunState(c *check.C) {
1626	// TODO Windows: This needs some rework as Windows busybox does not support top
1627	testRequires(c, DaemonIsLinux)
1628	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
1629
1630	id := strings.TrimSpace(out)
1631	state := inspectField(c, id, "State.Running")
1632	if state != "true" {
1633		c.Fatal("Container state is 'not running'")
1634	}
1635	pid1 := inspectField(c, id, "State.Pid")
1636	if pid1 == "0" {
1637		c.Fatal("Container state Pid 0")
1638	}
1639
1640	dockerCmd(c, "stop", id)
1641	state = inspectField(c, id, "State.Running")
1642	if state != "false" {
1643		c.Fatal("Container state is 'running'")
1644	}
1645	pid2 := inspectField(c, id, "State.Pid")
1646	if pid2 == pid1 {
1647		c.Fatalf("Container state Pid %s, but expected %s", pid2, pid1)
1648	}
1649
1650	dockerCmd(c, "start", id)
1651	state = inspectField(c, id, "State.Running")
1652	if state != "true" {
1653		c.Fatal("Container state is 'not running'")
1654	}
1655	pid3 := inspectField(c, id, "State.Pid")
1656	if pid3 == pid1 {
1657		c.Fatalf("Container state Pid %s, but expected %s", pid2, pid1)
1658	}
1659}
1660
1661// Test for #1737
1662func (s *DockerSuite) TestRunCopyVolumeUIDGID(c *check.C) {
1663	// Not applicable on Windows as it does not support uid or gid in this way
1664	testRequires(c, DaemonIsLinux)
1665	name := "testrunvolumesuidgid"
1666	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
1667		RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
1668		RUN echo 'dockerio:x:1001:' >> /etc/group
1669		RUN mkdir -p /hello && touch /hello/test && chown dockerio.dockerio /hello`))
1670
1671	// Test that the uid and gid is copied from the image to the volume
1672	out, _ := dockerCmd(c, "run", "--rm", "-v", "/hello", name, "sh", "-c", "ls -l / | grep hello | awk '{print $3\":\"$4}'")
1673	out = strings.TrimSpace(out)
1674	if out != "dockerio:dockerio" {
1675		c.Fatalf("Wrong /hello ownership: %s, expected dockerio:dockerio", out)
1676	}
1677}
1678
1679// Test for #1582
1680func (s *DockerSuite) TestRunCopyVolumeContent(c *check.C) {
1681	// TODO Windows, post RS1. Windows does not yet support volume functionality
1682	// that copies from the image to the volume.
1683	testRequires(c, DaemonIsLinux)
1684	name := "testruncopyvolumecontent"
1685	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
1686		RUN mkdir -p /hello/local && echo hello > /hello/local/world`))
1687
1688	// Test that the content is copied from the image to the volume
1689	out, _ := dockerCmd(c, "run", "--rm", "-v", "/hello", name, "find", "/hello")
1690	if !(strings.Contains(out, "/hello/local/world") && strings.Contains(out, "/hello/local")) {
1691		c.Fatal("Container failed to transfer content to volume")
1692	}
1693}
1694
1695func (s *DockerSuite) TestRunCleanupCmdOnEntrypoint(c *check.C) {
1696	name := "testrunmdcleanuponentrypoint"
1697	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
1698		ENTRYPOINT ["echo"]
1699		CMD ["testingpoint"]`))
1700
1701	out, exit := dockerCmd(c, "run", "--entrypoint", "whoami", name)
1702	if exit != 0 {
1703		c.Fatalf("expected exit code 0 received %d, out: %q", exit, out)
1704	}
1705	out = strings.TrimSpace(out)
1706	expected := "root"
1707	if testEnv.OSType == "windows" {
1708		if strings.Contains(testEnv.PlatformDefaults.BaseImage, "windowsservercore") {
1709			expected = `user manager\containeradministrator`
1710		} else {
1711			expected = `ContainerAdministrator` // nanoserver
1712		}
1713	}
1714	if out != expected {
1715		c.Fatalf("Expected output %s, got %q. %s", expected, out, testEnv.PlatformDefaults.BaseImage)
1716	}
1717}
1718
1719// TestRunWorkdirExistsAndIsFile checks that if 'docker run -w' with existing file can be detected
1720func (s *DockerSuite) TestRunWorkdirExistsAndIsFile(c *check.C) {
1721	existingFile := "/bin/cat"
1722	expected := "not a directory"
1723	if testEnv.OSType == "windows" {
1724		existingFile = `\windows\system32\ntdll.dll`
1725		expected = `The directory name is invalid.`
1726	}
1727
1728	out, exitCode, err := dockerCmdWithError("run", "-w", existingFile, "busybox")
1729	if !(err != nil && exitCode == 125 && strings.Contains(out, expected)) {
1730		c.Fatalf("Existing binary as a directory should error out with exitCode 125; we got: %s, exitCode: %d", out, exitCode)
1731	}
1732}
1733
1734func (s *DockerSuite) TestRunExitOnStdinClose(c *check.C) {
1735	name := "testrunexitonstdinclose"
1736
1737	meow := "/bin/cat"
1738	delay := 60
1739	if testEnv.OSType == "windows" {
1740		meow = "cat"
1741	}
1742	runCmd := exec.Command(dockerBinary, "run", "--name", name, "-i", "busybox", meow)
1743
1744	stdin, err := runCmd.StdinPipe()
1745	if err != nil {
1746		c.Fatal(err)
1747	}
1748	stdout, err := runCmd.StdoutPipe()
1749	if err != nil {
1750		c.Fatal(err)
1751	}
1752
1753	if err := runCmd.Start(); err != nil {
1754		c.Fatal(err)
1755	}
1756	if _, err := stdin.Write([]byte("hello\n")); err != nil {
1757		c.Fatal(err)
1758	}
1759
1760	r := bufio.NewReader(stdout)
1761	line, err := r.ReadString('\n')
1762	if err != nil {
1763		c.Fatal(err)
1764	}
1765	line = strings.TrimSpace(line)
1766	if line != "hello" {
1767		c.Fatalf("Output should be 'hello', got '%q'", line)
1768	}
1769	if err := stdin.Close(); err != nil {
1770		c.Fatal(err)
1771	}
1772	finish := make(chan error)
1773	go func() {
1774		finish <- runCmd.Wait()
1775		close(finish)
1776	}()
1777	select {
1778	case err := <-finish:
1779		c.Assert(err, check.IsNil)
1780	case <-time.After(time.Duration(delay) * time.Second):
1781		c.Fatal("docker run failed to exit on stdin close")
1782	}
1783	state := inspectField(c, name, "State.Running")
1784
1785	if state != "false" {
1786		c.Fatal("Container must be stopped after stdin closing")
1787	}
1788}
1789
1790// Test run -i --restart xxx doesn't hang
1791func (s *DockerSuite) TestRunInteractiveWithRestartPolicy(c *check.C) {
1792	name := "test-inter-restart"
1793
1794	result := icmd.StartCmd(icmd.Cmd{
1795		Command: []string{dockerBinary, "run", "-i", "--name", name, "--restart=always", "busybox", "sh"},
1796		Stdin:   bytes.NewBufferString("exit 11"),
1797	})
1798	c.Assert(result.Error, checker.IsNil)
1799	defer func() {
1800		dockerCmdWithResult("stop", name).Assert(c, icmd.Success)
1801	}()
1802
1803	result = icmd.WaitOnCmd(60*time.Second, result)
1804	result.Assert(c, icmd.Expected{ExitCode: 11})
1805}
1806
1807// Test for #2267
1808func (s *DockerSuite) TestRunWriteSpecialFilesAndNotCommit(c *check.C) {
1809	// Cannot run on Windows as this files are not present in Windows
1810	testRequires(c, DaemonIsLinux)
1811
1812	testRunWriteSpecialFilesAndNotCommit(c, "writehosts", "/etc/hosts")
1813	testRunWriteSpecialFilesAndNotCommit(c, "writehostname", "/etc/hostname")
1814	testRunWriteSpecialFilesAndNotCommit(c, "writeresolv", "/etc/resolv.conf")
1815}
1816
1817func testRunWriteSpecialFilesAndNotCommit(c *check.C, name, path string) {
1818	command := fmt.Sprintf("echo test2267 >> %s && cat %s", path, path)
1819	out, _ := dockerCmd(c, "run", "--name", name, "busybox", "sh", "-c", command)
1820	if !strings.Contains(out, "test2267") {
1821		c.Fatalf("%s should contain 'test2267'", path)
1822	}
1823
1824	out, _ = dockerCmd(c, "diff", name)
1825	if len(strings.Trim(out, "\r\n")) != 0 && !eqToBaseDiff(out, c) {
1826		c.Fatal("diff should be empty")
1827	}
1828}
1829
1830func eqToBaseDiff(out string, c *check.C) bool {
1831	name := "eqToBaseDiff" + testutil.GenerateRandomAlphaOnlyString(32)
1832	dockerCmd(c, "run", "--name", name, "busybox", "echo", "hello")
1833	cID := getIDByName(c, name)
1834	baseDiff, _ := dockerCmd(c, "diff", cID)
1835	baseArr := strings.Split(baseDiff, "\n")
1836	sort.Strings(baseArr)
1837	outArr := strings.Split(out, "\n")
1838	sort.Strings(outArr)
1839	return sliceEq(baseArr, outArr)
1840}
1841
1842func sliceEq(a, b []string) bool {
1843	if len(a) != len(b) {
1844		return false
1845	}
1846
1847	for i := range a {
1848		if a[i] != b[i] {
1849			return false
1850		}
1851	}
1852
1853	return true
1854}
1855
1856func (s *DockerSuite) TestRunWithBadDevice(c *check.C) {
1857	// Cannot run on Windows as Windows does not support --device
1858	testRequires(c, DaemonIsLinux)
1859	name := "baddevice"
1860	out, _, err := dockerCmdWithError("run", "--name", name, "--device", "/etc", "busybox", "true")
1861
1862	if err == nil {
1863		c.Fatal("Run should fail with bad device")
1864	}
1865	expected := `"/etc": not a device node`
1866	if !strings.Contains(out, expected) {
1867		c.Fatalf("Output should contain %q, actual out: %q", expected, out)
1868	}
1869}
1870
1871func (s *DockerSuite) TestRunEntrypoint(c *check.C) {
1872	name := "entrypoint"
1873
1874	out, _ := dockerCmd(c, "run", "--name", name, "--entrypoint", "echo", "busybox", "-n", "foobar")
1875	expected := "foobar"
1876
1877	if out != expected {
1878		c.Fatalf("Output should be %q, actual out: %q", expected, out)
1879	}
1880}
1881
1882func (s *DockerSuite) TestRunBindMounts(c *check.C) {
1883	testRequires(c, SameHostDaemon)
1884	if testEnv.OSType == "linux" {
1885		testRequires(c, DaemonIsLinux, NotUserNamespace)
1886	}
1887
1888	prefix, _ := getPrefixAndSlashFromDaemonPlatform()
1889
1890	tmpDir, err := ioutil.TempDir("", "docker-test-container")
1891	if err != nil {
1892		c.Fatal(err)
1893	}
1894
1895	defer os.RemoveAll(tmpDir)
1896	writeFile(path.Join(tmpDir, "touch-me"), "", c)
1897
1898	// Test reading from a read-only bind mount
1899	out, _ := dockerCmd(c, "run", "-v", fmt.Sprintf("%s:%s/tmp:ro", tmpDir, prefix), "busybox", "ls", prefix+"/tmp")
1900	if !strings.Contains(out, "touch-me") {
1901		c.Fatal("Container failed to read from bind mount")
1902	}
1903
1904	// test writing to bind mount
1905	if testEnv.OSType == "windows" {
1906		dockerCmd(c, "run", "-v", fmt.Sprintf(`%s:c:\tmp:rw`, tmpDir), "busybox", "touch", "c:/tmp/holla")
1907	} else {
1908		dockerCmd(c, "run", "-v", fmt.Sprintf("%s:/tmp:rw", tmpDir), "busybox", "touch", "/tmp/holla")
1909	}
1910
1911	readFile(path.Join(tmpDir, "holla"), c) // Will fail if the file doesn't exist
1912
1913	// test mounting to an illegal destination directory
1914	_, _, err = dockerCmdWithError("run", "-v", fmt.Sprintf("%s:.", tmpDir), "busybox", "ls", ".")
1915	if err == nil {
1916		c.Fatal("Container bind mounted illegal directory")
1917	}
1918
1919	// Windows does not (and likely never will) support mounting a single file
1920	if testEnv.OSType != "windows" {
1921		// test mount a file
1922		dockerCmd(c, "run", "-v", fmt.Sprintf("%s/holla:/tmp/holla:rw", tmpDir), "busybox", "sh", "-c", "echo -n 'yotta' > /tmp/holla")
1923		content := readFile(path.Join(tmpDir, "holla"), c) // Will fail if the file doesn't exist
1924		expected := "yotta"
1925		if content != expected {
1926			c.Fatalf("Output should be %q, actual out: %q", expected, content)
1927		}
1928	}
1929}
1930
1931// Ensure that CIDFile gets deleted if it's empty
1932// Perform this test by making `docker run` fail
1933func (s *DockerSuite) TestRunCidFileCleanupIfEmpty(c *check.C) {
1934	// Skip on Windows. Base image on Windows has a CMD set in the image.
1935	testRequires(c, DaemonIsLinux)
1936
1937	tmpDir, err := ioutil.TempDir("", "TestRunCidFile")
1938	if err != nil {
1939		c.Fatal(err)
1940	}
1941	defer os.RemoveAll(tmpDir)
1942	tmpCidFile := path.Join(tmpDir, "cid")
1943
1944	image := "emptyfs"
1945	if testEnv.OSType == "windows" {
1946		// Windows can't support an emptyfs image. Just use the regular Windows image
1947		image = testEnv.PlatformDefaults.BaseImage
1948	}
1949	out, _, err := dockerCmdWithError("run", "--cidfile", tmpCidFile, image)
1950	if err == nil {
1951		c.Fatalf("Run without command must fail. out=%s", out)
1952	} else if !strings.Contains(out, "No command specified") {
1953		c.Fatalf("Run without command failed with wrong output. out=%s\nerr=%v", out, err)
1954	}
1955
1956	if _, err := os.Stat(tmpCidFile); err == nil {
1957		c.Fatalf("empty CIDFile %q should've been deleted", tmpCidFile)
1958	}
1959}
1960
1961// #2098 - Docker cidFiles only contain short version of the containerId
1962//sudo docker run --cidfile /tmp/docker_tesc.cid ubuntu echo "test"
1963// TestRunCidFile tests that run --cidfile returns the longid
1964func (s *DockerSuite) TestRunCidFileCheckIDLength(c *check.C) {
1965	tmpDir, err := ioutil.TempDir("", "TestRunCidFile")
1966	if err != nil {
1967		c.Fatal(err)
1968	}
1969	tmpCidFile := path.Join(tmpDir, "cid")
1970	defer os.RemoveAll(tmpDir)
1971
1972	out, _ := dockerCmd(c, "run", "-d", "--cidfile", tmpCidFile, "busybox", "true")
1973
1974	id := strings.TrimSpace(out)
1975	buffer, err := ioutil.ReadFile(tmpCidFile)
1976	if err != nil {
1977		c.Fatal(err)
1978	}
1979	cid := string(buffer)
1980	if len(cid) != 64 {
1981		c.Fatalf("--cidfile should be a long id, not %q", id)
1982	}
1983	if cid != id {
1984		c.Fatalf("cid must be equal to %s, got %s", id, cid)
1985	}
1986}
1987
1988func (s *DockerSuite) TestRunSetMacAddress(c *check.C) {
1989	mac := "12:34:56:78:9a:bc"
1990	var out string
1991	if testEnv.OSType == "windows" {
1992		out, _ = dockerCmd(c, "run", "-i", "--rm", fmt.Sprintf("--mac-address=%s", mac), "busybox", "sh", "-c", "ipconfig /all | grep 'Physical Address' | awk '{print $12}'")
1993		mac = strings.Replace(strings.ToUpper(mac), ":", "-", -1) // To Windows-style MACs
1994	} else {
1995		out, _ = dockerCmd(c, "run", "-i", "--rm", fmt.Sprintf("--mac-address=%s", mac), "busybox", "/bin/sh", "-c", "ip link show eth0 | tail -1 | awk '{print $2}'")
1996	}
1997
1998	actualMac := strings.TrimSpace(out)
1999	if actualMac != mac {
2000		c.Fatalf("Set MAC address with --mac-address failed. The container has an incorrect MAC address: %q, expected: %q", actualMac, mac)
2001	}
2002}
2003
2004func (s *DockerSuite) TestRunInspectMacAddress(c *check.C) {
2005	// TODO Windows. Network settings are not propagated back to inspect.
2006	testRequires(c, DaemonIsLinux)
2007	mac := "12:34:56:78:9a:bc"
2008	out, _ := dockerCmd(c, "run", "-d", "--mac-address="+mac, "busybox", "top")
2009
2010	id := strings.TrimSpace(out)
2011	inspectedMac := inspectField(c, id, "NetworkSettings.Networks.bridge.MacAddress")
2012	if inspectedMac != mac {
2013		c.Fatalf("docker inspect outputs wrong MAC address: %q, should be: %q", inspectedMac, mac)
2014	}
2015}
2016
2017// test docker run use an invalid mac address
2018func (s *DockerSuite) TestRunWithInvalidMacAddress(c *check.C) {
2019	out, _, err := dockerCmdWithError("run", "--mac-address", "92:d0:c6:0a:29", "busybox")
2020	//use an invalid mac address should with an error out
2021	if err == nil || !strings.Contains(out, "is not a valid mac address") {
2022		c.Fatalf("run with an invalid --mac-address should with error out")
2023	}
2024}
2025
2026func (s *DockerSuite) TestRunDeallocatePortOnMissingIptablesRule(c *check.C) {
2027	// TODO Windows. Network settings are not propagated back to inspect.
2028	testRequires(c, SameHostDaemon, DaemonIsLinux)
2029
2030	out := cli.DockerCmd(c, "run", "-d", "-p", "23:23", "busybox", "top").Combined()
2031
2032	id := strings.TrimSpace(out)
2033	ip := inspectField(c, id, "NetworkSettings.Networks.bridge.IPAddress")
2034	icmd.RunCommand("iptables", "-D", "DOCKER", "-d", fmt.Sprintf("%s/32", ip),
2035		"!", "-i", "docker0", "-o", "docker0", "-p", "tcp", "-m", "tcp", "--dport", "23", "-j", "ACCEPT").Assert(c, icmd.Success)
2036
2037	cli.DockerCmd(c, "rm", "-fv", id)
2038
2039	cli.DockerCmd(c, "run", "-d", "-p", "23:23", "busybox", "top")
2040}
2041
2042func (s *DockerSuite) TestRunPortInUse(c *check.C) {
2043	// TODO Windows. The duplicate NAT message returned by Windows will be
2044	// changing as is currently completely undecipherable. Does need modifying
2045	// to run sh rather than top though as top isn't in Windows busybox.
2046	testRequires(c, SameHostDaemon, DaemonIsLinux)
2047
2048	port := "1234"
2049	dockerCmd(c, "run", "-d", "-p", port+":80", "busybox", "top")
2050
2051	out, _, err := dockerCmdWithError("run", "-d", "-p", port+":80", "busybox", "top")
2052	if err == nil {
2053		c.Fatalf("Binding on used port must fail")
2054	}
2055	if !strings.Contains(out, "port is already allocated") {
2056		c.Fatalf("Out must be about \"port is already allocated\", got %s", out)
2057	}
2058}
2059
2060// https://github.com/docker/docker/issues/12148
2061func (s *DockerSuite) TestRunAllocatePortInReservedRange(c *check.C) {
2062	// TODO Windows. -P is not yet supported
2063	testRequires(c, DaemonIsLinux)
2064	// allocate a dynamic port to get the most recent
2065	out, _ := dockerCmd(c, "run", "-d", "-P", "-p", "80", "busybox", "top")
2066
2067	id := strings.TrimSpace(out)
2068	out, _ = dockerCmd(c, "port", id, "80")
2069
2070	strPort := strings.Split(strings.TrimSpace(out), ":")[1]
2071	port, err := strconv.ParseInt(strPort, 10, 64)
2072	if err != nil {
2073		c.Fatalf("invalid port, got: %s, error: %s", strPort, err)
2074	}
2075
2076	// allocate a static port and a dynamic port together, with static port
2077	// takes the next recent port in dynamic port range.
2078	dockerCmd(c, "run", "-d", "-P", "-p", "80", "-p", fmt.Sprintf("%d:8080", port+1), "busybox", "top")
2079}
2080
2081// Regression test for #7792
2082func (s *DockerSuite) TestRunMountOrdering(c *check.C) {
2083	// TODO Windows: Post RS1. Windows does not support nested mounts.
2084	testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace)
2085	prefix, _ := getPrefixAndSlashFromDaemonPlatform()
2086
2087	tmpDir, err := ioutil.TempDir("", "docker_nested_mount_test")
2088	if err != nil {
2089		c.Fatal(err)
2090	}
2091	defer os.RemoveAll(tmpDir)
2092
2093	tmpDir2, err := ioutil.TempDir("", "docker_nested_mount_test2")
2094	if err != nil {
2095		c.Fatal(err)
2096	}
2097	defer os.RemoveAll(tmpDir2)
2098
2099	// Create a temporary tmpfs mounc.
2100	fooDir := filepath.Join(tmpDir, "foo")
2101	if err := os.MkdirAll(filepath.Join(tmpDir, "foo"), 0755); err != nil {
2102		c.Fatalf("failed to mkdir at %s - %s", fooDir, err)
2103	}
2104
2105	if err := ioutil.WriteFile(fmt.Sprintf("%s/touch-me", fooDir), []byte{}, 0644); err != nil {
2106		c.Fatal(err)
2107	}
2108
2109	if err := ioutil.WriteFile(fmt.Sprintf("%s/touch-me", tmpDir), []byte{}, 0644); err != nil {
2110		c.Fatal(err)
2111	}
2112
2113	if err := ioutil.WriteFile(fmt.Sprintf("%s/touch-me", tmpDir2), []byte{}, 0644); err != nil {
2114		c.Fatal(err)
2115	}
2116
2117	dockerCmd(c, "run",
2118		"-v", fmt.Sprintf("%s:"+prefix+"/tmp", tmpDir),
2119		"-v", fmt.Sprintf("%s:"+prefix+"/tmp/foo", fooDir),
2120		"-v", fmt.Sprintf("%s:"+prefix+"/tmp/tmp2", tmpDir2),
2121		"-v", fmt.Sprintf("%s:"+prefix+"/tmp/tmp2/foo", fooDir),
2122		"busybox:latest", "sh", "-c",
2123		"ls "+prefix+"/tmp/touch-me && ls "+prefix+"/tmp/foo/touch-me && ls "+prefix+"/tmp/tmp2/touch-me && ls "+prefix+"/tmp/tmp2/foo/touch-me")
2124}
2125
2126// Regression test for https://github.com/docker/docker/issues/8259
2127func (s *DockerSuite) TestRunReuseBindVolumeThatIsSymlink(c *check.C) {
2128	// Not applicable on Windows as Windows does not support volumes
2129	testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace)
2130	prefix, _ := getPrefixAndSlashFromDaemonPlatform()
2131
2132	tmpDir, err := ioutil.TempDir(os.TempDir(), "testlink")
2133	if err != nil {
2134		c.Fatal(err)
2135	}
2136	defer os.RemoveAll(tmpDir)
2137
2138	linkPath := os.TempDir() + "/testlink2"
2139	if err := os.Symlink(tmpDir, linkPath); err != nil {
2140		c.Fatal(err)
2141	}
2142	defer os.RemoveAll(linkPath)
2143
2144	// Create first container
2145	dockerCmd(c, "run", "-v", fmt.Sprintf("%s:"+prefix+"/tmp/test", linkPath), "busybox", "ls", prefix+"/tmp/test")
2146
2147	// Create second container with same symlinked path
2148	// This will fail if the referenced issue is hit with a "Volume exists" error
2149	dockerCmd(c, "run", "-v", fmt.Sprintf("%s:"+prefix+"/tmp/test", linkPath), "busybox", "ls", prefix+"/tmp/test")
2150}
2151
2152//GH#10604: Test an "/etc" volume doesn't overlay special bind mounts in container
2153func (s *DockerSuite) TestRunCreateVolumeEtc(c *check.C) {
2154	// While Windows supports volumes, it does not support --add-host hence
2155	// this test is not applicable on Windows.
2156	testRequires(c, DaemonIsLinux)
2157	out, _ := dockerCmd(c, "run", "--dns=127.0.0.1", "-v", "/etc", "busybox", "cat", "/etc/resolv.conf")
2158	if !strings.Contains(out, "nameserver 127.0.0.1") {
2159		c.Fatal("/etc volume mount hides /etc/resolv.conf")
2160	}
2161
2162	out, _ = dockerCmd(c, "run", "-h=test123", "-v", "/etc", "busybox", "cat", "/etc/hostname")
2163	if !strings.Contains(out, "test123") {
2164		c.Fatal("/etc volume mount hides /etc/hostname")
2165	}
2166
2167	out, _ = dockerCmd(c, "run", "--add-host=test:192.168.0.1", "-v", "/etc", "busybox", "cat", "/etc/hosts")
2168	out = strings.Replace(out, "\n", " ", -1)
2169	if !strings.Contains(out, "192.168.0.1\ttest") || !strings.Contains(out, "127.0.0.1\tlocalhost") {
2170		c.Fatal("/etc volume mount hides /etc/hosts")
2171	}
2172}
2173
2174func (s *DockerSuite) TestVolumesNoCopyData(c *check.C) {
2175	// TODO Windows (Post RS1). Windows does not support volumes which
2176	// are pre-populated such as is built in the dockerfile used in this test.
2177	testRequires(c, DaemonIsLinux)
2178	prefix, slash := getPrefixAndSlashFromDaemonPlatform()
2179	buildImageSuccessfully(c, "dataimage", build.WithDockerfile(`FROM busybox
2180		RUN ["mkdir", "-p", "/foo"]
2181		RUN ["touch", "/foo/bar"]`))
2182	dockerCmd(c, "run", "--name", "test", "-v", prefix+slash+"foo", "busybox")
2183
2184	if out, _, err := dockerCmdWithError("run", "--volumes-from", "test", "dataimage", "ls", "-lh", "/foo/bar"); err == nil || !strings.Contains(out, "No such file or directory") {
2185		c.Fatalf("Data was copied on volumes-from but shouldn't be:\n%q", out)
2186	}
2187
2188	tmpDir := RandomTmpDirPath("docker_test_bind_mount_copy_data", testEnv.OSType)
2189	if out, _, err := dockerCmdWithError("run", "-v", tmpDir+":/foo", "dataimage", "ls", "-lh", "/foo/bar"); err == nil || !strings.Contains(out, "No such file or directory") {
2190		c.Fatalf("Data was copied on bind mount but shouldn't be:\n%q", out)
2191	}
2192}
2193
2194func (s *DockerSuite) TestRunNoOutputFromPullInStdout(c *check.C) {
2195	// just run with unknown image
2196	cmd := exec.Command(dockerBinary, "run", "asdfsg")
2197	stdout := bytes.NewBuffer(nil)
2198	cmd.Stdout = stdout
2199	if err := cmd.Run(); err == nil {
2200		c.Fatal("Run with unknown image should fail")
2201	}
2202	if stdout.Len() != 0 {
2203		c.Fatalf("Stdout contains output from pull: %s", stdout)
2204	}
2205}
2206
2207func (s *DockerSuite) TestRunVolumesCleanPaths(c *check.C) {
2208	testRequires(c, SameHostDaemon)
2209	prefix, slash := getPrefixAndSlashFromDaemonPlatform()
2210	buildImageSuccessfully(c, "run_volumes_clean_paths", build.WithDockerfile(`FROM busybox
2211		VOLUME `+prefix+`/foo/`))
2212	dockerCmd(c, "run", "-v", prefix+"/foo", "-v", prefix+"/bar/", "--name", "dark_helmet", "run_volumes_clean_paths")
2213
2214	out, err := inspectMountSourceField("dark_helmet", prefix+slash+"foo"+slash)
2215	if err != errMountNotFound {
2216		c.Fatalf("Found unexpected volume entry for '%s/foo/' in volumes\n%q", prefix, out)
2217	}
2218
2219	out, err = inspectMountSourceField("dark_helmet", prefix+slash+`foo`)
2220	c.Assert(err, check.IsNil)
2221	if !strings.Contains(strings.ToLower(out), strings.ToLower(testEnv.PlatformDefaults.VolumesConfigPath)) {
2222		c.Fatalf("Volume was not defined for %s/foo\n%q", prefix, out)
2223	}
2224
2225	out, err = inspectMountSourceField("dark_helmet", prefix+slash+"bar"+slash)
2226	if err != errMountNotFound {
2227		c.Fatalf("Found unexpected volume entry for '%s/bar/' in volumes\n%q", prefix, out)
2228	}
2229
2230	out, err = inspectMountSourceField("dark_helmet", prefix+slash+"bar")
2231	c.Assert(err, check.IsNil)
2232	if !strings.Contains(strings.ToLower(out), strings.ToLower(testEnv.PlatformDefaults.VolumesConfigPath)) {
2233		c.Fatalf("Volume was not defined for %s/bar\n%q", prefix, out)
2234	}
2235}
2236
2237// Regression test for #3631
2238func (s *DockerSuite) TestRunSlowStdoutConsumer(c *check.C) {
2239	// TODO Windows: This should be able to run on Windows if can find an
2240	// alternate to /dev/zero and /dev/stdout.
2241	testRequires(c, DaemonIsLinux)
2242
2243	args := []string{"run", "--rm", "busybox", "/bin/sh", "-c", "dd if=/dev/zero of=/dev/stdout bs=1024 count=2000 | cat -v"}
2244	cont := exec.Command(dockerBinary, args...)
2245
2246	stdout, err := cont.StdoutPipe()
2247	if err != nil {
2248		c.Fatal(err)
2249	}
2250
2251	if err := cont.Start(); err != nil {
2252		c.Fatal(err)
2253	}
2254	defer func() { go cont.Wait() }()
2255	n, err := ConsumeWithSpeed(stdout, 10000, 5*time.Millisecond, nil)
2256	if err != nil {
2257		c.Fatal(err)
2258	}
2259
2260	expected := 2 * 1024 * 2000
2261	if n != expected {
2262		c.Fatalf("Expected %d, got %d", expected, n)
2263	}
2264}
2265
2266func (s *DockerSuite) TestRunAllowPortRangeThroughExpose(c *check.C) {
2267	// TODO Windows: -P is not currently supported. Also network
2268	// settings are not propagated back.
2269	testRequires(c, DaemonIsLinux)
2270	out, _ := dockerCmd(c, "run", "-d", "--expose", "3000-3003", "-P", "busybox", "top")
2271
2272	id := strings.TrimSpace(out)
2273	portstr := inspectFieldJSON(c, id, "NetworkSettings.Ports")
2274	var ports nat.PortMap
2275	if err := json.Unmarshal([]byte(portstr), &ports); err != nil {
2276		c.Fatal(err)
2277	}
2278	for port, binding := range ports {
2279		portnum, _ := strconv.Atoi(strings.Split(string(port), "/")[0])
2280		if portnum < 3000 || portnum > 3003 {
2281			c.Fatalf("Port %d is out of range ", portnum)
2282		}
2283		if binding == nil || len(binding) != 1 || len(binding[0].HostPort) == 0 {
2284			c.Fatalf("Port is not mapped for the port %s", port)
2285		}
2286	}
2287}
2288
2289func (s *DockerSuite) TestRunExposePort(c *check.C) {
2290	out, _, err := dockerCmdWithError("run", "--expose", "80000", "busybox")
2291	c.Assert(err, checker.NotNil, check.Commentf("--expose with an invalid port should error out"))
2292	c.Assert(out, checker.Contains, "invalid range format for --expose")
2293}
2294
2295func (s *DockerSuite) TestRunModeIpcHost(c *check.C) {
2296	// Not applicable on Windows as uses Unix-specific capabilities
2297	testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace)
2298
2299	hostIpc, err := os.Readlink("/proc/1/ns/ipc")
2300	if err != nil {
2301		c.Fatal(err)
2302	}
2303
2304	out, _ := dockerCmd(c, "run", "--ipc=host", "busybox", "readlink", "/proc/self/ns/ipc")
2305	out = strings.Trim(out, "\n")
2306	if hostIpc != out {
2307		c.Fatalf("IPC different with --ipc=host %s != %s\n", hostIpc, out)
2308	}
2309
2310	out, _ = dockerCmd(c, "run", "busybox", "readlink", "/proc/self/ns/ipc")
2311	out = strings.Trim(out, "\n")
2312	if hostIpc == out {
2313		c.Fatalf("IPC should be different without --ipc=host %s == %s\n", hostIpc, out)
2314	}
2315}
2316
2317func (s *DockerSuite) TestRunModeIpcContainerNotExists(c *check.C) {
2318	// Not applicable on Windows as uses Unix-specific capabilities
2319	testRequires(c, DaemonIsLinux)
2320	out, _, err := dockerCmdWithError("run", "-d", "--ipc", "container:abcd1234", "busybox", "top")
2321	if !strings.Contains(out, "abcd1234") || err == nil {
2322		c.Fatalf("run IPC from a non exists container should with correct error out")
2323	}
2324}
2325
2326func (s *DockerSuite) TestRunModeIpcContainerNotRunning(c *check.C) {
2327	// Not applicable on Windows as uses Unix-specific capabilities
2328	testRequires(c, SameHostDaemon, DaemonIsLinux)
2329
2330	out, _ := dockerCmd(c, "create", "busybox")
2331
2332	id := strings.TrimSpace(out)
2333	out, _, err := dockerCmdWithError("run", fmt.Sprintf("--ipc=container:%s", id), "busybox")
2334	if err == nil {
2335		c.Fatalf("Run container with ipc mode container should fail with non running container: %s\n%s", out, err)
2336	}
2337}
2338
2339func (s *DockerSuite) TestRunModePIDContainer(c *check.C) {
2340	// Not applicable on Windows as uses Unix-specific capabilities
2341	testRequires(c, SameHostDaemon, DaemonIsLinux)
2342
2343	out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", "top")
2344
2345	id := strings.TrimSpace(out)
2346	state := inspectField(c, id, "State.Running")
2347	if state != "true" {
2348		c.Fatal("Container state is 'not running'")
2349	}
2350	pid1 := inspectField(c, id, "State.Pid")
2351
2352	parentContainerPid, err := os.Readlink(fmt.Sprintf("/proc/%s/ns/pid", pid1))
2353	if err != nil {
2354		c.Fatal(err)
2355	}
2356
2357	out, _ = dockerCmd(c, "run", fmt.Sprintf("--pid=container:%s", id), "busybox", "readlink", "/proc/self/ns/pid")
2358	out = strings.Trim(out, "\n")
2359	if parentContainerPid != out {
2360		c.Fatalf("PID different with --pid=container:%s %s != %s\n", id, parentContainerPid, out)
2361	}
2362}
2363
2364func (s *DockerSuite) TestRunModePIDContainerNotExists(c *check.C) {
2365	// Not applicable on Windows as uses Unix-specific capabilities
2366	testRequires(c, DaemonIsLinux)
2367	out, _, err := dockerCmdWithError("run", "-d", "--pid", "container:abcd1234", "busybox", "top")
2368	if !strings.Contains(out, "abcd1234") || err == nil {
2369		c.Fatalf("run PID from a non exists container should with correct error out")
2370	}
2371}
2372
2373func (s *DockerSuite) TestRunModePIDContainerNotRunning(c *check.C) {
2374	// Not applicable on Windows as uses Unix-specific capabilities
2375	testRequires(c, SameHostDaemon, DaemonIsLinux)
2376
2377	out, _ := dockerCmd(c, "create", "busybox")
2378
2379	id := strings.TrimSpace(out)
2380	out, _, err := dockerCmdWithError("run", fmt.Sprintf("--pid=container:%s", id), "busybox")
2381	if err == nil {
2382		c.Fatalf("Run container with pid mode container should fail with non running container: %s\n%s", out, err)
2383	}
2384}
2385
2386func (s *DockerSuite) TestRunMountShmMqueueFromHost(c *check.C) {
2387	// Not applicable on Windows as uses Unix-specific capabilities
2388	testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace)
2389
2390	dockerCmd(c, "run", "-d", "--name", "shmfromhost", "-v", "/dev/shm:/dev/shm", "-v", "/dev/mqueue:/dev/mqueue", "busybox", "sh", "-c", "echo -n test > /dev/shm/test && touch /dev/mqueue/toto && top")
2391	defer os.Remove("/dev/mqueue/toto")
2392	defer os.Remove("/dev/shm/test")
2393	volPath, err := inspectMountSourceField("shmfromhost", "/dev/shm")
2394	c.Assert(err, checker.IsNil)
2395	if volPath != "/dev/shm" {
2396		c.Fatalf("volumePath should have been /dev/shm, was %s", volPath)
2397	}
2398
2399	out, _ := dockerCmd(c, "run", "--name", "ipchost", "--ipc", "host", "busybox", "cat", "/dev/shm/test")
2400	if out != "test" {
2401		c.Fatalf("Output of /dev/shm/test expected test but found: %s", out)
2402	}
2403
2404	// Check that the mq was created
2405	if _, err := os.Stat("/dev/mqueue/toto"); err != nil {
2406		c.Fatalf("Failed to confirm '/dev/mqueue/toto' presence on host: %s", err.Error())
2407	}
2408}
2409
2410func (s *DockerSuite) TestContainerNetworkMode(c *check.C) {
2411	// Not applicable on Windows as uses Unix-specific capabilities
2412	testRequires(c, SameHostDaemon, DaemonIsLinux)
2413
2414	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
2415	id := strings.TrimSpace(out)
2416	c.Assert(waitRun(id), check.IsNil)
2417	pid1 := inspectField(c, id, "State.Pid")
2418
2419	parentContainerNet, err := os.Readlink(fmt.Sprintf("/proc/%s/ns/net", pid1))
2420	if err != nil {
2421		c.Fatal(err)
2422	}
2423
2424	out, _ = dockerCmd(c, "run", fmt.Sprintf("--net=container:%s", id), "busybox", "readlink", "/proc/self/ns/net")
2425	out = strings.Trim(out, "\n")
2426	if parentContainerNet != out {
2427		c.Fatalf("NET different with --net=container:%s %s != %s\n", id, parentContainerNet, out)
2428	}
2429}
2430
2431func (s *DockerSuite) TestRunModePIDHost(c *check.C) {
2432	// Not applicable on Windows as uses Unix-specific capabilities
2433	testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace)
2434
2435	hostPid, err := os.Readlink("/proc/1/ns/pid")
2436	if err != nil {
2437		c.Fatal(err)
2438	}
2439
2440	out, _ := dockerCmd(c, "run", "--pid=host", "busybox", "readlink", "/proc/self/ns/pid")
2441	out = strings.Trim(out, "\n")
2442	if hostPid != out {
2443		c.Fatalf("PID different with --pid=host %s != %s\n", hostPid, out)
2444	}
2445
2446	out, _ = dockerCmd(c, "run", "busybox", "readlink", "/proc/self/ns/pid")
2447	out = strings.Trim(out, "\n")
2448	if hostPid == out {
2449		c.Fatalf("PID should be different without --pid=host %s == %s\n", hostPid, out)
2450	}
2451}
2452
2453func (s *DockerSuite) TestRunModeUTSHost(c *check.C) {
2454	// Not applicable on Windows as uses Unix-specific capabilities
2455	testRequires(c, SameHostDaemon, DaemonIsLinux)
2456
2457	hostUTS, err := os.Readlink("/proc/1/ns/uts")
2458	if err != nil {
2459		c.Fatal(err)
2460	}
2461
2462	out, _ := dockerCmd(c, "run", "--uts=host", "busybox", "readlink", "/proc/self/ns/uts")
2463	out = strings.Trim(out, "\n")
2464	if hostUTS != out {
2465		c.Fatalf("UTS different with --uts=host %s != %s\n", hostUTS, out)
2466	}
2467
2468	out, _ = dockerCmd(c, "run", "busybox", "readlink", "/proc/self/ns/uts")
2469	out = strings.Trim(out, "\n")
2470	if hostUTS == out {
2471		c.Fatalf("UTS should be different without --uts=host %s == %s\n", hostUTS, out)
2472	}
2473
2474	out, _ = dockerCmdWithFail(c, "run", "-h=name", "--uts=host", "busybox", "ps")
2475	c.Assert(out, checker.Contains, runconfig.ErrConflictUTSHostname.Error())
2476}
2477
2478func (s *DockerSuite) TestRunTLSVerify(c *check.C) {
2479	// Remote daemons use TLS and this test is not applicable when TLS is required.
2480	testRequires(c, SameHostDaemon)
2481	if out, code, err := dockerCmdWithError("ps"); err != nil || code != 0 {
2482		c.Fatalf("Should have worked: %v:\n%v", err, out)
2483	}
2484
2485	// Regardless of whether we specify true or false we need to
2486	// test to make sure tls is turned on if --tlsverify is specified at all
2487	result := dockerCmdWithResult("--tlsverify=false", "ps")
2488	result.Assert(c, icmd.Expected{ExitCode: 1, Err: "error during connect"})
2489
2490	result = dockerCmdWithResult("--tlsverify=true", "ps")
2491	result.Assert(c, icmd.Expected{ExitCode: 1, Err: "cert"})
2492}
2493
2494func (s *DockerSuite) TestRunPortFromDockerRangeInUse(c *check.C) {
2495	// TODO Windows. Once moved to libnetwork/CNM, this may be able to be
2496	// re-instated.
2497	testRequires(c, DaemonIsLinux)
2498	// first find allocator current position
2499	out, _ := dockerCmd(c, "run", "-d", "-p", ":80", "busybox", "top")
2500
2501	id := strings.TrimSpace(out)
2502	out, _ = dockerCmd(c, "port", id)
2503
2504	out = strings.TrimSpace(out)
2505	if out == "" {
2506		c.Fatal("docker port command output is empty")
2507	}
2508	out = strings.Split(out, ":")[1]
2509	lastPort, err := strconv.Atoi(out)
2510	if err != nil {
2511		c.Fatal(err)
2512	}
2513	port := lastPort + 1
2514	l, err := net.Listen("tcp", ":"+strconv.Itoa(port))
2515	if err != nil {
2516		c.Fatal(err)
2517	}
2518	defer l.Close()
2519
2520	out, _ = dockerCmd(c, "run", "-d", "-p", ":80", "busybox", "top")
2521
2522	id = strings.TrimSpace(out)
2523	dockerCmd(c, "port", id)
2524}
2525
2526func (s *DockerSuite) TestRunTTYWithPipe(c *check.C) {
2527	errChan := make(chan error)
2528	go func() {
2529		defer close(errChan)
2530
2531		cmd := exec.Command(dockerBinary, "run", "-ti", "busybox", "true")
2532		if _, err := cmd.StdinPipe(); err != nil {
2533			errChan <- err
2534			return
2535		}
2536
2537		expected := "the input device is not a TTY"
2538		if runtime.GOOS == "windows" {
2539			expected += ".  If you are using mintty, try prefixing the command with 'winpty'"
2540		}
2541		if out, _, err := runCommandWithOutput(cmd); err == nil {
2542			errChan <- fmt.Errorf("run should have failed")
2543			return
2544		} else if !strings.Contains(out, expected) {
2545			errChan <- fmt.Errorf("run failed with error %q: expected %q", out, expected)
2546			return
2547		}
2548	}()
2549
2550	select {
2551	case err := <-errChan:
2552		c.Assert(err, check.IsNil)
2553	case <-time.After(30 * time.Second):
2554		c.Fatal("container is running but should have failed")
2555	}
2556}
2557
2558func (s *DockerSuite) TestRunNonLocalMacAddress(c *check.C) {
2559	addr := "00:16:3E:08:00:50"
2560	args := []string{"run", "--mac-address", addr}
2561	expected := addr
2562
2563	if testEnv.OSType != "windows" {
2564		args = append(args, "busybox", "ifconfig")
2565	} else {
2566		args = append(args, testEnv.PlatformDefaults.BaseImage, "ipconfig", "/all")
2567		expected = strings.Replace(strings.ToUpper(addr), ":", "-", -1)
2568	}
2569
2570	if out, _ := dockerCmd(c, args...); !strings.Contains(out, expected) {
2571		c.Fatalf("Output should have contained %q: %s", expected, out)
2572	}
2573}
2574
2575func (s *DockerSuite) TestRunNetHost(c *check.C) {
2576	// Not applicable on Windows as uses Unix-specific capabilities
2577	testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace)
2578
2579	hostNet, err := os.Readlink("/proc/1/ns/net")
2580	if err != nil {
2581		c.Fatal(err)
2582	}
2583
2584	out, _ := dockerCmd(c, "run", "--net=host", "busybox", "readlink", "/proc/self/ns/net")
2585	out = strings.Trim(out, "\n")
2586	if hostNet != out {
2587		c.Fatalf("Net namespace different with --net=host %s != %s\n", hostNet, out)
2588	}
2589
2590	out, _ = dockerCmd(c, "run", "busybox", "readlink", "/proc/self/ns/net")
2591	out = strings.Trim(out, "\n")
2592	if hostNet == out {
2593		c.Fatalf("Net namespace should be different without --net=host %s == %s\n", hostNet, out)
2594	}
2595}
2596
2597func (s *DockerSuite) TestRunNetHostTwiceSameName(c *check.C) {
2598	// TODO Windows. As Windows networking evolves and converges towards
2599	// CNM, this test may be possible to enable on Windows.
2600	testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace)
2601
2602	dockerCmd(c, "run", "--rm", "--name=thost", "--net=host", "busybox", "true")
2603	dockerCmd(c, "run", "--rm", "--name=thost", "--net=host", "busybox", "true")
2604}
2605
2606func (s *DockerSuite) TestRunNetContainerWhichHost(c *check.C) {
2607	// Not applicable on Windows as uses Unix-specific capabilities
2608	testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace)
2609
2610	hostNet, err := os.Readlink("/proc/1/ns/net")
2611	if err != nil {
2612		c.Fatal(err)
2613	}
2614
2615	dockerCmd(c, "run", "-d", "--net=host", "--name=test", "busybox", "top")
2616
2617	out, _ := dockerCmd(c, "run", "--net=container:test", "busybox", "readlink", "/proc/self/ns/net")
2618	out = strings.Trim(out, "\n")
2619	if hostNet != out {
2620		c.Fatalf("Container should have host network namespace")
2621	}
2622}
2623
2624func (s *DockerSuite) TestRunAllowPortRangeThroughPublish(c *check.C) {
2625	// TODO Windows. This may be possible to enable in the future. However,
2626	// Windows does not currently support --expose, or populate the network
2627	// settings seen through inspect.
2628	testRequires(c, DaemonIsLinux)
2629	out, _ := dockerCmd(c, "run", "-d", "--expose", "3000-3003", "-p", "3000-3003", "busybox", "top")
2630
2631	id := strings.TrimSpace(out)
2632	portstr := inspectFieldJSON(c, id, "NetworkSettings.Ports")
2633
2634	var ports nat.PortMap
2635	err := json.Unmarshal([]byte(portstr), &ports)
2636	c.Assert(err, checker.IsNil, check.Commentf("failed to unmarshal: %v", portstr))
2637	for port, binding := range ports {
2638		portnum, _ := strconv.Atoi(strings.Split(string(port), "/")[0])
2639		if portnum < 3000 || portnum > 3003 {
2640			c.Fatalf("Port %d is out of range ", portnum)
2641		}
2642		if binding == nil || len(binding) != 1 || len(binding[0].HostPort) == 0 {
2643			c.Fatal("Port is not mapped for the port "+port, out)
2644		}
2645	}
2646}
2647
2648func (s *DockerSuite) TestRunSetDefaultRestartPolicy(c *check.C) {
2649	runSleepingContainer(c, "--name=testrunsetdefaultrestartpolicy")
2650	out := inspectField(c, "testrunsetdefaultrestartpolicy", "HostConfig.RestartPolicy.Name")
2651	if out != "no" {
2652		c.Fatalf("Set default restart policy failed")
2653	}
2654}
2655
2656func (s *DockerSuite) TestRunRestartMaxRetries(c *check.C) {
2657	out, _ := dockerCmd(c, "run", "-d", "--restart=on-failure:3", "busybox", "false")
2658	timeout := 10 * time.Second
2659	if testEnv.OSType == "windows" {
2660		timeout = 120 * time.Second
2661	}
2662
2663	id := strings.TrimSpace(string(out))
2664	if err := waitInspect(id, "{{ .State.Restarting }} {{ .State.Running }}", "false false", timeout); err != nil {
2665		c.Fatal(err)
2666	}
2667
2668	count := inspectField(c, id, "RestartCount")
2669	if count != "3" {
2670		c.Fatalf("Container was restarted %s times, expected %d", count, 3)
2671	}
2672
2673	MaximumRetryCount := inspectField(c, id, "HostConfig.RestartPolicy.MaximumRetryCount")
2674	if MaximumRetryCount != "3" {
2675		c.Fatalf("Container Maximum Retry Count is %s, expected %s", MaximumRetryCount, "3")
2676	}
2677}
2678
2679func (s *DockerSuite) TestRunContainerWithWritableRootfs(c *check.C) {
2680	dockerCmd(c, "run", "--rm", "busybox", "touch", "/file")
2681}
2682
2683func (s *DockerSuite) TestRunContainerWithReadonlyRootfs(c *check.C) {
2684	// Not applicable on Windows which does not support --read-only
2685	testRequires(c, DaemonIsLinux, UserNamespaceROMount)
2686
2687	testPriv := true
2688	// don't test privileged mode subtest if user namespaces enabled
2689	if root := os.Getenv("DOCKER_REMAP_ROOT"); root != "" {
2690		testPriv = false
2691	}
2692	testReadOnlyFile(c, testPriv, "/file", "/etc/hosts", "/etc/resolv.conf", "/etc/hostname")
2693}
2694
2695func (s *DockerSuite) TestPermissionsPtsReadonlyRootfs(c *check.C) {
2696	// Not applicable on Windows due to use of Unix specific functionality, plus
2697	// the use of --read-only which is not supported.
2698	testRequires(c, DaemonIsLinux, UserNamespaceROMount)
2699
2700	// Ensure we have not broken writing /dev/pts
2701	out, status := dockerCmd(c, "run", "--read-only", "--rm", "busybox", "mount")
2702	if status != 0 {
2703		c.Fatal("Could not obtain mounts when checking /dev/pts mntpnt.")
2704	}
2705	expected := "type devpts (rw,"
2706	if !strings.Contains(string(out), expected) {
2707		c.Fatalf("expected output to contain %s but contains %s", expected, out)
2708	}
2709}
2710
2711func testReadOnlyFile(c *check.C, testPriv bool, filenames ...string) {
2712	touch := "touch " + strings.Join(filenames, " ")
2713	out, _, err := dockerCmdWithError("run", "--read-only", "--rm", "busybox", "sh", "-c", touch)
2714	c.Assert(err, checker.NotNil)
2715
2716	for _, f := range filenames {
2717		expected := "touch: " + f + ": Read-only file system"
2718		c.Assert(out, checker.Contains, expected)
2719	}
2720
2721	if !testPriv {
2722		return
2723	}
2724
2725	out, _, err = dockerCmdWithError("run", "--read-only", "--privileged", "--rm", "busybox", "sh", "-c", touch)
2726	c.Assert(err, checker.NotNil)
2727
2728	for _, f := range filenames {
2729		expected := "touch: " + f + ": Read-only file system"
2730		c.Assert(out, checker.Contains, expected)
2731	}
2732}
2733
2734func (s *DockerSuite) TestRunContainerWithReadonlyEtcHostsAndLinkedContainer(c *check.C) {
2735	// Not applicable on Windows which does not support --link
2736	testRequires(c, DaemonIsLinux, UserNamespaceROMount)
2737
2738	dockerCmd(c, "run", "-d", "--name", "test-etc-hosts-ro-linked", "busybox", "top")
2739
2740	out, _ := dockerCmd(c, "run", "--read-only", "--link", "test-etc-hosts-ro-linked:testlinked", "busybox", "cat", "/etc/hosts")
2741	if !strings.Contains(string(out), "testlinked") {
2742		c.Fatal("Expected /etc/hosts to be updated even if --read-only enabled")
2743	}
2744}
2745
2746func (s *DockerSuite) TestRunContainerWithReadonlyRootfsWithDNSFlag(c *check.C) {
2747	// Not applicable on Windows which does not support either --read-only or --dns.
2748	testRequires(c, DaemonIsLinux, UserNamespaceROMount)
2749
2750	out, _ := dockerCmd(c, "run", "--read-only", "--dns", "1.1.1.1", "busybox", "/bin/cat", "/etc/resolv.conf")
2751	if !strings.Contains(string(out), "1.1.1.1") {
2752		c.Fatal("Expected /etc/resolv.conf to be updated even if --read-only enabled and --dns flag used")
2753	}
2754}
2755
2756func (s *DockerSuite) TestRunContainerWithReadonlyRootfsWithAddHostFlag(c *check.C) {
2757	// Not applicable on Windows which does not support --read-only
2758	testRequires(c, DaemonIsLinux, UserNamespaceROMount)
2759
2760	out, _ := dockerCmd(c, "run", "--read-only", "--add-host", "testreadonly:127.0.0.1", "busybox", "/bin/cat", "/etc/hosts")
2761	if !strings.Contains(string(out), "testreadonly") {
2762		c.Fatal("Expected /etc/hosts to be updated even if --read-only enabled and --add-host flag used")
2763	}
2764}
2765
2766func (s *DockerSuite) TestRunVolumesFromRestartAfterRemoved(c *check.C) {
2767	prefix, _ := getPrefixAndSlashFromDaemonPlatform()
2768	runSleepingContainer(c, "--name=voltest", "-v", prefix+"/foo")
2769	runSleepingContainer(c, "--name=restarter", "--volumes-from", "voltest")
2770
2771	// Remove the main volume container and restart the consuming container
2772	dockerCmd(c, "rm", "-f", "voltest")
2773
2774	// This should not fail since the volumes-from were already applied
2775	dockerCmd(c, "restart", "restarter")
2776}
2777
2778// run container with --rm should remove container if exit code != 0
2779func (s *DockerSuite) TestRunContainerWithRmFlagExitCodeNotEqualToZero(c *check.C) {
2780	existingContainers := ExistingContainerIDs(c)
2781	name := "flowers"
2782	cli.Docker(cli.Args("run", "--name", name, "--rm", "busybox", "ls", "/notexists")).Assert(c, icmd.Expected{
2783		ExitCode: 1,
2784	})
2785
2786	out := cli.DockerCmd(c, "ps", "-q", "-a").Combined()
2787	out = RemoveOutputForExistingElements(out, existingContainers)
2788	if out != "" {
2789		c.Fatal("Expected not to have containers", out)
2790	}
2791}
2792
2793func (s *DockerSuite) TestRunContainerWithRmFlagCannotStartContainer(c *check.C) {
2794	existingContainers := ExistingContainerIDs(c)
2795	name := "sparkles"
2796	cli.Docker(cli.Args("run", "--name", name, "--rm", "busybox", "commandNotFound")).Assert(c, icmd.Expected{
2797		ExitCode: 127,
2798	})
2799	out := cli.DockerCmd(c, "ps", "-q", "-a").Combined()
2800	out = RemoveOutputForExistingElements(out, existingContainers)
2801	if out != "" {
2802		c.Fatal("Expected not to have containers", out)
2803	}
2804}
2805
2806func (s *DockerSuite) TestRunPIDHostWithChildIsKillable(c *check.C) {
2807	// Not applicable on Windows as uses Unix specific functionality
2808	testRequires(c, DaemonIsLinux, NotUserNamespace)
2809	name := "ibuildthecloud"
2810	dockerCmd(c, "run", "-d", "--pid=host", "--name", name, "busybox", "sh", "-c", "sleep 30; echo hi")
2811
2812	c.Assert(waitRun(name), check.IsNil)
2813
2814	errchan := make(chan error)
2815	go func() {
2816		if out, _, err := dockerCmdWithError("kill", name); err != nil {
2817			errchan <- fmt.Errorf("%v:\n%s", err, out)
2818		}
2819		close(errchan)
2820	}()
2821	select {
2822	case err := <-errchan:
2823		c.Assert(err, check.IsNil)
2824	case <-time.After(5 * time.Second):
2825		c.Fatal("Kill container timed out")
2826	}
2827}
2828
2829func (s *DockerSuite) TestRunWithTooSmallMemoryLimit(c *check.C) {
2830	// TODO Windows. This may be possible to enable once Windows supports
2831	// memory limits on containers
2832	testRequires(c, DaemonIsLinux)
2833	// this memory limit is 1 byte less than the min, which is 4MB
2834	// https://github.com/docker/docker/blob/v1.5.0/daemon/create.go#L22
2835	out, _, err := dockerCmdWithError("run", "-m", "4194303", "busybox")
2836	if err == nil || !strings.Contains(out, "Minimum memory limit allowed is 4MB") {
2837		c.Fatalf("expected run to fail when using too low a memory limit: %q", out)
2838	}
2839}
2840
2841func (s *DockerSuite) TestRunWriteToProcAsound(c *check.C) {
2842	// Not applicable on Windows as uses Unix specific functionality
2843	testRequires(c, DaemonIsLinux)
2844	_, code, err := dockerCmdWithError("run", "busybox", "sh", "-c", "echo 111 >> /proc/asound/version")
2845	if err == nil || code == 0 {
2846		c.Fatal("standard container should not be able to write to /proc/asound")
2847	}
2848}
2849
2850func (s *DockerSuite) TestRunReadProcTimer(c *check.C) {
2851	// Not applicable on Windows as uses Unix specific functionality
2852	testRequires(c, DaemonIsLinux)
2853	out, code, err := dockerCmdWithError("run", "busybox", "cat", "/proc/timer_stats")
2854	if code != 0 {
2855		return
2856	}
2857	if err != nil {
2858		c.Fatal(err)
2859	}
2860	if strings.Trim(out, "\n ") != "" {
2861		c.Fatalf("expected to receive no output from /proc/timer_stats but received %q", out)
2862	}
2863}
2864
2865func (s *DockerSuite) TestRunReadProcLatency(c *check.C) {
2866	// Not applicable on Windows as uses Unix specific functionality
2867	testRequires(c, DaemonIsLinux)
2868	// some kernels don't have this configured so skip the test if this file is not found
2869	// on the host running the tests.
2870	if _, err := os.Stat("/proc/latency_stats"); err != nil {
2871		c.Skip("kernel doesn't have latency_stats configured")
2872		return
2873	}
2874	out, code, err := dockerCmdWithError("run", "busybox", "cat", "/proc/latency_stats")
2875	if code != 0 {
2876		return
2877	}
2878	if err != nil {
2879		c.Fatal(err)
2880	}
2881	if strings.Trim(out, "\n ") != "" {
2882		c.Fatalf("expected to receive no output from /proc/latency_stats but received %q", out)
2883	}
2884}
2885
2886func (s *DockerSuite) TestRunReadFilteredProc(c *check.C) {
2887	// Not applicable on Windows as uses Unix specific functionality
2888	testRequires(c, Apparmor, DaemonIsLinux, NotUserNamespace)
2889
2890	testReadPaths := []string{
2891		"/proc/latency_stats",
2892		"/proc/timer_stats",
2893		"/proc/kcore",
2894	}
2895	for i, filePath := range testReadPaths {
2896		name := fmt.Sprintf("procsieve-%d", i)
2897		shellCmd := fmt.Sprintf("exec 3<%s", filePath)
2898
2899		out, exitCode, err := dockerCmdWithError("run", "--privileged", "--security-opt", "apparmor=docker-default", "--name", name, "busybox", "sh", "-c", shellCmd)
2900		if exitCode != 0 {
2901			return
2902		}
2903		if err != nil {
2904			c.Fatalf("Open FD for read should have failed with permission denied, got: %s, %v", out, err)
2905		}
2906	}
2907}
2908
2909func (s *DockerSuite) TestMountIntoProc(c *check.C) {
2910	// Not applicable on Windows as uses Unix specific functionality
2911	testRequires(c, DaemonIsLinux)
2912	_, code, err := dockerCmdWithError("run", "-v", "/proc//sys", "busybox", "true")
2913	if err == nil || code == 0 {
2914		c.Fatal("container should not be able to mount into /proc")
2915	}
2916}
2917
2918func (s *DockerSuite) TestMountIntoSys(c *check.C) {
2919	// Not applicable on Windows as uses Unix specific functionality
2920	testRequires(c, DaemonIsLinux)
2921	testRequires(c, NotUserNamespace)
2922	dockerCmd(c, "run", "-v", "/sys/fs/cgroup", "busybox", "true")
2923}
2924
2925func (s *DockerSuite) TestRunUnshareProc(c *check.C) {
2926	// Not applicable on Windows as uses Unix specific functionality
2927	testRequires(c, Apparmor, DaemonIsLinux, NotUserNamespace)
2928
2929	// In this test goroutines are used to run test cases in parallel to prevent the test from taking a long time to run.
2930	errChan := make(chan error)
2931
2932	go func() {
2933		name := "acidburn"
2934		out, _, err := dockerCmdWithError("run", "--name", name, "--security-opt", "seccomp=unconfined", "debian:jessie", "unshare", "-p", "-m", "-f", "-r", "--mount-proc=/proc", "mount")
2935		if err == nil ||
2936			!(strings.Contains(strings.ToLower(out), "permission denied") ||
2937				strings.Contains(strings.ToLower(out), "operation not permitted")) {
2938			errChan <- fmt.Errorf("unshare with --mount-proc should have failed with 'permission denied' or 'operation not permitted', got: %s, %v", out, err)
2939		} else {
2940			errChan <- nil
2941		}
2942	}()
2943
2944	go func() {
2945		name := "cereal"
2946		out, _, err := dockerCmdWithError("run", "--name", name, "--security-opt", "seccomp=unconfined", "debian:jessie", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc")
2947		if err == nil ||
2948			!(strings.Contains(strings.ToLower(out), "mount: cannot mount none") ||
2949				strings.Contains(strings.ToLower(out), "permission denied") ||
2950				strings.Contains(strings.ToLower(out), "operation not permitted")) {
2951			errChan <- fmt.Errorf("unshare and mount of /proc should have failed with 'mount: cannot mount none' or 'permission denied', got: %s, %v", out, err)
2952		} else {
2953			errChan <- nil
2954		}
2955	}()
2956
2957	/* Ensure still fails if running privileged with the default policy */
2958	go func() {
2959		name := "crashoverride"
2960		out, _, err := dockerCmdWithError("run", "--privileged", "--security-opt", "seccomp=unconfined", "--security-opt", "apparmor=docker-default", "--name", name, "debian:jessie", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc")
2961		if err == nil ||
2962			!(strings.Contains(strings.ToLower(out), "mount: cannot mount none") ||
2963				strings.Contains(strings.ToLower(out), "permission denied") ||
2964				strings.Contains(strings.ToLower(out), "operation not permitted")) {
2965			errChan <- fmt.Errorf("privileged unshare with apparmor should have failed with 'mount: cannot mount none' or 'permission denied', got: %s, %v", out, err)
2966		} else {
2967			errChan <- nil
2968		}
2969	}()
2970
2971	var retErr error
2972	for i := 0; i < 3; i++ {
2973		err := <-errChan
2974		if retErr == nil && err != nil {
2975			retErr = err
2976		}
2977	}
2978	if retErr != nil {
2979		c.Fatal(retErr)
2980	}
2981}
2982
2983func (s *DockerSuite) TestRunPublishPort(c *check.C) {
2984	// TODO Windows: This may be possible once Windows moves to libnetwork and CNM
2985	testRequires(c, DaemonIsLinux)
2986	dockerCmd(c, "run", "-d", "--name", "test", "--expose", "8080", "busybox", "top")
2987	out, _ := dockerCmd(c, "port", "test")
2988	out = strings.Trim(out, "\r\n")
2989	if out != "" {
2990		c.Fatalf("run without --publish-all should not publish port, out should be nil, but got: %s", out)
2991	}
2992}
2993
2994// Issue #10184.
2995func (s *DockerSuite) TestDevicePermissions(c *check.C) {
2996	// Not applicable on Windows as uses Unix specific functionality
2997	testRequires(c, DaemonIsLinux)
2998	const permissions = "crw-rw-rw-"
2999	out, status := dockerCmd(c, "run", "--device", "/dev/fuse:/dev/fuse:mrw", "busybox:latest", "ls", "-l", "/dev/fuse")
3000	if status != 0 {
3001		c.Fatalf("expected status 0, got %d", status)
3002	}
3003	if !strings.HasPrefix(out, permissions) {
3004		c.Fatalf("output should begin with %q, got %q", permissions, out)
3005	}
3006}
3007
3008func (s *DockerSuite) TestRunCapAddCHOWN(c *check.C) {
3009	// Not applicable on Windows as uses Unix specific functionality
3010	testRequires(c, DaemonIsLinux)
3011	out, _ := dockerCmd(c, "run", "--cap-drop=ALL", "--cap-add=CHOWN", "busybox", "sh", "-c", "adduser -D -H newuser && chown newuser /home && echo ok")
3012
3013	if actual := strings.Trim(out, "\r\n"); actual != "ok" {
3014		c.Fatalf("expected output ok received %s", actual)
3015	}
3016}
3017
3018// https://github.com/docker/docker/pull/14498
3019func (s *DockerSuite) TestVolumeFromMixedRWOptions(c *check.C) {
3020	prefix, slash := getPrefixAndSlashFromDaemonPlatform()
3021
3022	dockerCmd(c, "run", "--name", "parent", "-v", prefix+"/test", "busybox", "true")
3023
3024	dockerCmd(c, "run", "--volumes-from", "parent:ro", "--name", "test-volumes-1", "busybox", "true")
3025	dockerCmd(c, "run", "--volumes-from", "parent:rw", "--name", "test-volumes-2", "busybox", "true")
3026
3027	if testEnv.OSType != "windows" {
3028		mRO, err := inspectMountPoint("test-volumes-1", prefix+slash+"test")
3029		c.Assert(err, checker.IsNil, check.Commentf("failed to inspect mount point"))
3030		if mRO.RW {
3031			c.Fatalf("Expected RO volume was RW")
3032		}
3033	}
3034
3035	mRW, err := inspectMountPoint("test-volumes-2", prefix+slash+"test")
3036	c.Assert(err, checker.IsNil, check.Commentf("failed to inspect mount point"))
3037	if !mRW.RW {
3038		c.Fatalf("Expected RW volume was RO")
3039	}
3040}
3041
3042func (s *DockerSuite) TestRunWriteFilteredProc(c *check.C) {
3043	// Not applicable on Windows as uses Unix specific functionality
3044	testRequires(c, Apparmor, DaemonIsLinux, NotUserNamespace)
3045
3046	testWritePaths := []string{
3047		/* modprobe and core_pattern should both be denied by generic
3048		 * policy of denials for /proc/sys/kernel. These files have been
3049		 * picked to be checked as they are particularly sensitive to writes */
3050		"/proc/sys/kernel/modprobe",
3051		"/proc/sys/kernel/core_pattern",
3052		"/proc/sysrq-trigger",
3053		"/proc/kcore",
3054	}
3055	for i, filePath := range testWritePaths {
3056		name := fmt.Sprintf("writeprocsieve-%d", i)
3057
3058		shellCmd := fmt.Sprintf("exec 3>%s", filePath)
3059		out, code, err := dockerCmdWithError("run", "--privileged", "--security-opt", "apparmor=docker-default", "--name", name, "busybox", "sh", "-c", shellCmd)
3060		if code != 0 {
3061			return
3062		}
3063		if err != nil {
3064			c.Fatalf("Open FD for write should have failed with permission denied, got: %s, %v", out, err)
3065		}
3066	}
3067}
3068
3069func (s *DockerSuite) TestRunNetworkFilesBindMount(c *check.C) {
3070	// Not applicable on Windows as uses Unix specific functionality
3071	testRequires(c, SameHostDaemon, DaemonIsLinux)
3072
3073	expected := "test123"
3074
3075	filename := createTmpFile(c, expected)
3076	defer os.Remove(filename)
3077
3078	// for user namespaced test runs, the temp file must be accessible to unprivileged root
3079	if err := os.Chmod(filename, 0646); err != nil {
3080		c.Fatalf("error modifying permissions of %s: %v", filename, err)
3081	}
3082
3083	nwfiles := []string{"/etc/resolv.conf", "/etc/hosts", "/etc/hostname"}
3084
3085	for i := range nwfiles {
3086		actual, _ := dockerCmd(c, "run", "-v", filename+":"+nwfiles[i], "busybox", "cat", nwfiles[i])
3087		if actual != expected {
3088			c.Fatalf("expected %s be: %q, but was: %q", nwfiles[i], expected, actual)
3089		}
3090	}
3091}
3092
3093func (s *DockerSuite) TestRunNetworkFilesBindMountRO(c *check.C) {
3094	// Not applicable on Windows as uses Unix specific functionality
3095	testRequires(c, SameHostDaemon, DaemonIsLinux)
3096
3097	filename := createTmpFile(c, "test123")
3098	defer os.Remove(filename)
3099
3100	// for user namespaced test runs, the temp file must be accessible to unprivileged root
3101	if err := os.Chmod(filename, 0646); err != nil {
3102		c.Fatalf("error modifying permissions of %s: %v", filename, err)
3103	}
3104
3105	nwfiles := []string{"/etc/resolv.conf", "/etc/hosts", "/etc/hostname"}
3106
3107	for i := range nwfiles {
3108		_, exitCode, err := dockerCmdWithError("run", "-v", filename+":"+nwfiles[i]+":ro", "busybox", "touch", nwfiles[i])
3109		if err == nil || exitCode == 0 {
3110			c.Fatalf("run should fail because bind mount of %s is ro: exit code %d", nwfiles[i], exitCode)
3111		}
3112	}
3113}
3114
3115func (s *DockerSuite) TestRunNetworkFilesBindMountROFilesystem(c *check.C) {
3116	// Not applicable on Windows as uses Unix specific functionality
3117	testRequires(c, SameHostDaemon, DaemonIsLinux, UserNamespaceROMount)
3118
3119	filename := createTmpFile(c, "test123")
3120	defer os.Remove(filename)
3121
3122	// for user namespaced test runs, the temp file must be accessible to unprivileged root
3123	if err := os.Chmod(filename, 0646); err != nil {
3124		c.Fatalf("error modifying permissions of %s: %v", filename, err)
3125	}
3126
3127	nwfiles := []string{"/etc/resolv.conf", "/etc/hosts", "/etc/hostname"}
3128
3129	for i := range nwfiles {
3130		_, exitCode := dockerCmd(c, "run", "-v", filename+":"+nwfiles[i], "--read-only", "busybox", "touch", nwfiles[i])
3131		if exitCode != 0 {
3132			c.Fatalf("run should not fail because %s is mounted writable on read-only root filesystem: exit code %d", nwfiles[i], exitCode)
3133		}
3134	}
3135
3136	for i := range nwfiles {
3137		_, exitCode, err := dockerCmdWithError("run", "-v", filename+":"+nwfiles[i]+":ro", "--read-only", "busybox", "touch", nwfiles[i])
3138		if err == nil || exitCode == 0 {
3139			c.Fatalf("run should fail because %s is mounted read-only on read-only root filesystem: exit code %d", nwfiles[i], exitCode)
3140		}
3141	}
3142}
3143
3144func (s *DockerSuite) TestPtraceContainerProcsFromHost(c *check.C) {
3145	// Not applicable on Windows as uses Unix specific functionality
3146	testRequires(c, DaemonIsLinux, SameHostDaemon)
3147
3148	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
3149	id := strings.TrimSpace(out)
3150	c.Assert(waitRun(id), check.IsNil)
3151	pid1 := inspectField(c, id, "State.Pid")
3152
3153	_, err := os.Readlink(fmt.Sprintf("/proc/%s/ns/net", pid1))
3154	if err != nil {
3155		c.Fatal(err)
3156	}
3157}
3158
3159func (s *DockerSuite) TestAppArmorDeniesPtrace(c *check.C) {
3160	// Not applicable on Windows as uses Unix specific functionality
3161	testRequires(c, SameHostDaemon, Apparmor, DaemonIsLinux)
3162
3163	// Run through 'sh' so we are NOT pid 1. Pid 1 may be able to trace
3164	// itself, but pid>1 should not be able to trace pid1.
3165	_, exitCode, _ := dockerCmdWithError("run", "busybox", "sh", "-c", "sh -c readlink /proc/1/ns/net")
3166	if exitCode == 0 {
3167		c.Fatal("ptrace was not successfully restricted by AppArmor")
3168	}
3169}
3170
3171func (s *DockerSuite) TestAppArmorTraceSelf(c *check.C) {
3172	// Not applicable on Windows as uses Unix specific functionality
3173	testRequires(c, DaemonIsLinux, SameHostDaemon, Apparmor)
3174
3175	_, exitCode, _ := dockerCmdWithError("run", "busybox", "readlink", "/proc/1/ns/net")
3176	if exitCode != 0 {
3177		c.Fatal("ptrace of self failed.")
3178	}
3179}
3180
3181func (s *DockerSuite) TestAppArmorDeniesChmodProc(c *check.C) {
3182	// Not applicable on Windows as uses Unix specific functionality
3183	testRequires(c, SameHostDaemon, Apparmor, DaemonIsLinux, NotUserNamespace)
3184	_, exitCode, _ := dockerCmdWithError("run", "busybox", "chmod", "744", "/proc/cpuinfo")
3185	if exitCode == 0 {
3186		// If our test failed, attempt to repair the host system...
3187		_, exitCode, _ := dockerCmdWithError("run", "busybox", "chmod", "444", "/proc/cpuinfo")
3188		if exitCode == 0 {
3189			c.Fatal("AppArmor was unsuccessful in prohibiting chmod of /proc/* files.")
3190		}
3191	}
3192}
3193
3194func (s *DockerSuite) TestRunCapAddSYSTIME(c *check.C) {
3195	// Not applicable on Windows as uses Unix specific functionality
3196	testRequires(c, DaemonIsLinux)
3197
3198	dockerCmd(c, "run", "--cap-drop=ALL", "--cap-add=SYS_TIME", "busybox", "sh", "-c", "grep ^CapEff /proc/self/status | sed 's/^CapEff:\t//' | grep ^0000000002000000$")
3199}
3200
3201// run create container failed should clean up the container
3202func (s *DockerSuite) TestRunCreateContainerFailedCleanUp(c *check.C) {
3203	// TODO Windows. This may be possible to enable once link is supported
3204	testRequires(c, DaemonIsLinux)
3205	name := "unique_name"
3206	_, _, err := dockerCmdWithError("run", "--name", name, "--link", "nothing:nothing", "busybox")
3207	c.Assert(err, check.NotNil, check.Commentf("Expected docker run to fail!"))
3208
3209	containerID, err := inspectFieldWithError(name, "Id")
3210	c.Assert(err, checker.NotNil, check.Commentf("Expected not to have this container: %s!", containerID))
3211	c.Assert(containerID, check.Equals, "", check.Commentf("Expected not to have this container: %s!", containerID))
3212}
3213
3214func (s *DockerSuite) TestRunNamedVolume(c *check.C) {
3215	prefix, _ := getPrefixAndSlashFromDaemonPlatform()
3216	testRequires(c, DaemonIsLinux)
3217	dockerCmd(c, "run", "--name=test", "-v", "testing:"+prefix+"/foo", "busybox", "sh", "-c", "echo hello > "+prefix+"/foo/bar")
3218
3219	out, _ := dockerCmd(c, "run", "--volumes-from", "test", "busybox", "sh", "-c", "cat "+prefix+"/foo/bar")
3220	c.Assert(strings.TrimSpace(out), check.Equals, "hello")
3221
3222	out, _ = dockerCmd(c, "run", "-v", "testing:"+prefix+"/foo", "busybox", "sh", "-c", "cat "+prefix+"/foo/bar")
3223	c.Assert(strings.TrimSpace(out), check.Equals, "hello")
3224}
3225
3226func (s *DockerSuite) TestRunWithUlimits(c *check.C) {
3227	// Not applicable on Windows as uses Unix specific functionality
3228	testRequires(c, DaemonIsLinux)
3229
3230	out, _ := dockerCmd(c, "run", "--name=testulimits", "--ulimit", "nofile=42", "busybox", "/bin/sh", "-c", "ulimit -n")
3231	ul := strings.TrimSpace(out)
3232	if ul != "42" {
3233		c.Fatalf("expected `ulimit -n` to be 42, got %s", ul)
3234	}
3235}
3236
3237func (s *DockerSuite) TestRunContainerWithCgroupParent(c *check.C) {
3238	// Not applicable on Windows as uses Unix specific functionality
3239	testRequires(c, DaemonIsLinux)
3240
3241	// cgroup-parent relative path
3242	testRunContainerWithCgroupParent(c, "test", "cgroup-test")
3243
3244	// cgroup-parent absolute path
3245	testRunContainerWithCgroupParent(c, "/cgroup-parent/test", "cgroup-test-absolute")
3246}
3247
3248func testRunContainerWithCgroupParent(c *check.C, cgroupParent, name string) {
3249	out, _, err := dockerCmdWithError("run", "--cgroup-parent", cgroupParent, "--name", name, "busybox", "cat", "/proc/self/cgroup")
3250	if err != nil {
3251		c.Fatalf("unexpected failure when running container with --cgroup-parent option - %s\n%v", string(out), err)
3252	}
3253	cgroupPaths := ParseCgroupPaths(string(out))
3254	if len(cgroupPaths) == 0 {
3255		c.Fatalf("unexpected output - %q", string(out))
3256	}
3257	id := getIDByName(c, name)
3258	expectedCgroup := path.Join(cgroupParent, id)
3259	found := false
3260	for _, path := range cgroupPaths {
3261		if strings.HasSuffix(path, expectedCgroup) {
3262			found = true
3263			break
3264		}
3265	}
3266	if !found {
3267		c.Fatalf("unexpected cgroup paths. Expected at least one cgroup path to have suffix %q. Cgroup Paths: %v", expectedCgroup, cgroupPaths)
3268	}
3269}
3270
3271// TestRunInvalidCgroupParent checks that a specially-crafted cgroup parent doesn't cause Docker to crash or start modifying /.
3272func (s *DockerSuite) TestRunInvalidCgroupParent(c *check.C) {
3273	// Not applicable on Windows as uses Unix specific functionality
3274	testRequires(c, DaemonIsLinux)
3275
3276	testRunInvalidCgroupParent(c, "../../../../../../../../SHOULD_NOT_EXIST", "SHOULD_NOT_EXIST", "cgroup-invalid-test")
3277
3278	testRunInvalidCgroupParent(c, "/../../../../../../../../SHOULD_NOT_EXIST", "/SHOULD_NOT_EXIST", "cgroup-absolute-invalid-test")
3279}
3280
3281func testRunInvalidCgroupParent(c *check.C, cgroupParent, cleanCgroupParent, name string) {
3282	out, _, err := dockerCmdWithError("run", "--cgroup-parent", cgroupParent, "--name", name, "busybox", "cat", "/proc/self/cgroup")
3283	if err != nil {
3284		// XXX: This may include a daemon crash.
3285		c.Fatalf("unexpected failure when running container with --cgroup-parent option - %s\n%v", string(out), err)
3286	}
3287
3288	// We expect "/SHOULD_NOT_EXIST" to not exist. If not, we have a security issue.
3289	if _, err := os.Stat("/SHOULD_NOT_EXIST"); err == nil || !os.IsNotExist(err) {
3290		c.Fatalf("SECURITY: --cgroup-parent with ../../ relative paths cause files to be created in the host (this is bad) !!")
3291	}
3292
3293	cgroupPaths := ParseCgroupPaths(string(out))
3294	if len(cgroupPaths) == 0 {
3295		c.Fatalf("unexpected output - %q", string(out))
3296	}
3297	id := getIDByName(c, name)
3298	expectedCgroup := path.Join(cleanCgroupParent, id)
3299	found := false
3300	for _, path := range cgroupPaths {
3301		if strings.HasSuffix(path, expectedCgroup) {
3302			found = true
3303			break
3304		}
3305	}
3306	if !found {
3307		c.Fatalf("unexpected cgroup paths. Expected at least one cgroup path to have suffix %q. Cgroup Paths: %v", expectedCgroup, cgroupPaths)
3308	}
3309}
3310
3311func (s *DockerSuite) TestRunContainerWithCgroupMountRO(c *check.C) {
3312	// Not applicable on Windows as uses Unix specific functionality
3313	// --read-only + userns has remount issues
3314	testRequires(c, DaemonIsLinux, NotUserNamespace)
3315
3316	filename := "/sys/fs/cgroup/devices/test123"
3317	out, _, err := dockerCmdWithError("run", "busybox", "touch", filename)
3318	if err == nil {
3319		c.Fatal("expected cgroup mount point to be read-only, touch file should fail")
3320	}
3321	expected := "Read-only file system"
3322	if !strings.Contains(out, expected) {
3323		c.Fatalf("expected output from failure to contain %s but contains %s", expected, out)
3324	}
3325}
3326
3327func (s *DockerSuite) TestRunContainerNetworkModeToSelf(c *check.C) {
3328	// Not applicable on Windows which does not support --net=container
3329	testRequires(c, DaemonIsLinux)
3330	out, _, err := dockerCmdWithError("run", "--name=me", "--net=container:me", "busybox", "true")
3331	if err == nil || !strings.Contains(out, "cannot join own network") {
3332		c.Fatalf("using container net mode to self should result in an error\nerr: %q\nout: %s", err, out)
3333	}
3334}
3335
3336func (s *DockerSuite) TestRunContainerNetModeWithDNSMacHosts(c *check.C) {
3337	// Not applicable on Windows which does not support --net=container
3338	testRequires(c, DaemonIsLinux)
3339	out, _, err := dockerCmdWithError("run", "-d", "--name", "parent", "busybox", "top")
3340	if err != nil {
3341		c.Fatalf("failed to run container: %v, output: %q", err, out)
3342	}
3343
3344	out, _, err = dockerCmdWithError("run", "--dns", "1.2.3.4", "--net=container:parent", "busybox")
3345	if err == nil || !strings.Contains(out, runconfig.ErrConflictNetworkAndDNS.Error()) {
3346		c.Fatalf("run --net=container with --dns should error out")
3347	}
3348
3349	out, _, err = dockerCmdWithError("run", "--mac-address", "92:d0:c6:0a:29:33", "--net=container:parent", "busybox")
3350	if err == nil || !strings.Contains(out, runconfig.ErrConflictContainerNetworkAndMac.Error()) {
3351		c.Fatalf("run --net=container with --mac-address should error out")
3352	}
3353
3354	out, _, err = dockerCmdWithError("run", "--add-host", "test:192.168.2.109", "--net=container:parent", "busybox")
3355	if err == nil || !strings.Contains(out, runconfig.ErrConflictNetworkHosts.Error()) {
3356		c.Fatalf("run --net=container with --add-host should error out")
3357	}
3358}
3359
3360func (s *DockerSuite) TestRunContainerNetModeWithExposePort(c *check.C) {
3361	// Not applicable on Windows which does not support --net=container
3362	testRequires(c, DaemonIsLinux)
3363	dockerCmd(c, "run", "-d", "--name", "parent", "busybox", "top")
3364
3365	out, _, err := dockerCmdWithError("run", "-p", "5000:5000", "--net=container:parent", "busybox")
3366	if err == nil || !strings.Contains(out, runconfig.ErrConflictNetworkPublishPorts.Error()) {
3367		c.Fatalf("run --net=container with -p should error out")
3368	}
3369
3370	out, _, err = dockerCmdWithError("run", "-P", "--net=container:parent", "busybox")
3371	if err == nil || !strings.Contains(out, runconfig.ErrConflictNetworkPublishPorts.Error()) {
3372		c.Fatalf("run --net=container with -P should error out")
3373	}
3374
3375	out, _, err = dockerCmdWithError("run", "--expose", "5000", "--net=container:parent", "busybox")
3376	if err == nil || !strings.Contains(out, runconfig.ErrConflictNetworkExposePorts.Error()) {
3377		c.Fatalf("run --net=container with --expose should error out")
3378	}
3379}
3380
3381func (s *DockerSuite) TestRunLinkToContainerNetMode(c *check.C) {
3382	// Not applicable on Windows which does not support --net=container or --link
3383	testRequires(c, DaemonIsLinux)
3384	dockerCmd(c, "run", "--name", "test", "-d", "busybox", "top")
3385	dockerCmd(c, "run", "--name", "parent", "-d", "--net=container:test", "busybox", "top")
3386	dockerCmd(c, "run", "-d", "--link=parent:parent", "busybox", "top")
3387	dockerCmd(c, "run", "--name", "child", "-d", "--net=container:parent", "busybox", "top")
3388	dockerCmd(c, "run", "-d", "--link=child:child", "busybox", "top")
3389}
3390
3391func (s *DockerSuite) TestRunLoopbackOnlyExistsWhenNetworkingDisabled(c *check.C) {
3392	// TODO Windows: This may be possible to convert.
3393	testRequires(c, DaemonIsLinux)
3394	out, _ := dockerCmd(c, "run", "--net=none", "busybox", "ip", "-o", "-4", "a", "show", "up")
3395
3396	var (
3397		count = 0
3398		parts = strings.Split(out, "\n")
3399	)
3400
3401	for _, l := range parts {
3402		if l != "" {
3403			count++
3404		}
3405	}
3406
3407	if count != 1 {
3408		c.Fatalf("Wrong interface count in container %d", count)
3409	}
3410
3411	if !strings.HasPrefix(out, "1: lo") {
3412		c.Fatalf("Wrong interface in test container: expected [1: lo], got %s", out)
3413	}
3414}
3415
3416// Issue #4681
3417func (s *DockerSuite) TestRunLoopbackWhenNetworkDisabled(c *check.C) {
3418	if testEnv.OSType == "windows" {
3419		dockerCmd(c, "run", "--net=none", testEnv.PlatformDefaults.BaseImage, "ping", "-n", "1", "127.0.0.1")
3420	} else {
3421		dockerCmd(c, "run", "--net=none", "busybox", "ping", "-c", "1", "127.0.0.1")
3422	}
3423}
3424
3425func (s *DockerSuite) TestRunModeNetContainerHostname(c *check.C) {
3426	// Windows does not support --net=container
3427	testRequires(c, DaemonIsLinux, ExecSupport)
3428
3429	dockerCmd(c, "run", "-i", "-d", "--name", "parent", "busybox", "top")
3430	out, _ := dockerCmd(c, "exec", "parent", "cat", "/etc/hostname")
3431	out1, _ := dockerCmd(c, "run", "--net=container:parent", "busybox", "cat", "/etc/hostname")
3432
3433	if out1 != out {
3434		c.Fatal("containers with shared net namespace should have same hostname")
3435	}
3436}
3437
3438func (s *DockerSuite) TestRunNetworkNotInitializedNoneMode(c *check.C) {
3439	// TODO Windows: Network settings are not currently propagated. This may
3440	// be resolved in the future with the move to libnetwork and CNM.
3441	testRequires(c, DaemonIsLinux)
3442	out, _ := dockerCmd(c, "run", "-d", "--net=none", "busybox", "top")
3443	id := strings.TrimSpace(out)
3444	res := inspectField(c, id, "NetworkSettings.Networks.none.IPAddress")
3445	if res != "" {
3446		c.Fatalf("For 'none' mode network must not be initialized, but container got IP: %s", res)
3447	}
3448}
3449
3450func (s *DockerSuite) TestTwoContainersInNetHost(c *check.C) {
3451	// Not applicable as Windows does not support --net=host
3452	testRequires(c, DaemonIsLinux, NotUserNamespace, NotUserNamespace)
3453	dockerCmd(c, "run", "-d", "--net=host", "--name=first", "busybox", "top")
3454	dockerCmd(c, "run", "-d", "--net=host", "--name=second", "busybox", "top")
3455	dockerCmd(c, "stop", "first")
3456	dockerCmd(c, "stop", "second")
3457}
3458
3459func (s *DockerSuite) TestContainersInUserDefinedNetwork(c *check.C) {
3460	testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm)
3461	dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork")
3462	dockerCmd(c, "run", "-d", "--net=testnetwork", "--name=first", "busybox", "top")
3463	c.Assert(waitRun("first"), check.IsNil)
3464	dockerCmd(c, "run", "-t", "--net=testnetwork", "--name=second", "busybox", "ping", "-c", "1", "first")
3465}
3466
3467func (s *DockerSuite) TestContainersInMultipleNetworks(c *check.C) {
3468	testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm)
3469	// Create 2 networks using bridge driver
3470	dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1")
3471	dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork2")
3472	// Run and connect containers to testnetwork1
3473	dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=first", "busybox", "top")
3474	c.Assert(waitRun("first"), check.IsNil)
3475	dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=second", "busybox", "top")
3476	c.Assert(waitRun("second"), check.IsNil)
3477	// Check connectivity between containers in testnetwork2
3478	dockerCmd(c, "exec", "first", "ping", "-c", "1", "second.testnetwork1")
3479	// Connect containers to testnetwork2
3480	dockerCmd(c, "network", "connect", "testnetwork2", "first")
3481	dockerCmd(c, "network", "connect", "testnetwork2", "second")
3482	// Check connectivity between containers
3483	dockerCmd(c, "exec", "second", "ping", "-c", "1", "first.testnetwork2")
3484}
3485
3486func (s *DockerSuite) TestContainersNetworkIsolation(c *check.C) {
3487	testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm)
3488	// Create 2 networks using bridge driver
3489	dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1")
3490	dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork2")
3491	// Run 1 container in testnetwork1 and another in testnetwork2
3492	dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=first", "busybox", "top")
3493	c.Assert(waitRun("first"), check.IsNil)
3494	dockerCmd(c, "run", "-d", "--net=testnetwork2", "--name=second", "busybox", "top")
3495	c.Assert(waitRun("second"), check.IsNil)
3496
3497	// Check Isolation between containers : ping must fail
3498	_, _, err := dockerCmdWithError("exec", "first", "ping", "-c", "1", "second")
3499	c.Assert(err, check.NotNil)
3500	// Connect first container to testnetwork2
3501	dockerCmd(c, "network", "connect", "testnetwork2", "first")
3502	// ping must succeed now
3503	_, _, err = dockerCmdWithError("exec", "first", "ping", "-c", "1", "second")
3504	c.Assert(err, check.IsNil)
3505
3506	// Disconnect first container from testnetwork2
3507	dockerCmd(c, "network", "disconnect", "testnetwork2", "first")
3508	// ping must fail again
3509	_, _, err = dockerCmdWithError("exec", "first", "ping", "-c", "1", "second")
3510	c.Assert(err, check.NotNil)
3511}
3512
3513func (s *DockerSuite) TestNetworkRmWithActiveContainers(c *check.C) {
3514	testRequires(c, DaemonIsLinux, NotUserNamespace)
3515	// Create 2 networks using bridge driver
3516	dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1")
3517	// Run and connect containers to testnetwork1
3518	dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=first", "busybox", "top")
3519	c.Assert(waitRun("first"), check.IsNil)
3520	dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=second", "busybox", "top")
3521	c.Assert(waitRun("second"), check.IsNil)
3522	// Network delete with active containers must fail
3523	_, _, err := dockerCmdWithError("network", "rm", "testnetwork1")
3524	c.Assert(err, check.NotNil)
3525
3526	dockerCmd(c, "stop", "first")
3527	_, _, err = dockerCmdWithError("network", "rm", "testnetwork1")
3528	c.Assert(err, check.NotNil)
3529}
3530
3531func (s *DockerSuite) TestContainerRestartInMultipleNetworks(c *check.C) {
3532	testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm)
3533	// Create 2 networks using bridge driver
3534	dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1")
3535	dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork2")
3536
3537	// Run and connect containers to testnetwork1
3538	dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=first", "busybox", "top")
3539	c.Assert(waitRun("first"), check.IsNil)
3540	dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=second", "busybox", "top")
3541	c.Assert(waitRun("second"), check.IsNil)
3542	// Check connectivity between containers in testnetwork2
3543	dockerCmd(c, "exec", "first", "ping", "-c", "1", "second.testnetwork1")
3544	// Connect containers to testnetwork2
3545	dockerCmd(c, "network", "connect", "testnetwork2", "first")
3546	dockerCmd(c, "network", "connect", "testnetwork2", "second")
3547	// Check connectivity between containers
3548	dockerCmd(c, "exec", "second", "ping", "-c", "1", "first.testnetwork2")
3549
3550	// Stop second container and test ping failures on both networks
3551	dockerCmd(c, "stop", "second")
3552	_, _, err := dockerCmdWithError("exec", "first", "ping", "-c", "1", "second.testnetwork1")
3553	c.Assert(err, check.NotNil)
3554	_, _, err = dockerCmdWithError("exec", "first", "ping", "-c", "1", "second.testnetwork2")
3555	c.Assert(err, check.NotNil)
3556
3557	// Start second container and connectivity must be restored on both networks
3558	dockerCmd(c, "start", "second")
3559	dockerCmd(c, "exec", "first", "ping", "-c", "1", "second.testnetwork1")
3560	dockerCmd(c, "exec", "second", "ping", "-c", "1", "first.testnetwork2")
3561}
3562
3563func (s *DockerSuite) TestContainerWithConflictingHostNetworks(c *check.C) {
3564	testRequires(c, DaemonIsLinux, NotUserNamespace)
3565	// Run a container with --net=host
3566	dockerCmd(c, "run", "-d", "--net=host", "--name=first", "busybox", "top")
3567	c.Assert(waitRun("first"), check.IsNil)
3568
3569	// Create a network using bridge driver
3570	dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1")
3571
3572	// Connecting to the user defined network must fail
3573	_, _, err := dockerCmdWithError("network", "connect", "testnetwork1", "first")
3574	c.Assert(err, check.NotNil)
3575}
3576
3577func (s *DockerSuite) TestContainerWithConflictingSharedNetwork(c *check.C) {
3578	testRequires(c, DaemonIsLinux)
3579	dockerCmd(c, "run", "-d", "--name=first", "busybox", "top")
3580	c.Assert(waitRun("first"), check.IsNil)
3581	// Run second container in first container's network namespace
3582	dockerCmd(c, "run", "-d", "--net=container:first", "--name=second", "busybox", "top")
3583	c.Assert(waitRun("second"), check.IsNil)
3584
3585	// Create a network using bridge driver
3586	dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1")
3587
3588	// Connecting to the user defined network must fail
3589	out, _, err := dockerCmdWithError("network", "connect", "testnetwork1", "second")
3590	c.Assert(err, check.NotNil)
3591	c.Assert(out, checker.Contains, runconfig.ErrConflictSharedNetwork.Error())
3592}
3593
3594func (s *DockerSuite) TestContainerWithConflictingNoneNetwork(c *check.C) {
3595	testRequires(c, DaemonIsLinux)
3596	dockerCmd(c, "run", "-d", "--net=none", "--name=first", "busybox", "top")
3597	c.Assert(waitRun("first"), check.IsNil)
3598
3599	// Create a network using bridge driver
3600	dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1")
3601
3602	// Connecting to the user defined network must fail
3603	out, _, err := dockerCmdWithError("network", "connect", "testnetwork1", "first")
3604	c.Assert(err, check.NotNil)
3605	c.Assert(out, checker.Contains, runconfig.ErrConflictNoNetwork.Error())
3606
3607	// create a container connected to testnetwork1
3608	dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=second", "busybox", "top")
3609	c.Assert(waitRun("second"), check.IsNil)
3610
3611	// Connect second container to none network. it must fail as well
3612	_, _, err = dockerCmdWithError("network", "connect", "none", "second")
3613	c.Assert(err, check.NotNil)
3614}
3615
3616// #11957 - stdin with no tty does not exit if stdin is not closed even though container exited
3617func (s *DockerSuite) TestRunStdinBlockedAfterContainerExit(c *check.C) {
3618	cmd := exec.Command(dockerBinary, "run", "-i", "--name=test", "busybox", "true")
3619	in, err := cmd.StdinPipe()
3620	c.Assert(err, check.IsNil)
3621	defer in.Close()
3622	stdout := bytes.NewBuffer(nil)
3623	cmd.Stdout = stdout
3624	cmd.Stderr = stdout
3625	c.Assert(cmd.Start(), check.IsNil)
3626
3627	waitChan := make(chan error)
3628	go func() {
3629		waitChan <- cmd.Wait()
3630	}()
3631
3632	select {
3633	case err := <-waitChan:
3634		c.Assert(err, check.IsNil, check.Commentf(stdout.String()))
3635	case <-time.After(30 * time.Second):
3636		c.Fatal("timeout waiting for command to exit")
3637	}
3638}
3639
3640func (s *DockerSuite) TestRunWrongCpusetCpusFlagValue(c *check.C) {
3641	// TODO Windows: This needs validation (error out) in the daemon.
3642	testRequires(c, DaemonIsLinux)
3643	out, exitCode, err := dockerCmdWithError("run", "--cpuset-cpus", "1-10,11--", "busybox", "true")
3644	c.Assert(err, check.NotNil)
3645	expected := "Error response from daemon: Invalid value 1-10,11-- for cpuset cpus.\n"
3646	if !(strings.Contains(out, expected) || exitCode == 125) {
3647		c.Fatalf("Expected output to contain %q with exitCode 125, got out: %q exitCode: %v", expected, out, exitCode)
3648	}
3649}
3650
3651func (s *DockerSuite) TestRunWrongCpusetMemsFlagValue(c *check.C) {
3652	// TODO Windows: This needs validation (error out) in the daemon.
3653	testRequires(c, DaemonIsLinux)
3654	out, exitCode, err := dockerCmdWithError("run", "--cpuset-mems", "1-42--", "busybox", "true")
3655	c.Assert(err, check.NotNil)
3656	expected := "Error response from daemon: Invalid value 1-42-- for cpuset mems.\n"
3657	if !(strings.Contains(out, expected) || exitCode == 125) {
3658		c.Fatalf("Expected output to contain %q with exitCode 125, got out: %q exitCode: %v", expected, out, exitCode)
3659	}
3660}
3661
3662// TestRunNonExecutableCmd checks that 'docker run busybox foo' exits with error code 127'
3663func (s *DockerSuite) TestRunNonExecutableCmd(c *check.C) {
3664	name := "testNonExecutableCmd"
3665	icmd.RunCommand(dockerBinary, "run", "--name", name, "busybox", "foo").Assert(c, icmd.Expected{
3666		ExitCode: 127,
3667		Error:    "exit status 127",
3668	})
3669}
3670
3671// TestRunNonExistingCmd checks that 'docker run busybox /bin/foo' exits with code 127.
3672func (s *DockerSuite) TestRunNonExistingCmd(c *check.C) {
3673	name := "testNonExistingCmd"
3674	icmd.RunCommand(dockerBinary, "run", "--name", name, "busybox", "/bin/foo").Assert(c, icmd.Expected{
3675		ExitCode: 127,
3676		Error:    "exit status 127",
3677	})
3678}
3679
3680// TestCmdCannotBeInvoked checks that 'docker run busybox /etc' exits with 126, or
3681// 127 on Windows. The difference is that in Windows, the container must be started
3682// as that's when the check is made (and yes, by its design...)
3683func (s *DockerSuite) TestCmdCannotBeInvoked(c *check.C) {
3684	expected := 126
3685	if testEnv.OSType == "windows" {
3686		expected = 127
3687	}
3688	name := "testCmdCannotBeInvoked"
3689	icmd.RunCommand(dockerBinary, "run", "--name", name, "busybox", "/etc").Assert(c, icmd.Expected{
3690		ExitCode: expected,
3691		Error:    fmt.Sprintf("exit status %d", expected),
3692	})
3693}
3694
3695// TestRunNonExistingImage checks that 'docker run foo' exits with error msg 125 and contains  'Unable to find image'
3696// FIXME(vdemeester) should be a unit test
3697func (s *DockerSuite) TestRunNonExistingImage(c *check.C) {
3698	icmd.RunCommand(dockerBinary, "run", "foo").Assert(c, icmd.Expected{
3699		ExitCode: 125,
3700		Err:      "Unable to find image",
3701	})
3702}
3703
3704// TestDockerFails checks that 'docker run -foo busybox' exits with 125 to signal docker run failed
3705// FIXME(vdemeester) should be a unit test
3706func (s *DockerSuite) TestDockerFails(c *check.C) {
3707	icmd.RunCommand(dockerBinary, "run", "-foo", "busybox").Assert(c, icmd.Expected{
3708		ExitCode: 125,
3709		Error:    "exit status 125",
3710	})
3711}
3712
3713// TestRunInvalidReference invokes docker run with a bad reference.
3714func (s *DockerSuite) TestRunInvalidReference(c *check.C) {
3715	out, exit, _ := dockerCmdWithError("run", "busybox@foo")
3716	if exit == 0 {
3717		c.Fatalf("expected non-zero exist code; received %d", exit)
3718	}
3719
3720	if !strings.Contains(out, "invalid reference format") {
3721		c.Fatalf(`Expected "invalid reference format" in output; got: %s`, out)
3722	}
3723}
3724
3725// Test fix for issue #17854
3726func (s *DockerSuite) TestRunInitLayerPathOwnership(c *check.C) {
3727	// Not applicable on Windows as it does not support Linux uid/gid ownership
3728	testRequires(c, DaemonIsLinux)
3729	name := "testetcfileownership"
3730	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
3731		RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
3732		RUN echo 'dockerio:x:1001:' >> /etc/group
3733		RUN chown dockerio:dockerio /etc`))
3734
3735	// Test that dockerio ownership of /etc is retained at runtime
3736	out, _ := dockerCmd(c, "run", "--rm", name, "stat", "-c", "%U:%G", "/etc")
3737	out = strings.TrimSpace(out)
3738	if out != "dockerio:dockerio" {
3739		c.Fatalf("Wrong /etc ownership: expected dockerio:dockerio, got %q", out)
3740	}
3741}
3742
3743func (s *DockerSuite) TestRunWithOomScoreAdj(c *check.C) {
3744	testRequires(c, DaemonIsLinux)
3745
3746	expected := "642"
3747	out, _ := dockerCmd(c, "run", "--oom-score-adj", expected, "busybox", "cat", "/proc/self/oom_score_adj")
3748	oomScoreAdj := strings.TrimSpace(out)
3749	if oomScoreAdj != "642" {
3750		c.Fatalf("Expected oom_score_adj set to %q, got %q instead", expected, oomScoreAdj)
3751	}
3752}
3753
3754func (s *DockerSuite) TestRunWithOomScoreAdjInvalidRange(c *check.C) {
3755	testRequires(c, DaemonIsLinux)
3756
3757	out, _, err := dockerCmdWithError("run", "--oom-score-adj", "1001", "busybox", "true")
3758	c.Assert(err, check.NotNil)
3759	expected := "Invalid value 1001, range for oom score adj is [-1000, 1000]."
3760	if !strings.Contains(out, expected) {
3761		c.Fatalf("Expected output to contain %q, got %q instead", expected, out)
3762	}
3763	out, _, err = dockerCmdWithError("run", "--oom-score-adj", "-1001", "busybox", "true")
3764	c.Assert(err, check.NotNil)
3765	expected = "Invalid value -1001, range for oom score adj is [-1000, 1000]."
3766	if !strings.Contains(out, expected) {
3767		c.Fatalf("Expected output to contain %q, got %q instead", expected, out)
3768	}
3769}
3770
3771func (s *DockerSuite) TestRunVolumesMountedAsShared(c *check.C) {
3772	// Volume propagation is linux only. Also it creates directories for
3773	// bind mounting, so needs to be same host.
3774	testRequires(c, DaemonIsLinux, SameHostDaemon, NotUserNamespace)
3775
3776	// Prepare a source directory to bind mount
3777	tmpDir, err := ioutil.TempDir("", "volume-source")
3778	if err != nil {
3779		c.Fatal(err)
3780	}
3781	defer os.RemoveAll(tmpDir)
3782
3783	if err := os.Mkdir(path.Join(tmpDir, "mnt1"), 0755); err != nil {
3784		c.Fatal(err)
3785	}
3786
3787	// Convert this directory into a shared mount point so that we do
3788	// not rely on propagation properties of parent mount.
3789	icmd.RunCommand("mount", "--bind", tmpDir, tmpDir).Assert(c, icmd.Success)
3790	icmd.RunCommand("mount", "--make-private", "--make-shared", tmpDir).Assert(c, icmd.Success)
3791
3792	dockerCmd(c, "run", "--privileged", "-v", fmt.Sprintf("%s:/volume-dest:shared", tmpDir), "busybox", "mount", "--bind", "/volume-dest/mnt1", "/volume-dest/mnt1")
3793
3794	// Make sure a bind mount under a shared volume propagated to host.
3795	if mounted, _ := mount.Mounted(path.Join(tmpDir, "mnt1")); !mounted {
3796		c.Fatalf("Bind mount under shared volume did not propagate to host")
3797	}
3798
3799	mount.Unmount(path.Join(tmpDir, "mnt1"))
3800}
3801
3802func (s *DockerSuite) TestRunVolumesMountedAsSlave(c *check.C) {
3803	// Volume propagation is linux only. Also it creates directories for
3804	// bind mounting, so needs to be same host.
3805	testRequires(c, DaemonIsLinux, SameHostDaemon, NotUserNamespace)
3806
3807	// Prepare a source directory to bind mount
3808	tmpDir, err := ioutil.TempDir("", "volume-source")
3809	if err != nil {
3810		c.Fatal(err)
3811	}
3812	defer os.RemoveAll(tmpDir)
3813
3814	if err := os.Mkdir(path.Join(tmpDir, "mnt1"), 0755); err != nil {
3815		c.Fatal(err)
3816	}
3817
3818	// Prepare a source directory with file in it. We will bind mount this
3819	// directory and see if file shows up.
3820	tmpDir2, err := ioutil.TempDir("", "volume-source2")
3821	if err != nil {
3822		c.Fatal(err)
3823	}
3824	defer os.RemoveAll(tmpDir2)
3825
3826	if err := ioutil.WriteFile(path.Join(tmpDir2, "slave-testfile"), []byte("Test"), 0644); err != nil {
3827		c.Fatal(err)
3828	}
3829
3830	// Convert this directory into a shared mount point so that we do
3831	// not rely on propagation properties of parent mount.
3832	icmd.RunCommand("mount", "--bind", tmpDir, tmpDir).Assert(c, icmd.Success)
3833	icmd.RunCommand("mount", "--make-private", "--make-shared", tmpDir).Assert(c, icmd.Success)
3834
3835	dockerCmd(c, "run", "-i", "-d", "--name", "parent", "-v", fmt.Sprintf("%s:/volume-dest:slave", tmpDir), "busybox", "top")
3836
3837	// Bind mount tmpDir2/ onto tmpDir/mnt1. If mount propagates inside
3838	// container then contents of tmpDir2/slave-testfile should become
3839	// visible at "/volume-dest/mnt1/slave-testfile"
3840	icmd.RunCommand("mount", "--bind", tmpDir2, path.Join(tmpDir, "mnt1")).Assert(c, icmd.Success)
3841
3842	out, _ := dockerCmd(c, "exec", "parent", "cat", "/volume-dest/mnt1/slave-testfile")
3843
3844	mount.Unmount(path.Join(tmpDir, "mnt1"))
3845
3846	if out != "Test" {
3847		c.Fatalf("Bind mount under slave volume did not propagate to container")
3848	}
3849}
3850
3851func (s *DockerSuite) TestRunNamedVolumesMountedAsShared(c *check.C) {
3852	testRequires(c, DaemonIsLinux, NotUserNamespace)
3853	out, exitCode, _ := dockerCmdWithError("run", "-v", "foo:/test:shared", "busybox", "touch", "/test/somefile")
3854	c.Assert(exitCode, checker.Not(checker.Equals), 0)
3855	c.Assert(out, checker.Contains, "invalid mount config")
3856}
3857
3858func (s *DockerSuite) TestRunNamedVolumeCopyImageData(c *check.C) {
3859	testRequires(c, DaemonIsLinux)
3860
3861	testImg := "testvolumecopy"
3862	buildImageSuccessfully(c, testImg, build.WithDockerfile(`
3863	FROM busybox
3864	RUN mkdir -p /foo && echo hello > /foo/hello
3865	`))
3866
3867	dockerCmd(c, "run", "-v", "foo:/foo", testImg)
3868	out, _ := dockerCmd(c, "run", "-v", "foo:/foo", "busybox", "cat", "/foo/hello")
3869	c.Assert(strings.TrimSpace(out), check.Equals, "hello")
3870}
3871
3872func (s *DockerSuite) TestRunNamedVolumeNotRemoved(c *check.C) {
3873	prefix, _ := getPrefixAndSlashFromDaemonPlatform()
3874
3875	dockerCmd(c, "volume", "create", "test")
3876
3877	dockerCmd(c, "run", "--rm", "-v", "test:"+prefix+"/foo", "-v", prefix+"/bar", "busybox", "true")
3878	dockerCmd(c, "volume", "inspect", "test")
3879	out, _ := dockerCmd(c, "volume", "ls", "-q")
3880	c.Assert(strings.TrimSpace(out), checker.Contains, "test")
3881
3882	dockerCmd(c, "run", "--name=test", "-v", "test:"+prefix+"/foo", "-v", prefix+"/bar", "busybox", "true")
3883	dockerCmd(c, "rm", "-fv", "test")
3884	dockerCmd(c, "volume", "inspect", "test")
3885	out, _ = dockerCmd(c, "volume", "ls", "-q")
3886	c.Assert(strings.TrimSpace(out), checker.Contains, "test")
3887}
3888
3889func (s *DockerSuite) TestRunNamedVolumesFromNotRemoved(c *check.C) {
3890	prefix, _ := getPrefixAndSlashFromDaemonPlatform()
3891
3892	dockerCmd(c, "volume", "create", "test")
3893	cid, _ := dockerCmd(c, "run", "-d", "--name=parent", "-v", "test:"+prefix+"/foo", "-v", prefix+"/bar", "busybox", "true")
3894	dockerCmd(c, "run", "--name=child", "--volumes-from=parent", "busybox", "true")
3895
3896	cli, err := client.NewEnvClient()
3897	c.Assert(err, checker.IsNil)
3898	defer cli.Close()
3899
3900	container, err := cli.ContainerInspect(context.Background(), strings.TrimSpace(cid))
3901	c.Assert(err, checker.IsNil)
3902	var vname string
3903	for _, v := range container.Mounts {
3904		if v.Name != "test" {
3905			vname = v.Name
3906		}
3907	}
3908	c.Assert(vname, checker.Not(checker.Equals), "")
3909
3910	// Remove the parent so there are not other references to the volumes
3911	dockerCmd(c, "rm", "-f", "parent")
3912	// now remove the child and ensure the named volume (and only the named volume) still exists
3913	dockerCmd(c, "rm", "-fv", "child")
3914	dockerCmd(c, "volume", "inspect", "test")
3915	out, _ := dockerCmd(c, "volume", "ls", "-q")
3916	c.Assert(strings.TrimSpace(out), checker.Contains, "test")
3917	c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), vname)
3918}
3919
3920func (s *DockerSuite) TestRunAttachFailedNoLeak(c *check.C) {
3921	// TODO @msabansal - https://github.com/moby/moby/issues/35023. Duplicate
3922	// port mappings are not errored out on RS3 builds. Temporarily disabling
3923	// this test pending further investigation. Note we parse kernel.GetKernelVersion
3924	// rather than system.GetOSVersion as test binaries aren't manifested, so would
3925	// otherwise report build 9200.
3926	if runtime.GOOS == "windows" {
3927		v, err := kernel.GetKernelVersion()
3928		c.Assert(err, checker.IsNil)
3929		build, _ := strconv.Atoi(strings.Split(strings.SplitN(v.String(), " ", 3)[2][1:], ".")[0])
3930		if build == 16299 {
3931			c.Skip("Temporarily disabled on RS3 builds")
3932		}
3933	}
3934
3935	nroutines, err := getGoroutineNumber()
3936	c.Assert(err, checker.IsNil)
3937
3938	runSleepingContainer(c, "--name=test", "-p", "8000:8000")
3939
3940	// Wait until container is fully up and running
3941	c.Assert(waitRun("test"), check.IsNil)
3942
3943	out, _, err := dockerCmdWithError("run", "--name=fail", "-p", "8000:8000", "busybox", "true")
3944	// We will need the following `inspect` to diagnose the issue if test fails (#21247)
3945	out1, err1 := dockerCmd(c, "inspect", "--format", "{{json .State}}", "test")
3946	out2, err2 := dockerCmd(c, "inspect", "--format", "{{json .State}}", "fail")
3947	c.Assert(err, checker.NotNil, check.Commentf("Command should have failed but succeeded with: %s\nContainer 'test' [%+v]: %s\nContainer 'fail' [%+v]: %s", out, err1, out1, err2, out2))
3948	// check for windows error as well
3949	// TODO Windows Post TP5. Fix the error message string
3950	c.Assert(strings.Contains(string(out), "port is already allocated") ||
3951		strings.Contains(string(out), "were not connected because a duplicate name exists") ||
3952		strings.Contains(string(out), "The specified port already exists") ||
3953		strings.Contains(string(out), "HNS failed with error : Failed to create endpoint") ||
3954		strings.Contains(string(out), "HNS failed with error : The object already exists"), checker.Equals, true, check.Commentf("Output: %s", out))
3955	dockerCmd(c, "rm", "-f", "test")
3956
3957	// NGoroutines is not updated right away, so we need to wait before failing
3958	c.Assert(waitForGoroutines(nroutines), checker.IsNil)
3959}
3960
3961// Test for one character directory name case (#20122)
3962func (s *DockerSuite) TestRunVolumeWithOneCharacter(c *check.C) {
3963	testRequires(c, DaemonIsLinux)
3964
3965	out, _ := dockerCmd(c, "run", "-v", "/tmp/q:/foo", "busybox", "sh", "-c", "find /foo")
3966	c.Assert(strings.TrimSpace(out), checker.Equals, "/foo")
3967}
3968
3969func (s *DockerSuite) TestRunVolumeCopyFlag(c *check.C) {
3970	testRequires(c, DaemonIsLinux) // Windows does not support copying data from image to the volume
3971	buildImageSuccessfully(c, "volumecopy", build.WithDockerfile(`FROM busybox
3972		RUN mkdir /foo && echo hello > /foo/bar
3973		CMD cat /foo/bar`))
3974	dockerCmd(c, "volume", "create", "test")
3975
3976	// test with the nocopy flag
3977	out, _, err := dockerCmdWithError("run", "-v", "test:/foo:nocopy", "volumecopy")
3978	c.Assert(err, checker.NotNil, check.Commentf("%s", out))
3979	// test default behavior which is to copy for non-binds
3980	out, _ = dockerCmd(c, "run", "-v", "test:/foo", "volumecopy")
3981	c.Assert(strings.TrimSpace(out), checker.Equals, "hello")
3982	// error out when the volume is already populated
3983	out, _, err = dockerCmdWithError("run", "-v", "test:/foo:copy", "volumecopy")
3984	c.Assert(err, checker.NotNil, check.Commentf("%s", out))
3985	// do not error out when copy isn't explicitly set even though it's already populated
3986	out, _ = dockerCmd(c, "run", "-v", "test:/foo", "volumecopy")
3987	c.Assert(strings.TrimSpace(out), checker.Equals, "hello")
3988
3989	// do not allow copy modes on volumes-from
3990	dockerCmd(c, "run", "--name=test", "-v", "/foo", "busybox", "true")
3991	out, _, err = dockerCmdWithError("run", "--volumes-from=test:copy", "busybox", "true")
3992	c.Assert(err, checker.NotNil, check.Commentf("%s", out))
3993	out, _, err = dockerCmdWithError("run", "--volumes-from=test:nocopy", "busybox", "true")
3994	c.Assert(err, checker.NotNil, check.Commentf("%s", out))
3995
3996	// do not allow copy modes on binds
3997	out, _, err = dockerCmdWithError("run", "-v", "/foo:/bar:copy", "busybox", "true")
3998	c.Assert(err, checker.NotNil, check.Commentf("%s", out))
3999	out, _, err = dockerCmdWithError("run", "-v", "/foo:/bar:nocopy", "busybox", "true")
4000	c.Assert(err, checker.NotNil, check.Commentf("%s", out))
4001}
4002
4003// Test case for #21976
4004func (s *DockerSuite) TestRunDNSInHostMode(c *check.C) {
4005	testRequires(c, DaemonIsLinux, NotUserNamespace)
4006
4007	expectedOutput := "nameserver 127.0.0.1"
4008	expectedWarning := "Localhost DNS setting"
4009	cli.DockerCmd(c, "run", "--dns=127.0.0.1", "--net=host", "busybox", "cat", "/etc/resolv.conf").Assert(c, icmd.Expected{
4010		Out: expectedOutput,
4011		Err: expectedWarning,
4012	})
4013
4014	expectedOutput = "nameserver 1.2.3.4"
4015	cli.DockerCmd(c, "run", "--dns=1.2.3.4", "--net=host", "busybox", "cat", "/etc/resolv.conf").Assert(c, icmd.Expected{
4016		Out: expectedOutput,
4017	})
4018
4019	expectedOutput = "search example.com"
4020	cli.DockerCmd(c, "run", "--dns-search=example.com", "--net=host", "busybox", "cat", "/etc/resolv.conf").Assert(c, icmd.Expected{
4021		Out: expectedOutput,
4022	})
4023
4024	expectedOutput = "options timeout:3"
4025	cli.DockerCmd(c, "run", "--dns-opt=timeout:3", "--net=host", "busybox", "cat", "/etc/resolv.conf").Assert(c, icmd.Expected{
4026		Out: expectedOutput,
4027	})
4028
4029	expectedOutput1 := "nameserver 1.2.3.4"
4030	expectedOutput2 := "search example.com"
4031	expectedOutput3 := "options timeout:3"
4032	out := cli.DockerCmd(c, "run", "--dns=1.2.3.4", "--dns-search=example.com", "--dns-opt=timeout:3", "--net=host", "busybox", "cat", "/etc/resolv.conf").Combined()
4033	c.Assert(out, checker.Contains, expectedOutput1, check.Commentf("Expected '%s', but got %q", expectedOutput1, out))
4034	c.Assert(out, checker.Contains, expectedOutput2, check.Commentf("Expected '%s', but got %q", expectedOutput2, out))
4035	c.Assert(out, checker.Contains, expectedOutput3, check.Commentf("Expected '%s', but got %q", expectedOutput3, out))
4036}
4037
4038// Test case for #21976
4039func (s *DockerSuite) TestRunAddHostInHostMode(c *check.C) {
4040	testRequires(c, DaemonIsLinux, NotUserNamespace)
4041
4042	expectedOutput := "1.2.3.4\textra"
4043	out, _ := dockerCmd(c, "run", "--add-host=extra:1.2.3.4", "--net=host", "busybox", "cat", "/etc/hosts")
4044	c.Assert(out, checker.Contains, expectedOutput, check.Commentf("Expected '%s', but got %q", expectedOutput, out))
4045}
4046
4047func (s *DockerSuite) TestRunRmAndWait(c *check.C) {
4048	dockerCmd(c, "run", "--name=test", "--rm", "-d", "busybox", "sh", "-c", "sleep 3;exit 2")
4049
4050	out, code, err := dockerCmdWithError("wait", "test")
4051	c.Assert(err, checker.IsNil, check.Commentf("out: %s; exit code: %d", out, code))
4052	c.Assert(out, checker.Equals, "2\n", check.Commentf("exit code: %d", code))
4053	c.Assert(code, checker.Equals, 0)
4054}
4055
4056// Test that auto-remove is performed by the daemon (API 1.25 and above)
4057func (s *DockerSuite) TestRunRm(c *check.C) {
4058	name := "miss-me-when-im-gone"
4059	cli.DockerCmd(c, "run", "--name="+name, "--rm", "busybox")
4060
4061	cli.Docker(cli.Inspect(name), cli.Format(".name")).Assert(c, icmd.Expected{
4062		ExitCode: 1,
4063		Err:      "No such object: " + name,
4064	})
4065}
4066
4067// Test that auto-remove is performed by the client on API versions that do not support daemon-side api-remove (API < 1.25)
4068func (s *DockerSuite) TestRunRmPre125Api(c *check.C) {
4069	name := "miss-me-when-im-gone"
4070	envs := appendBaseEnv(os.Getenv("DOCKER_TLS_VERIFY") != "", "DOCKER_API_VERSION=1.24")
4071	cli.Docker(cli.Args("run", "--name="+name, "--rm", "busybox"), cli.WithEnvironmentVariables(envs...)).Assert(c, icmd.Success)
4072
4073	cli.Docker(cli.Inspect(name), cli.Format(".name")).Assert(c, icmd.Expected{
4074		ExitCode: 1,
4075		Err:      "No such object: " + name,
4076	})
4077}
4078
4079// Test case for #23498
4080func (s *DockerSuite) TestRunUnsetEntrypoint(c *check.C) {
4081	testRequires(c, DaemonIsLinux)
4082	name := "test-entrypoint"
4083	dockerfile := `FROM busybox
4084ADD entrypoint.sh /entrypoint.sh
4085RUN chmod 755 /entrypoint.sh
4086ENTRYPOINT ["/entrypoint.sh"]
4087CMD echo foobar`
4088
4089	ctx := fakecontext.New(c, "",
4090		fakecontext.WithDockerfile(dockerfile),
4091		fakecontext.WithFiles(map[string]string{
4092			"entrypoint.sh": `#!/bin/sh
4093echo "I am an entrypoint"
4094exec "$@"`,
4095		}))
4096	defer ctx.Close()
4097
4098	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
4099
4100	out := cli.DockerCmd(c, "run", "--entrypoint=", "-t", name, "echo", "foo").Combined()
4101	c.Assert(strings.TrimSpace(out), check.Equals, "foo")
4102
4103	// CMD will be reset as well (the same as setting a custom entrypoint)
4104	cli.Docker(cli.Args("run", "--entrypoint=", "-t", name)).Assert(c, icmd.Expected{
4105		ExitCode: 125,
4106		Err:      "No command specified",
4107	})
4108}
4109
4110func (s *DockerDaemonSuite) TestRunWithUlimitAndDaemonDefault(c *check.C) {
4111	s.d.StartWithBusybox(c, "--debug", "--default-ulimit=nofile=65535")
4112
4113	name := "test-A"
4114	_, err := s.d.Cmd("run", "--name", name, "-d", "busybox", "top")
4115	c.Assert(err, checker.IsNil)
4116	c.Assert(s.d.WaitRun(name), check.IsNil)
4117
4118	out, err := s.d.Cmd("inspect", "--format", "{{.HostConfig.Ulimits}}", name)
4119	c.Assert(err, checker.IsNil)
4120	c.Assert(out, checker.Contains, "[nofile=65535:65535]")
4121
4122	name = "test-B"
4123	_, err = s.d.Cmd("run", "--name", name, "--ulimit=nofile=42", "-d", "busybox", "top")
4124	c.Assert(err, checker.IsNil)
4125	c.Assert(s.d.WaitRun(name), check.IsNil)
4126
4127	out, err = s.d.Cmd("inspect", "--format", "{{.HostConfig.Ulimits}}", name)
4128	c.Assert(err, checker.IsNil)
4129	c.Assert(out, checker.Contains, "[nofile=42:42]")
4130}
4131
4132func (s *DockerSuite) TestRunStoppedLoggingDriverNoLeak(c *check.C) {
4133	nroutines, err := getGoroutineNumber()
4134	c.Assert(err, checker.IsNil)
4135
4136	out, _, err := dockerCmdWithError("run", "--name=fail", "--log-driver=splunk", "busybox", "true")
4137	c.Assert(err, checker.NotNil)
4138	c.Assert(out, checker.Contains, "failed to initialize logging driver", check.Commentf("error should be about logging driver, got output %s", out))
4139
4140	// NGoroutines is not updated right away, so we need to wait before failing
4141	c.Assert(waitForGoroutines(nroutines), checker.IsNil)
4142}
4143
4144// Handles error conditions for --credentialspec. Validating E2E success cases
4145// requires additional infrastructure (AD for example) on CI servers.
4146func (s *DockerSuite) TestRunCredentialSpecFailures(c *check.C) {
4147	testRequires(c, DaemonIsWindows)
4148	attempts := []struct{ value, expectedError string }{
4149		{"rubbish", "invalid credential spec security option - value must be prefixed file:// or registry://"},
4150		{"rubbish://", "invalid credential spec security option - value must be prefixed file:// or registry://"},
4151		{"file://", "no value supplied for file:// credential spec security option"},
4152		{"registry://", "no value supplied for registry:// credential spec security option"},
4153		{`file://c:\blah.txt`, "path cannot be absolute"},
4154		{`file://doesnotexist.txt`, "The system cannot find the file specified"},
4155	}
4156	for _, attempt := range attempts {
4157		_, _, err := dockerCmdWithError("run", "--security-opt=credentialspec="+attempt.value, "busybox", "true")
4158		c.Assert(err, checker.NotNil, check.Commentf("%s expected non-nil err", attempt.value))
4159		c.Assert(err.Error(), checker.Contains, attempt.expectedError, check.Commentf("%s expected %s got %s", attempt.value, attempt.expectedError, err))
4160	}
4161}
4162
4163// Windows specific test to validate credential specs with a well-formed spec.
4164// Note it won't actually do anything in CI configuration with the spec, but
4165// it should not fail to run a container.
4166func (s *DockerSuite) TestRunCredentialSpecWellFormed(c *check.C) {
4167	testRequires(c, DaemonIsWindows, SameHostDaemon)
4168	validCS := readFile(`fixtures\credentialspecs\valid.json`, c)
4169	writeFile(filepath.Join(testEnv.DaemonInfo.DockerRootDir, `credentialspecs\valid.json`), validCS, c)
4170	dockerCmd(c, "run", `--security-opt=credentialspec=file://valid.json`, "busybox", "true")
4171}
4172
4173func (s *DockerSuite) TestRunDuplicateMount(c *check.C) {
4174	testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace)
4175
4176	tmpFile, err := ioutil.TempFile("", "touch-me")
4177	c.Assert(err, checker.IsNil)
4178	defer tmpFile.Close()
4179
4180	data := "touch-me-foo-bar\n"
4181	if _, err := tmpFile.Write([]byte(data)); err != nil {
4182		c.Fatal(err)
4183	}
4184
4185	name := "test"
4186	out, _ := dockerCmd(c, "run", "--name", name, "-v", "/tmp:/tmp", "-v", "/tmp:/tmp", "busybox", "sh", "-c", "cat "+tmpFile.Name()+" && ls /")
4187	c.Assert(out, checker.Not(checker.Contains), "tmp:")
4188	c.Assert(out, checker.Contains, data)
4189
4190	out = inspectFieldJSON(c, name, "Config.Volumes")
4191	c.Assert(out, checker.Contains, "null")
4192}
4193
4194func (s *DockerSuite) TestRunWindowsWithCPUCount(c *check.C) {
4195	testRequires(c, DaemonIsWindows)
4196
4197	out, _ := dockerCmd(c, "run", "--cpu-count=1", "--name", "test", "busybox", "echo", "testing")
4198	c.Assert(strings.TrimSpace(out), checker.Equals, "testing")
4199
4200	out = inspectField(c, "test", "HostConfig.CPUCount")
4201	c.Assert(out, check.Equals, "1")
4202}
4203
4204func (s *DockerSuite) TestRunWindowsWithCPUShares(c *check.C) {
4205	testRequires(c, DaemonIsWindows)
4206
4207	out, _ := dockerCmd(c, "run", "--cpu-shares=1000", "--name", "test", "busybox", "echo", "testing")
4208	c.Assert(strings.TrimSpace(out), checker.Equals, "testing")
4209
4210	out = inspectField(c, "test", "HostConfig.CPUShares")
4211	c.Assert(out, check.Equals, "1000")
4212}
4213
4214func (s *DockerSuite) TestRunWindowsWithCPUPercent(c *check.C) {
4215	testRequires(c, DaemonIsWindows)
4216
4217	out, _ := dockerCmd(c, "run", "--cpu-percent=80", "--name", "test", "busybox", "echo", "testing")
4218	c.Assert(strings.TrimSpace(out), checker.Equals, "testing")
4219
4220	out = inspectField(c, "test", "HostConfig.CPUPercent")
4221	c.Assert(out, check.Equals, "80")
4222}
4223
4224func (s *DockerSuite) TestRunProcessIsolationWithCPUCountCPUSharesAndCPUPercent(c *check.C) {
4225	testRequires(c, DaemonIsWindows, IsolationIsProcess)
4226
4227	out, _ := dockerCmd(c, "run", "--cpu-count=1", "--cpu-shares=1000", "--cpu-percent=80", "--name", "test", "busybox", "echo", "testing")
4228	c.Assert(strings.TrimSpace(out), checker.Contains, "WARNING: Conflicting options: CPU count takes priority over CPU shares on Windows Server Containers. CPU shares discarded")
4229	c.Assert(strings.TrimSpace(out), checker.Contains, "WARNING: Conflicting options: CPU count takes priority over CPU percent on Windows Server Containers. CPU percent discarded")
4230	c.Assert(strings.TrimSpace(out), checker.Contains, "testing")
4231
4232	out = inspectField(c, "test", "HostConfig.CPUCount")
4233	c.Assert(out, check.Equals, "1")
4234
4235	out = inspectField(c, "test", "HostConfig.CPUShares")
4236	c.Assert(out, check.Equals, "0")
4237
4238	out = inspectField(c, "test", "HostConfig.CPUPercent")
4239	c.Assert(out, check.Equals, "0")
4240}
4241
4242func (s *DockerSuite) TestRunHypervIsolationWithCPUCountCPUSharesAndCPUPercent(c *check.C) {
4243	testRequires(c, DaemonIsWindows, IsolationIsHyperv)
4244
4245	out, _ := dockerCmd(c, "run", "--cpu-count=1", "--cpu-shares=1000", "--cpu-percent=80", "--name", "test", "busybox", "echo", "testing")
4246	c.Assert(strings.TrimSpace(out), checker.Contains, "testing")
4247
4248	out = inspectField(c, "test", "HostConfig.CPUCount")
4249	c.Assert(out, check.Equals, "1")
4250
4251	out = inspectField(c, "test", "HostConfig.CPUShares")
4252	c.Assert(out, check.Equals, "1000")
4253
4254	out = inspectField(c, "test", "HostConfig.CPUPercent")
4255	c.Assert(out, check.Equals, "80")
4256}
4257
4258// Test for #25099
4259func (s *DockerSuite) TestRunEmptyEnv(c *check.C) {
4260	testRequires(c, DaemonIsLinux)
4261
4262	expectedOutput := "invalid environment variable:"
4263
4264	out, _, err := dockerCmdWithError("run", "-e", "", "busybox", "true")
4265	c.Assert(err, checker.NotNil)
4266	c.Assert(out, checker.Contains, expectedOutput)
4267
4268	out, _, err = dockerCmdWithError("run", "-e", "=", "busybox", "true")
4269	c.Assert(err, checker.NotNil)
4270	c.Assert(out, checker.Contains, expectedOutput)
4271
4272	out, _, err = dockerCmdWithError("run", "-e", "=foo", "busybox", "true")
4273	c.Assert(err, checker.NotNil)
4274	c.Assert(out, checker.Contains, expectedOutput)
4275}
4276
4277// #28658
4278func (s *DockerSuite) TestSlowStdinClosing(c *check.C) {
4279	name := "testslowstdinclosing"
4280	repeat := 3 // regression happened 50% of the time
4281	for i := 0; i < repeat; i++ {
4282		cmd := icmd.Cmd{
4283			Command: []string{dockerBinary, "run", "--rm", "--name", name, "-i", "busybox", "cat"},
4284			Stdin:   &delayedReader{},
4285		}
4286		done := make(chan error, 1)
4287		go func() {
4288			err := icmd.RunCmd(cmd).Error
4289			done <- err
4290		}()
4291
4292		select {
4293		case <-time.After(30 * time.Second):
4294			c.Fatal("running container timed out") // cleanup in teardown
4295		case err := <-done:
4296			c.Assert(err, checker.IsNil)
4297		}
4298	}
4299}
4300
4301type delayedReader struct{}
4302
4303func (s *delayedReader) Read([]byte) (int, error) {
4304	time.Sleep(500 * time.Millisecond)
4305	return 0, io.EOF
4306}
4307
4308// #28823 (originally #28639)
4309func (s *DockerSuite) TestRunMountReadOnlyDevShm(c *check.C) {
4310	testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace)
4311	emptyDir, err := ioutil.TempDir("", "test-read-only-dev-shm")
4312	c.Assert(err, check.IsNil)
4313	defer os.RemoveAll(emptyDir)
4314	out, _, err := dockerCmdWithError("run", "--rm", "--read-only",
4315		"-v", fmt.Sprintf("%s:/dev/shm:ro", emptyDir),
4316		"busybox", "touch", "/dev/shm/foo")
4317	c.Assert(err, checker.NotNil, check.Commentf("%s", out))
4318	c.Assert(out, checker.Contains, "Read-only file system")
4319}
4320
4321func (s *DockerSuite) TestRunMount(c *check.C) {
4322	testRequires(c, DaemonIsLinux, SameHostDaemon, NotUserNamespace)
4323
4324	// mnt1, mnt2, and testCatFooBar are commonly used in multiple test cases
4325	tmpDir, err := ioutil.TempDir("", "mount")
4326	if err != nil {
4327		c.Fatal(err)
4328	}
4329	defer os.RemoveAll(tmpDir)
4330	mnt1, mnt2 := path.Join(tmpDir, "mnt1"), path.Join(tmpDir, "mnt2")
4331	if err := os.Mkdir(mnt1, 0755); err != nil {
4332		c.Fatal(err)
4333	}
4334	if err := os.Mkdir(mnt2, 0755); err != nil {
4335		c.Fatal(err)
4336	}
4337	if err := ioutil.WriteFile(path.Join(mnt1, "test1"), []byte("test1"), 0644); err != nil {
4338		c.Fatal(err)
4339	}
4340	if err := ioutil.WriteFile(path.Join(mnt2, "test2"), []byte("test2"), 0644); err != nil {
4341		c.Fatal(err)
4342	}
4343	testCatFooBar := func(cName string) error {
4344		out, _ := dockerCmd(c, "exec", cName, "cat", "/foo/test1")
4345		if out != "test1" {
4346			return fmt.Errorf("%s not mounted on /foo", mnt1)
4347		}
4348		out, _ = dockerCmd(c, "exec", cName, "cat", "/bar/test2")
4349		if out != "test2" {
4350			return fmt.Errorf("%s not mounted on /bar", mnt2)
4351		}
4352		return nil
4353	}
4354
4355	type testCase struct {
4356		equivalents [][]string
4357		valid       bool
4358		// fn should be nil if valid==false
4359		fn func(cName string) error
4360	}
4361	cases := []testCase{
4362		{
4363			equivalents: [][]string{
4364				{
4365					"--mount", fmt.Sprintf("type=bind,src=%s,dst=/foo", mnt1),
4366					"--mount", fmt.Sprintf("type=bind,src=%s,dst=/bar", mnt2),
4367				},
4368				{
4369					"--mount", fmt.Sprintf("type=bind,src=%s,dst=/foo", mnt1),
4370					"--mount", fmt.Sprintf("type=bind,src=%s,target=/bar", mnt2),
4371				},
4372				{
4373					"--volume", mnt1 + ":/foo",
4374					"--mount", fmt.Sprintf("type=bind,src=%s,target=/bar", mnt2),
4375				},
4376			},
4377			valid: true,
4378			fn:    testCatFooBar,
4379		},
4380		{
4381			equivalents: [][]string{
4382				{
4383					"--mount", fmt.Sprintf("type=volume,src=%s,dst=/foo", mnt1),
4384					"--mount", fmt.Sprintf("type=volume,src=%s,dst=/bar", mnt2),
4385				},
4386				{
4387					"--mount", fmt.Sprintf("type=volume,src=%s,dst=/foo", mnt1),
4388					"--mount", fmt.Sprintf("type=volume,src=%s,target=/bar", mnt2),
4389				},
4390			},
4391			valid: false,
4392		},
4393		{
4394			equivalents: [][]string{
4395				{
4396					"--mount", fmt.Sprintf("type=bind,src=%s,dst=/foo", mnt1),
4397					"--mount", fmt.Sprintf("type=volume,src=%s,dst=/bar", mnt2),
4398				},
4399				{
4400					"--volume", mnt1 + ":/foo",
4401					"--mount", fmt.Sprintf("type=volume,src=%s,target=/bar", mnt2),
4402				},
4403			},
4404			valid: false,
4405			fn:    testCatFooBar,
4406		},
4407		{
4408			equivalents: [][]string{
4409				{
4410					"--read-only",
4411					"--mount", "type=volume,dst=/bar",
4412				},
4413			},
4414			valid: true,
4415			fn: func(cName string) error {
4416				_, _, err := dockerCmdWithError("exec", cName, "touch", "/bar/icanwritehere")
4417				return err
4418			},
4419		},
4420		{
4421			equivalents: [][]string{
4422				{
4423					"--read-only",
4424					"--mount", fmt.Sprintf("type=bind,src=%s,dst=/foo", mnt1),
4425					"--mount", "type=volume,dst=/bar",
4426				},
4427				{
4428					"--read-only",
4429					"--volume", fmt.Sprintf("%s:/foo", mnt1),
4430					"--mount", "type=volume,dst=/bar",
4431				},
4432			},
4433			valid: true,
4434			fn: func(cName string) error {
4435				out, _ := dockerCmd(c, "exec", cName, "cat", "/foo/test1")
4436				if out != "test1" {
4437					return fmt.Errorf("%s not mounted on /foo", mnt1)
4438				}
4439				_, _, err := dockerCmdWithError("exec", cName, "touch", "/bar/icanwritehere")
4440				return err
4441			},
4442		},
4443		{
4444			equivalents: [][]string{
4445				{
4446					"--mount", fmt.Sprintf("type=bind,src=%s,dst=/foo", mnt1),
4447					"--mount", fmt.Sprintf("type=bind,src=%s,dst=/foo", mnt2),
4448				},
4449				{
4450					"--mount", fmt.Sprintf("type=bind,src=%s,dst=/foo", mnt1),
4451					"--mount", fmt.Sprintf("type=bind,src=%s,target=/foo", mnt2),
4452				},
4453				{
4454					"--volume", fmt.Sprintf("%s:/foo", mnt1),
4455					"--mount", fmt.Sprintf("type=bind,src=%s,target=/foo", mnt2),
4456				},
4457			},
4458			valid: false,
4459		},
4460		{
4461			equivalents: [][]string{
4462				{
4463					"--volume", fmt.Sprintf("%s:/foo", mnt1),
4464					"--mount", fmt.Sprintf("type=volume,src=%s,target=/foo", mnt2),
4465				},
4466			},
4467			valid: false,
4468		},
4469		{
4470			equivalents: [][]string{
4471				{
4472					"--mount", "type=volume,target=/foo",
4473					"--mount", "type=volume,target=/foo",
4474				},
4475			},
4476			valid: false,
4477		},
4478	}
4479
4480	for i, testCase := range cases {
4481		for j, opts := range testCase.equivalents {
4482			cName := fmt.Sprintf("mount-%d-%d", i, j)
4483			_, _, err := dockerCmdWithError(append([]string{"run", "-i", "-d", "--name", cName},
4484				append(opts, []string{"busybox", "top"}...)...)...)
4485			if testCase.valid {
4486				c.Assert(err, check.IsNil,
4487					check.Commentf("got error while creating a container with %v (%s)", opts, cName))
4488				c.Assert(testCase.fn(cName), check.IsNil,
4489					check.Commentf("got error while executing test for %v (%s)", opts, cName))
4490				dockerCmd(c, "rm", "-f", cName)
4491			} else {
4492				c.Assert(err, checker.NotNil,
4493					check.Commentf("got nil while creating a container with %v (%s)", opts, cName))
4494			}
4495		}
4496	}
4497}
4498
4499// Test that passing a FQDN as hostname properly sets hostname, and
4500// /etc/hostname. Test case for 29100
4501func (s *DockerSuite) TestRunHostnameFQDN(c *check.C) {
4502	testRequires(c, DaemonIsLinux)
4503
4504	expectedOutput := "foobar.example.com\nfoobar.example.com\nfoobar\nexample.com\nfoobar.example.com"
4505	out, _ := dockerCmd(c, "run", "--hostname=foobar.example.com", "busybox", "sh", "-c", `cat /etc/hostname && hostname && hostname -s && hostname -d && hostname -f`)
4506	c.Assert(strings.TrimSpace(out), checker.Equals, expectedOutput)
4507
4508	out, _ = dockerCmd(c, "run", "--hostname=foobar.example.com", "busybox", "sh", "-c", `cat /etc/hosts`)
4509	expectedOutput = "foobar.example.com foobar"
4510	c.Assert(strings.TrimSpace(out), checker.Contains, expectedOutput)
4511}
4512
4513// Test case for 29129
4514func (s *DockerSuite) TestRunHostnameInHostMode(c *check.C) {
4515	testRequires(c, DaemonIsLinux, NotUserNamespace)
4516
4517	expectedOutput := "foobar\nfoobar"
4518	out, _ := dockerCmd(c, "run", "--net=host", "--hostname=foobar", "busybox", "sh", "-c", `echo $HOSTNAME && hostname`)
4519	c.Assert(strings.TrimSpace(out), checker.Equals, expectedOutput)
4520}
4521
4522func (s *DockerSuite) TestRunAddDeviceCgroupRule(c *check.C) {
4523	testRequires(c, DaemonIsLinux)
4524
4525	deviceRule := "c 7:128 rwm"
4526
4527	out, _ := dockerCmd(c, "run", "--rm", "busybox", "cat", "/sys/fs/cgroup/devices/devices.list")
4528	if strings.Contains(out, deviceRule) {
4529		c.Fatalf("%s shouldn't been in the device.list", deviceRule)
4530	}
4531
4532	out, _ = dockerCmd(c, "run", "--rm", fmt.Sprintf("--device-cgroup-rule=%s", deviceRule), "busybox", "grep", deviceRule, "/sys/fs/cgroup/devices/devices.list")
4533	c.Assert(strings.TrimSpace(out), checker.Equals, deviceRule)
4534}
4535
4536// Verifies that running as local system is operating correctly on Windows
4537func (s *DockerSuite) TestWindowsRunAsSystem(c *check.C) {
4538	testRequires(c, DaemonIsWindowsAtLeastBuild(15000))
4539	out, _ := dockerCmd(c, "run", "--net=none", `--user=nt authority\system`, "--hostname=XYZZY", minimalBaseImage(), "cmd", "/c", `@echo %USERNAME%`)
4540	c.Assert(strings.TrimSpace(out), checker.Equals, "XYZZY$")
4541}
4542