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