docker_cli_run_test.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "os/exec"
  6. "regexp"
  7. "sort"
  8. "strings"
  9. "sync"
  10. "testing"
  11. )
  12. // "test123" should be printed by docker run
  13. func TestDockerRunEchoStdout(t *testing.T) {
  14. runCmd := exec.Command(dockerBinary, "run", "busybox", "echo", "test123")
  15. out, _, _, err := runCommandWithStdoutStderr(runCmd)
  16. errorOut(err, t, out)
  17. if out != "test123\n" {
  18. t.Errorf("container should've printed 'test123'")
  19. }
  20. deleteAllContainers()
  21. logDone("run - echo test123")
  22. }
  23. // "test" should be printed
  24. func TestDockerRunEchoStdoutWithMemoryLimit(t *testing.T) {
  25. runCmd := exec.Command(dockerBinary, "run", "-m", "2786432", "busybox", "echo", "test")
  26. out, _, _, err := runCommandWithStdoutStderr(runCmd)
  27. errorOut(err, t, out)
  28. if out != "test\n" {
  29. t.Errorf("container should've printed 'test'")
  30. }
  31. deleteAllContainers()
  32. logDone("run - echo with memory limit")
  33. }
  34. // "test" should be printed
  35. func TestDockerRunEchoStdoutWitCPULimit(t *testing.T) {
  36. runCmd := exec.Command(dockerBinary, "run", "-c", "1000", "busybox", "echo", "test")
  37. out, _, _, err := runCommandWithStdoutStderr(runCmd)
  38. errorOut(err, t, out)
  39. if out != "test\n" {
  40. t.Errorf("container should've printed 'test'")
  41. }
  42. deleteAllContainers()
  43. logDone("run - echo with CPU limit")
  44. }
  45. // "test" should be printed
  46. func TestDockerRunEchoStdoutWithCPUAndMemoryLimit(t *testing.T) {
  47. runCmd := exec.Command(dockerBinary, "run", "-c", "1000", "-m", "2786432", "busybox", "echo", "test")
  48. out, _, _, err := runCommandWithStdoutStderr(runCmd)
  49. errorOut(err, t, out)
  50. if out != "test\n" {
  51. t.Errorf("container should've printed 'test'")
  52. }
  53. deleteAllContainers()
  54. logDone("run - echo with CPU and memory limit")
  55. }
  56. // "test" should be printed
  57. func TestDockerRunEchoNamedContainer(t *testing.T) {
  58. runCmd := exec.Command(dockerBinary, "run", "--name", "testfoonamedcontainer", "busybox", "echo", "test")
  59. out, _, _, err := runCommandWithStdoutStderr(runCmd)
  60. errorOut(err, t, out)
  61. if out != "test\n" {
  62. t.Errorf("container should've printed 'test'")
  63. }
  64. if err := deleteContainer("testfoonamedcontainer"); err != nil {
  65. t.Errorf("failed to remove the named container: %v", err)
  66. }
  67. deleteAllContainers()
  68. logDone("run - echo with named container")
  69. }
  70. // it should be possible to ping Google DNS resolver
  71. // this will fail when Internet access is unavailable
  72. func TestDockerRunPingGoogle(t *testing.T) {
  73. runCmd := exec.Command(dockerBinary, "run", "busybox", "ping", "-c", "1", "8.8.8.8")
  74. out, _, _, err := runCommandWithStdoutStderr(runCmd)
  75. errorOut(err, t, out)
  76. errorOut(err, t, "container should've been able to ping 8.8.8.8")
  77. deleteAllContainers()
  78. logDone("run - ping 8.8.8.8")
  79. }
  80. // the exit code should be 0
  81. // some versions of lxc might make this test fail
  82. func TestDockerRunExitCodeZero(t *testing.T) {
  83. runCmd := exec.Command(dockerBinary, "run", "busybox", "true")
  84. exitCode, err := runCommand(runCmd)
  85. errorOut(err, t, fmt.Sprintf("%s", err))
  86. if exitCode != 0 {
  87. t.Errorf("container should've exited with exit code 0")
  88. }
  89. deleteAllContainers()
  90. logDone("run - exit with 0")
  91. }
  92. // the exit code should be 1
  93. // some versions of lxc might make this test fail
  94. func TestDockerRunExitCodeOne(t *testing.T) {
  95. runCmd := exec.Command(dockerBinary, "run", "busybox", "false")
  96. exitCode, err := runCommand(runCmd)
  97. if err != nil && !strings.Contains("exit status 1", fmt.Sprintf("%s", err)) {
  98. t.Fatal(err)
  99. }
  100. if exitCode != 1 {
  101. t.Errorf("container should've exited with exit code 1")
  102. }
  103. deleteAllContainers()
  104. logDone("run - exit with 1")
  105. }
  106. // it should be possible to pipe in data via stdin to a process running in a container
  107. // some versions of lxc might make this test fail
  108. func TestRunStdinPipe(t *testing.T) {
  109. runCmd := exec.Command("bash", "-c", `echo "blahblah" | docker run -i -a stdin busybox cat`)
  110. out, _, _, err := runCommandWithStdoutStderr(runCmd)
  111. errorOut(err, t, out)
  112. out = stripTrailingCharacters(out)
  113. inspectCmd := exec.Command(dockerBinary, "inspect", out)
  114. inspectOut, _, err := runCommandWithOutput(inspectCmd)
  115. errorOut(err, t, fmt.Sprintf("out should've been a container id: %s %s", out, inspectOut))
  116. waitCmd := exec.Command(dockerBinary, "wait", out)
  117. _, _, err = runCommandWithOutput(waitCmd)
  118. errorOut(err, t, fmt.Sprintf("error thrown while waiting for container: %s", out))
  119. logsCmd := exec.Command(dockerBinary, "logs", out)
  120. containerLogs, _, err := runCommandWithOutput(logsCmd)
  121. errorOut(err, t, fmt.Sprintf("error thrown while trying to get container logs: %s", err))
  122. containerLogs = stripTrailingCharacters(containerLogs)
  123. if containerLogs != "blahblah" {
  124. t.Errorf("logs didn't print the container's logs %s", containerLogs)
  125. }
  126. rmCmd := exec.Command(dockerBinary, "rm", out)
  127. _, _, err = runCommandWithOutput(rmCmd)
  128. errorOut(err, t, fmt.Sprintf("rm failed to remove container %s", err))
  129. deleteAllContainers()
  130. logDone("run - pipe in with -i -a stdin")
  131. }
  132. // the container's ID should be printed when starting a container in detached mode
  133. func TestDockerRunDetachedContainerIDPrinting(t *testing.T) {
  134. runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true")
  135. out, _, _, err := runCommandWithStdoutStderr(runCmd)
  136. errorOut(err, t, out)
  137. out = stripTrailingCharacters(out)
  138. inspectCmd := exec.Command(dockerBinary, "inspect", out)
  139. inspectOut, _, err := runCommandWithOutput(inspectCmd)
  140. errorOut(err, t, fmt.Sprintf("out should've been a container id: %s %s", out, inspectOut))
  141. waitCmd := exec.Command(dockerBinary, "wait", out)
  142. _, _, err = runCommandWithOutput(waitCmd)
  143. errorOut(err, t, fmt.Sprintf("error thrown while waiting for container: %s", out))
  144. rmCmd := exec.Command(dockerBinary, "rm", out)
  145. rmOut, _, err := runCommandWithOutput(rmCmd)
  146. errorOut(err, t, "rm failed to remove container")
  147. rmOut = stripTrailingCharacters(rmOut)
  148. if rmOut != out {
  149. t.Errorf("rm didn't print the container ID %s %s", out, rmOut)
  150. }
  151. deleteAllContainers()
  152. logDone("run - print container ID in detached mode")
  153. }
  154. // the working directory should be set correctly
  155. func TestDockerRunWorkingDirectory(t *testing.T) {
  156. runCmd := exec.Command(dockerBinary, "run", "-w", "/root", "busybox", "pwd")
  157. out, _, _, err := runCommandWithStdoutStderr(runCmd)
  158. errorOut(err, t, out)
  159. out = stripTrailingCharacters(out)
  160. if out != "/root" {
  161. t.Errorf("-w failed to set working directory")
  162. }
  163. runCmd = exec.Command(dockerBinary, "run", "--workdir", "/root", "busybox", "pwd")
  164. out, _, _, err = runCommandWithStdoutStderr(runCmd)
  165. errorOut(err, t, out)
  166. out = stripTrailingCharacters(out)
  167. if out != "/root" {
  168. t.Errorf("--workdir failed to set working directory")
  169. }
  170. deleteAllContainers()
  171. logDone("run - run with working directory set by -w")
  172. logDone("run - run with working directory set by --workdir")
  173. }
  174. // pinging Google's DNS resolver should fail when we disable the networking
  175. func TestDockerRunWithoutNetworking(t *testing.T) {
  176. runCmd := exec.Command(dockerBinary, "run", "--networking=false", "busybox", "ping", "-c", "1", "8.8.8.8")
  177. out, _, exitCode, err := runCommandWithStdoutStderr(runCmd)
  178. if err != nil && exitCode != 1 {
  179. t.Fatal(out, err)
  180. }
  181. if exitCode != 1 {
  182. t.Errorf("--networking=false should've disabled the network; the container shouldn't have been able to ping 8.8.8.8")
  183. }
  184. runCmd = exec.Command(dockerBinary, "run", "-n=false", "busybox", "ping", "-c", "1", "8.8.8.8")
  185. out, _, exitCode, err = runCommandWithStdoutStderr(runCmd)
  186. if err != nil && exitCode != 1 {
  187. t.Fatal(out, err)
  188. }
  189. if exitCode != 1 {
  190. t.Errorf("-n=false should've disabled the network; the container shouldn't have been able to ping 8.8.8.8")
  191. }
  192. deleteAllContainers()
  193. logDone("run - disable networking with --networking=false")
  194. logDone("run - disable networking with -n=false")
  195. }
  196. // Regression test for #4741
  197. func TestDockerRunWithVolumesAsFiles(t *testing.T) {
  198. runCmd := exec.Command(dockerBinary, "run", "--name", "test-data", "--volume", "/etc/hosts:/target-file", "busybox", "true")
  199. out, stderr, exitCode, err := runCommandWithStdoutStderr(runCmd)
  200. if err != nil && exitCode != 0 {
  201. t.Fatal("1", out, stderr, err)
  202. }
  203. runCmd = exec.Command(dockerBinary, "run", "--volumes-from", "test-data", "busybox", "cat", "/target-file")
  204. out, stderr, exitCode, err = runCommandWithStdoutStderr(runCmd)
  205. if err != nil && exitCode != 0 {
  206. t.Fatal("2", out, stderr, err)
  207. }
  208. deleteAllContainers()
  209. logDone("run - regression test for #4741 - volumes from as files")
  210. }
  211. // Regression test for #4979
  212. func TestDockerRunWithVolumesFromExited(t *testing.T) {
  213. runCmd := exec.Command(dockerBinary, "run", "--name", "test-data", "--volume", "/some/dir", "busybox", "touch", "/some/dir/file")
  214. out, stderr, exitCode, err := runCommandWithStdoutStderr(runCmd)
  215. if err != nil && exitCode != 0 {
  216. t.Fatal("1", out, stderr, err)
  217. }
  218. runCmd = exec.Command(dockerBinary, "run", "--volumes-from", "test-data", "busybox", "cat", "/some/dir/file")
  219. out, stderr, exitCode, err = runCommandWithStdoutStderr(runCmd)
  220. if err != nil && exitCode != 0 {
  221. t.Fatal("2", out, stderr, err)
  222. }
  223. deleteAllContainers()
  224. logDone("run - regression test for #4979 - volumes-from on exited container")
  225. }
  226. // Regression test for #4830
  227. func TestDockerRunWithRelativePath(t *testing.T) {
  228. runCmd := exec.Command(dockerBinary, "run", "-v", "tmp:/other-tmp", "busybox", "true")
  229. if _, _, _, err := runCommandWithStdoutStderr(runCmd); err == nil {
  230. t.Fatalf("relative path should result in an error")
  231. }
  232. deleteAllContainers()
  233. logDone("run - volume with relative path")
  234. }
  235. func TestVolumesMountedAsReadonly(t *testing.T) {
  236. cmd := exec.Command(dockerBinary, "run", "-v", "/test:/test:ro", "busybox", "touch", "/test/somefile")
  237. if code, err := runCommand(cmd); err == nil || code == 0 {
  238. t.Fatalf("run should fail because volume is ro: exit code %d", code)
  239. }
  240. deleteAllContainers()
  241. logDone("run - volumes as readonly mount")
  242. }
  243. func TestVolumesFromInReadonlyMode(t *testing.T) {
  244. cmd := exec.Command(dockerBinary, "run", "--name", "parent", "-v", "/test", "busybox", "true")
  245. if _, err := runCommand(cmd); err != nil {
  246. t.Fatal(err)
  247. }
  248. cmd = exec.Command(dockerBinary, "run", "--volumes-from", "parent:ro", "busybox", "touch", "/test/file")
  249. if code, err := runCommand(cmd); err == nil || code == 0 {
  250. t.Fatalf("run should fail because volume is ro: exit code %d", code)
  251. }
  252. deleteAllContainers()
  253. logDone("run - volumes from as readonly mount")
  254. }
  255. // Regression test for #1201
  256. func TestVolumesFromInReadWriteMode(t *testing.T) {
  257. cmd := exec.Command(dockerBinary, "run", "--name", "parent", "-v", "/test", "busybox", "true")
  258. if _, err := runCommand(cmd); err != nil {
  259. t.Fatal(err)
  260. }
  261. cmd = exec.Command(dockerBinary, "run", "--volumes-from", "parent", "busybox", "touch", "/test/file")
  262. if _, err := runCommand(cmd); err != nil {
  263. t.Fatal(err)
  264. }
  265. deleteAllContainers()
  266. logDone("run - volumes from as read write mount")
  267. }
  268. // Test for #1351
  269. func TestApplyVolumesFromBeforeVolumes(t *testing.T) {
  270. cmd := exec.Command(dockerBinary, "run", "--name", "parent", "-v", "/test", "busybox", "touch", "/test/foo")
  271. if _, err := runCommand(cmd); err != nil {
  272. t.Fatal(err)
  273. }
  274. cmd = exec.Command(dockerBinary, "run", "--volumes-from", "parent", "-v", "/test", "busybox", "cat", "/test/foo")
  275. if _, err := runCommand(cmd); err != nil {
  276. t.Fatal(err)
  277. }
  278. deleteAllContainers()
  279. logDone("run - volumes from mounted first")
  280. }
  281. func TestMultipleVolumesFrom(t *testing.T) {
  282. cmd := exec.Command(dockerBinary, "run", "--name", "parent1", "-v", "/test", "busybox", "touch", "/test/foo")
  283. if _, err := runCommand(cmd); err != nil {
  284. t.Fatal(err)
  285. }
  286. cmd = exec.Command(dockerBinary, "run", "--name", "parent2", "-v", "/other", "busybox", "touch", "/other/bar")
  287. if _, err := runCommand(cmd); err != nil {
  288. t.Fatal(err)
  289. }
  290. cmd = exec.Command(dockerBinary, "run", "--volumes-from", "parent1", "--volumes-from", "parent2",
  291. "busybox", "sh", "-c", "cat /test/foo && cat /other/bar")
  292. if _, err := runCommand(cmd); err != nil {
  293. t.Fatal(err)
  294. }
  295. deleteAllContainers()
  296. logDone("run - multiple volumes from")
  297. }
  298. // this tests verifies the ID format for the container
  299. func TestVerifyContainerID(t *testing.T) {
  300. cmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true")
  301. out, exit, err := runCommandWithOutput(cmd)
  302. if err != nil {
  303. t.Fatal(err)
  304. }
  305. if exit != 0 {
  306. t.Fatalf("expected exit code 0 received %d", exit)
  307. }
  308. match, err := regexp.MatchString("^[0-9a-f]{64}$", strings.TrimSuffix(out, "\n"))
  309. if err != nil {
  310. t.Fatal(err)
  311. }
  312. if !match {
  313. t.Fatalf("Invalid container ID: %s", out)
  314. }
  315. deleteAllContainers()
  316. logDone("run - verify container ID")
  317. }
  318. // Test that creating a container with a volume doesn't crash. Regression test for #995.
  319. func TestCreateVolume(t *testing.T) {
  320. cmd := exec.Command(dockerBinary, "run", "-v", "/var/lib/data", "busybox", "true")
  321. if _, err := runCommand(cmd); err != nil {
  322. t.Fatal(err)
  323. }
  324. deleteAllContainers()
  325. logDone("run - create docker mangaed volume")
  326. }
  327. func TestExitCode(t *testing.T) {
  328. cmd := exec.Command(dockerBinary, "run", "busybox", "/bin/sh", "-c", "exit 72")
  329. exit, err := runCommand(cmd)
  330. if err == nil {
  331. t.Fatal("should not have a non nil error")
  332. }
  333. if exit != 72 {
  334. t.Fatalf("expected exit code 72 received %d", exit)
  335. }
  336. deleteAllContainers()
  337. logDone("run - correct exit code")
  338. }
  339. func TestUserDefaultsToRoot(t *testing.T) {
  340. cmd := exec.Command(dockerBinary, "run", "busybox", "id")
  341. out, _, err := runCommandWithOutput(cmd)
  342. if err != nil {
  343. t.Fatal(err, out)
  344. }
  345. if !strings.Contains(out, "uid=0(root) gid=0(root)") {
  346. t.Fatalf("expected root user got %s", out)
  347. }
  348. deleteAllContainers()
  349. logDone("run - default user")
  350. }
  351. func TestUserByName(t *testing.T) {
  352. cmd := exec.Command(dockerBinary, "run", "-u", "root", "busybox", "id")
  353. out, _, err := runCommandWithOutput(cmd)
  354. if err != nil {
  355. t.Fatal(err, out)
  356. }
  357. if !strings.Contains(out, "uid=0(root) gid=0(root)") {
  358. t.Fatalf("expected root user got %s", out)
  359. }
  360. deleteAllContainers()
  361. logDone("run - user by name")
  362. }
  363. func TestUserByID(t *testing.T) {
  364. cmd := exec.Command(dockerBinary, "run", "-u", "1", "busybox", "id")
  365. out, _, err := runCommandWithOutput(cmd)
  366. if err != nil {
  367. t.Fatal(err, out)
  368. }
  369. if !strings.Contains(out, "uid=1(daemon) gid=1(daemon)") {
  370. t.Fatalf("expected daemon user got %s", out)
  371. }
  372. deleteAllContainers()
  373. logDone("run - user by id")
  374. }
  375. func TestUserNotFound(t *testing.T) {
  376. cmd := exec.Command(dockerBinary, "run", "-u", "notme", "busybox", "id")
  377. _, err := runCommand(cmd)
  378. if err == nil {
  379. t.Fatal("unknown user should cause container to fail")
  380. }
  381. deleteAllContainers()
  382. logDone("run - user not found")
  383. }
  384. func TestRunTwoConcurrentContainers(t *testing.T) {
  385. group := sync.WaitGroup{}
  386. group.Add(2)
  387. for i := 0; i < 2; i++ {
  388. go func() {
  389. defer group.Done()
  390. cmd := exec.Command(dockerBinary, "run", "busybox", "sleep", "2")
  391. if _, err := runCommand(cmd); err != nil {
  392. t.Fatal(err)
  393. }
  394. }()
  395. }
  396. group.Wait()
  397. deleteAllContainers()
  398. logDone("run - two concurrent containers")
  399. }
  400. func TestEnvironment(t *testing.T) {
  401. cmd := exec.Command(dockerBinary, "run", "-h", "testing", "-e=FALSE=true", "-e=TRUE", "-e=TRICKY", "busybox", "env")
  402. cmd.Env = append(os.Environ(),
  403. "TRUE=false",
  404. "TRICKY=tri\ncky\n",
  405. )
  406. out, _, err := runCommandWithOutput(cmd)
  407. if err != nil {
  408. t.Fatal(err, out)
  409. }
  410. actualEnv := strings.Split(out, "\n")
  411. if actualEnv[len(actualEnv)-1] == "" {
  412. actualEnv = actualEnv[:len(actualEnv)-1]
  413. }
  414. sort.Strings(actualEnv)
  415. goodEnv := []string{
  416. "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
  417. "HOME=/",
  418. "HOSTNAME=testing",
  419. "FALSE=true",
  420. "TRUE=false",
  421. "TRICKY=tri",
  422. "cky",
  423. "",
  424. }
  425. sort.Strings(goodEnv)
  426. if len(goodEnv) != len(actualEnv) {
  427. t.Fatalf("Wrong environment: should be %d variables, not: '%s'\n", len(goodEnv), strings.Join(actualEnv, ", "))
  428. }
  429. for i := range goodEnv {
  430. if actualEnv[i] != goodEnv[i] {
  431. t.Fatalf("Wrong environment variable: should be %s, not %s", goodEnv[i], actualEnv[i])
  432. }
  433. }
  434. deleteAllContainers()
  435. logDone("run - verify environment")
  436. }