container_test.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720
  1. package docker
  2. import (
  3. "bufio"
  4. "fmt"
  5. "github.com/dotcloud/docker/runconfig"
  6. "github.com/dotcloud/docker/utils"
  7. "io"
  8. "io/ioutil"
  9. "os"
  10. "path"
  11. "regexp"
  12. "sort"
  13. "strings"
  14. "testing"
  15. "time"
  16. )
  17. func TestCpuShares(t *testing.T) {
  18. _, err1 := os.Stat("/sys/fs/cgroup/cpuacct,cpu")
  19. _, err2 := os.Stat("/sys/fs/cgroup/cpu,cpuacct")
  20. if err1 == nil || err2 == nil {
  21. t.Skip("Fixme. Setting cpu cgroup shares doesn't work in dind on a Fedora host. The lxc utils are confused by the cpu,cpuacct mount.")
  22. }
  23. daemon := mkDaemon(t)
  24. defer nuke(daemon)
  25. container, _, _ := mkContainer(daemon, []string{"-m", "33554432", "-c", "1000", "-i", "_", "/bin/cat"}, t)
  26. defer daemon.Destroy(container)
  27. cStdin, err := container.StdinPipe()
  28. if err != nil {
  29. t.Fatal(err)
  30. }
  31. if err := container.Start(); err != nil {
  32. t.Fatal(err)
  33. }
  34. // Give some time to the process to start
  35. container.WaitTimeout(500 * time.Millisecond)
  36. if !container.State.IsRunning() {
  37. t.Errorf("Container should be running")
  38. }
  39. if err := container.Start(); err != nil {
  40. t.Fatalf("A running container should be able to be started")
  41. }
  42. // Try to avoid the timeout in destroy. Best effort, don't check error
  43. cStdin.Close()
  44. container.WaitTimeout(2 * time.Second)
  45. }
  46. func TestKillDifferentUser(t *testing.T) {
  47. daemon := mkDaemon(t)
  48. defer nuke(daemon)
  49. container, _, err := daemon.Create(&runconfig.Config{
  50. Image: GetTestImage(daemon).ID,
  51. Cmd: []string{"cat"},
  52. OpenStdin: true,
  53. User: "daemon",
  54. },
  55. "",
  56. )
  57. if err != nil {
  58. t.Fatal(err)
  59. }
  60. defer daemon.Destroy(container)
  61. // FIXME @shykes: this seems redundant, but is very old, I'm leaving it in case
  62. // there is a side effect I'm not seeing.
  63. // defer container.stdin.Close()
  64. if container.State.IsRunning() {
  65. t.Errorf("Container shouldn't be running")
  66. }
  67. if err := container.Start(); err != nil {
  68. t.Fatal(err)
  69. }
  70. setTimeout(t, "Waiting for the container to be started timed out", 2*time.Second, func() {
  71. for !container.State.IsRunning() {
  72. time.Sleep(10 * time.Millisecond)
  73. }
  74. })
  75. setTimeout(t, "read/write assertion timed out", 2*time.Second, func() {
  76. out, _ := container.StdoutPipe()
  77. in, _ := container.StdinPipe()
  78. if err := assertPipe("hello\n", "hello", out, in, 150); err != nil {
  79. t.Fatal(err)
  80. }
  81. })
  82. if err := container.Kill(); err != nil {
  83. t.Fatal(err)
  84. }
  85. if container.State.IsRunning() {
  86. t.Errorf("Container shouldn't be running")
  87. }
  88. container.Wait()
  89. if container.State.IsRunning() {
  90. t.Errorf("Container shouldn't be running")
  91. }
  92. // Try stopping twice
  93. if err := container.Kill(); err != nil {
  94. t.Fatal(err)
  95. }
  96. }
  97. func TestRestart(t *testing.T) {
  98. daemon := mkDaemon(t)
  99. defer nuke(daemon)
  100. container, _, err := daemon.Create(&runconfig.Config{
  101. Image: GetTestImage(daemon).ID,
  102. Cmd: []string{"echo", "-n", "foobar"},
  103. },
  104. "",
  105. )
  106. if err != nil {
  107. t.Fatal(err)
  108. }
  109. defer daemon.Destroy(container)
  110. output, err := container.Output()
  111. if err != nil {
  112. t.Fatal(err)
  113. }
  114. if string(output) != "foobar" {
  115. t.Error(string(output))
  116. }
  117. // Run the container again and check the output
  118. output, err = container.Output()
  119. if err != nil {
  120. t.Fatal(err)
  121. }
  122. if string(output) != "foobar" {
  123. t.Error(string(output))
  124. }
  125. }
  126. func TestRestartStdin(t *testing.T) {
  127. daemon := mkDaemon(t)
  128. defer nuke(daemon)
  129. container, _, err := daemon.Create(&runconfig.Config{
  130. Image: GetTestImage(daemon).ID,
  131. Cmd: []string{"cat"},
  132. OpenStdin: true,
  133. },
  134. "",
  135. )
  136. if err != nil {
  137. t.Fatal(err)
  138. }
  139. defer daemon.Destroy(container)
  140. stdin, err := container.StdinPipe()
  141. if err != nil {
  142. t.Fatal(err)
  143. }
  144. stdout, err := container.StdoutPipe()
  145. if err != nil {
  146. t.Fatal(err)
  147. }
  148. if err := container.Start(); err != nil {
  149. t.Fatal(err)
  150. }
  151. if _, err := io.WriteString(stdin, "hello world"); err != nil {
  152. t.Fatal(err)
  153. }
  154. if err := stdin.Close(); err != nil {
  155. t.Fatal(err)
  156. }
  157. container.Wait()
  158. output, err := ioutil.ReadAll(stdout)
  159. if err != nil {
  160. t.Fatal(err)
  161. }
  162. if err := stdout.Close(); err != nil {
  163. t.Fatal(err)
  164. }
  165. if string(output) != "hello world" {
  166. t.Fatalf("Unexpected output. Expected %s, received: %s", "hello world", string(output))
  167. }
  168. // Restart and try again
  169. stdin, err = container.StdinPipe()
  170. if err != nil {
  171. t.Fatal(err)
  172. }
  173. stdout, err = container.StdoutPipe()
  174. if err != nil {
  175. t.Fatal(err)
  176. }
  177. if err := container.Start(); err != nil {
  178. t.Fatal(err)
  179. }
  180. if _, err := io.WriteString(stdin, "hello world #2"); err != nil {
  181. t.Fatal(err)
  182. }
  183. if err := stdin.Close(); err != nil {
  184. t.Fatal(err)
  185. }
  186. container.Wait()
  187. output, err = ioutil.ReadAll(stdout)
  188. if err != nil {
  189. t.Fatal(err)
  190. }
  191. if err := stdout.Close(); err != nil {
  192. t.Fatal(err)
  193. }
  194. if string(output) != "hello world #2" {
  195. t.Fatalf("Unexpected output. Expected %s, received: %s", "hello world #2", string(output))
  196. }
  197. }
  198. func TestStdin(t *testing.T) {
  199. daemon := mkDaemon(t)
  200. defer nuke(daemon)
  201. container, _, err := daemon.Create(&runconfig.Config{
  202. Image: GetTestImage(daemon).ID,
  203. Cmd: []string{"cat"},
  204. OpenStdin: true,
  205. },
  206. "",
  207. )
  208. if err != nil {
  209. t.Fatal(err)
  210. }
  211. defer daemon.Destroy(container)
  212. stdin, err := container.StdinPipe()
  213. if err != nil {
  214. t.Fatal(err)
  215. }
  216. stdout, err := container.StdoutPipe()
  217. if err != nil {
  218. t.Fatal(err)
  219. }
  220. if err := container.Start(); err != nil {
  221. t.Fatal(err)
  222. }
  223. defer stdin.Close()
  224. defer stdout.Close()
  225. if _, err := io.WriteString(stdin, "hello world"); err != nil {
  226. t.Fatal(err)
  227. }
  228. if err := stdin.Close(); err != nil {
  229. t.Fatal(err)
  230. }
  231. container.Wait()
  232. output, err := ioutil.ReadAll(stdout)
  233. if err != nil {
  234. t.Fatal(err)
  235. }
  236. if string(output) != "hello world" {
  237. t.Fatalf("Unexpected output. Expected %s, received: %s", "hello world", string(output))
  238. }
  239. }
  240. func TestTty(t *testing.T) {
  241. daemon := mkDaemon(t)
  242. defer nuke(daemon)
  243. container, _, err := daemon.Create(&runconfig.Config{
  244. Image: GetTestImage(daemon).ID,
  245. Cmd: []string{"cat"},
  246. OpenStdin: true,
  247. },
  248. "",
  249. )
  250. if err != nil {
  251. t.Fatal(err)
  252. }
  253. defer daemon.Destroy(container)
  254. stdin, err := container.StdinPipe()
  255. if err != nil {
  256. t.Fatal(err)
  257. }
  258. stdout, err := container.StdoutPipe()
  259. if err != nil {
  260. t.Fatal(err)
  261. }
  262. if err := container.Start(); err != nil {
  263. t.Fatal(err)
  264. }
  265. defer stdin.Close()
  266. defer stdout.Close()
  267. if _, err := io.WriteString(stdin, "hello world"); err != nil {
  268. t.Fatal(err)
  269. }
  270. if err := stdin.Close(); err != nil {
  271. t.Fatal(err)
  272. }
  273. container.Wait()
  274. output, err := ioutil.ReadAll(stdout)
  275. if err != nil {
  276. t.Fatal(err)
  277. }
  278. if string(output) != "hello world" {
  279. t.Fatalf("Unexpected output. Expected %s, received: %s", "hello world", string(output))
  280. }
  281. }
  282. func TestEntrypoint(t *testing.T) {
  283. daemon := mkDaemon(t)
  284. defer nuke(daemon)
  285. container, _, err := daemon.Create(
  286. &runconfig.Config{
  287. Image: GetTestImage(daemon).ID,
  288. Entrypoint: []string{"/bin/echo"},
  289. Cmd: []string{"-n", "foobar"},
  290. },
  291. "",
  292. )
  293. if err != nil {
  294. t.Fatal(err)
  295. }
  296. defer daemon.Destroy(container)
  297. output, err := container.Output()
  298. if err != nil {
  299. t.Fatal(err)
  300. }
  301. if string(output) != "foobar" {
  302. t.Error(string(output))
  303. }
  304. }
  305. func TestEntrypointNoCmd(t *testing.T) {
  306. daemon := mkDaemon(t)
  307. defer nuke(daemon)
  308. container, _, err := daemon.Create(
  309. &runconfig.Config{
  310. Image: GetTestImage(daemon).ID,
  311. Entrypoint: []string{"/bin/echo", "foobar"},
  312. },
  313. "",
  314. )
  315. if err != nil {
  316. t.Fatal(err)
  317. }
  318. defer daemon.Destroy(container)
  319. output, err := container.Output()
  320. if err != nil {
  321. t.Fatal(err)
  322. }
  323. if strings.Trim(string(output), "\r\n") != "foobar" {
  324. t.Error(string(output))
  325. }
  326. }
  327. func BenchmarkRunSequential(b *testing.B) {
  328. daemon := mkDaemon(b)
  329. defer nuke(daemon)
  330. for i := 0; i < b.N; i++ {
  331. container, _, err := daemon.Create(&runconfig.Config{
  332. Image: GetTestImage(daemon).ID,
  333. Cmd: []string{"echo", "-n", "foo"},
  334. },
  335. "",
  336. )
  337. if err != nil {
  338. b.Fatal(err)
  339. }
  340. defer daemon.Destroy(container)
  341. output, err := container.Output()
  342. if err != nil {
  343. b.Fatal(err)
  344. }
  345. if string(output) != "foo" {
  346. b.Fatalf("Unexpected output: %s", output)
  347. }
  348. if err := daemon.Destroy(container); err != nil {
  349. b.Fatal(err)
  350. }
  351. }
  352. }
  353. func BenchmarkRunParallel(b *testing.B) {
  354. daemon := mkDaemon(b)
  355. defer nuke(daemon)
  356. var tasks []chan error
  357. for i := 0; i < b.N; i++ {
  358. complete := make(chan error)
  359. tasks = append(tasks, complete)
  360. go func(i int, complete chan error) {
  361. container, _, err := daemon.Create(&runconfig.Config{
  362. Image: GetTestImage(daemon).ID,
  363. Cmd: []string{"echo", "-n", "foo"},
  364. },
  365. "",
  366. )
  367. if err != nil {
  368. complete <- err
  369. return
  370. }
  371. defer daemon.Destroy(container)
  372. if err := container.Start(); err != nil {
  373. complete <- err
  374. return
  375. }
  376. if err := container.WaitTimeout(15 * time.Second); err != nil {
  377. complete <- err
  378. return
  379. }
  380. // if string(output) != "foo" {
  381. // complete <- fmt.Errorf("Unexecpted output: %v", string(output))
  382. // }
  383. if err := daemon.Destroy(container); err != nil {
  384. complete <- err
  385. return
  386. }
  387. complete <- nil
  388. }(i, complete)
  389. }
  390. var errors []error
  391. for _, task := range tasks {
  392. err := <-task
  393. if err != nil {
  394. errors = append(errors, err)
  395. }
  396. }
  397. if len(errors) > 0 {
  398. b.Fatal(errors)
  399. }
  400. }
  401. func tempDir(t *testing.T) string {
  402. tmpDir, err := ioutil.TempDir("", "docker-test-container")
  403. if err != nil {
  404. t.Fatal(err)
  405. }
  406. return tmpDir
  407. }
  408. // Test for #1737
  409. func TestCopyVolumeUidGid(t *testing.T) {
  410. eng := NewTestEngine(t)
  411. r := mkDaemonFromEngine(eng, t)
  412. defer r.Nuke()
  413. // Add directory not owned by root
  414. container1, _, _ := mkContainer(r, []string{"_", "/bin/sh", "-c", "mkdir -p /hello && touch /hello/test.txt && chown daemon.daemon /hello"}, t)
  415. defer r.Destroy(container1)
  416. if container1.State.IsRunning() {
  417. t.Errorf("Container shouldn't be running")
  418. }
  419. if err := container1.Run(); err != nil {
  420. t.Fatal(err)
  421. }
  422. if container1.State.IsRunning() {
  423. t.Errorf("Container shouldn't be running")
  424. }
  425. img, err := r.Commit(container1, "", "", "unit test commited image", "", nil)
  426. if err != nil {
  427. t.Error(err)
  428. }
  429. // Test that the uid and gid is copied from the image to the volume
  430. tmpDir1 := tempDir(t)
  431. defer os.RemoveAll(tmpDir1)
  432. stdout1, _ := runContainer(eng, r, []string{"-v", "/hello", img.ID, "stat", "-c", "%U %G", "/hello"}, t)
  433. if !strings.Contains(stdout1, "daemon daemon") {
  434. t.Fatal("Container failed to transfer uid and gid to volume")
  435. }
  436. }
  437. // Test for #1582
  438. func TestCopyVolumeContent(t *testing.T) {
  439. eng := NewTestEngine(t)
  440. r := mkDaemonFromEngine(eng, t)
  441. defer r.Nuke()
  442. // Put some content in a directory of a container and commit it
  443. container1, _, _ := mkContainer(r, []string{"_", "/bin/sh", "-c", "mkdir -p /hello/local && echo hello > /hello/local/world"}, t)
  444. defer r.Destroy(container1)
  445. if container1.State.IsRunning() {
  446. t.Errorf("Container shouldn't be running")
  447. }
  448. if err := container1.Run(); err != nil {
  449. t.Fatal(err)
  450. }
  451. if container1.State.IsRunning() {
  452. t.Errorf("Container shouldn't be running")
  453. }
  454. img, err := r.Commit(container1, "", "", "unit test commited image", "", nil)
  455. if err != nil {
  456. t.Error(err)
  457. }
  458. // Test that the content is copied from the image to the volume
  459. tmpDir1 := tempDir(t)
  460. defer os.RemoveAll(tmpDir1)
  461. stdout1, _ := runContainer(eng, r, []string{"-v", "/hello", img.ID, "find", "/hello"}, t)
  462. if !(strings.Contains(stdout1, "/hello/local/world") && strings.Contains(stdout1, "/hello/local")) {
  463. t.Fatal("Container failed to transfer content to volume")
  464. }
  465. }
  466. func TestBindMounts(t *testing.T) {
  467. eng := NewTestEngine(t)
  468. r := mkDaemonFromEngine(eng, t)
  469. defer r.Nuke()
  470. tmpDir := tempDir(t)
  471. defer os.RemoveAll(tmpDir)
  472. writeFile(path.Join(tmpDir, "touch-me"), "", t)
  473. // Test reading from a read-only bind mount
  474. stdout, _ := runContainer(eng, r, []string{"-v", fmt.Sprintf("%s:/tmp:ro", tmpDir), "_", "ls", "/tmp"}, t)
  475. if !strings.Contains(stdout, "touch-me") {
  476. t.Fatal("Container failed to read from bind mount")
  477. }
  478. // test writing to bind mount
  479. runContainer(eng, r, []string{"-v", fmt.Sprintf("%s:/tmp:rw", tmpDir), "_", "touch", "/tmp/holla"}, t)
  480. readFile(path.Join(tmpDir, "holla"), t) // Will fail if the file doesn't exist
  481. // test mounting to an illegal destination directory
  482. if _, err := runContainer(eng, r, []string{"-v", fmt.Sprintf("%s:.", tmpDir), "_", "ls", "."}, nil); err == nil {
  483. t.Fatal("Container bind mounted illegal directory")
  484. }
  485. // test mount a file
  486. runContainer(eng, r, []string{"-v", fmt.Sprintf("%s/holla:/tmp/holla:rw", tmpDir), "_", "sh", "-c", "echo -n 'yotta' > /tmp/holla"}, t)
  487. content := readFile(path.Join(tmpDir, "holla"), t) // Will fail if the file doesn't exist
  488. if content != "yotta" {
  489. t.Fatal("Container failed to write to bind mount file")
  490. }
  491. }
  492. // Test that restarting a container with a volume does not create a new volume on restart. Regression test for #819.
  493. func TestRestartWithVolumes(t *testing.T) {
  494. daemon := mkDaemon(t)
  495. defer nuke(daemon)
  496. container, _, err := daemon.Create(&runconfig.Config{
  497. Image: GetTestImage(daemon).ID,
  498. Cmd: []string{"echo", "-n", "foobar"},
  499. Volumes: map[string]struct{}{"/test": {}},
  500. },
  501. "",
  502. )
  503. if err != nil {
  504. t.Fatal(err)
  505. }
  506. defer daemon.Destroy(container)
  507. for key := range container.Config.Volumes {
  508. if key != "/test" {
  509. t.Fail()
  510. }
  511. }
  512. _, err = container.Output()
  513. if err != nil {
  514. t.Fatal(err)
  515. }
  516. expected := container.Volumes["/test"]
  517. if expected == "" {
  518. t.Fail()
  519. }
  520. // Run the container again to verify the volume path persists
  521. _, err = container.Output()
  522. if err != nil {
  523. t.Fatal(err)
  524. }
  525. actual := container.Volumes["/test"]
  526. if expected != actual {
  527. t.Fatalf("Expected volume path: %s Actual path: %s", expected, actual)
  528. }
  529. }
  530. func TestContainerNetwork(t *testing.T) {
  531. daemon := mkDaemon(t)
  532. defer nuke(daemon)
  533. container, _, err := daemon.Create(
  534. &runconfig.Config{
  535. Image: GetTestImage(daemon).ID,
  536. // If I change this to ping 8.8.8.8 it fails. Any idea why? - timthelion
  537. Cmd: []string{"ping", "-c", "1", "127.0.0.1"},
  538. },
  539. "",
  540. )
  541. if err != nil {
  542. t.Fatal(err)
  543. }
  544. defer daemon.Destroy(container)
  545. if err := container.Run(); err != nil {
  546. t.Fatal(err)
  547. }
  548. if code := container.State.GetExitCode(); code != 0 {
  549. t.Fatalf("Unexpected ping 127.0.0.1 exit code %d (expected 0)", code)
  550. }
  551. }
  552. // Issue #4681
  553. func TestLoopbackFunctionsWhenNetworkingIsDissabled(t *testing.T) {
  554. daemon := mkDaemon(t)
  555. defer nuke(daemon)
  556. container, _, err := daemon.Create(
  557. &runconfig.Config{
  558. Image: GetTestImage(daemon).ID,
  559. Cmd: []string{"ping", "-c", "1", "127.0.0.1"},
  560. NetworkDisabled: true,
  561. },
  562. "",
  563. )
  564. if err != nil {
  565. t.Fatal(err)
  566. }
  567. defer daemon.Destroy(container)
  568. if err := container.Run(); err != nil {
  569. t.Fatal(err)
  570. }
  571. if code := container.State.GetExitCode(); code != 0 {
  572. t.Fatalf("Unexpected ping 127.0.0.1 exit code %d (expected 0)", code)
  573. }
  574. }
  575. func TestOnlyLoopbackExistsWhenUsingDisableNetworkOption(t *testing.T) {
  576. eng := NewTestEngine(t)
  577. daemon := mkDaemonFromEngine(eng, t)
  578. defer nuke(daemon)
  579. config, hc, _, err := runconfig.Parse([]string{"-n=false", GetTestImage(daemon).ID, "ip", "addr", "show", "up"}, nil)
  580. if err != nil {
  581. t.Fatal(err)
  582. }
  583. jobCreate := eng.Job("create")
  584. if err := jobCreate.ImportEnv(config); err != nil {
  585. t.Fatal(err)
  586. }
  587. var id string
  588. jobCreate.Stdout.AddString(&id)
  589. if err := jobCreate.Run(); err != nil {
  590. t.Fatal(err)
  591. }
  592. // FIXME: this hack can be removed once Wait is a job
  593. c := daemon.Get(id)
  594. if c == nil {
  595. t.Fatalf("Couldn't retrieve container %s from daemon", id)
  596. }
  597. stdout, err := c.StdoutPipe()
  598. if err != nil {
  599. t.Fatal(err)
  600. }
  601. jobStart := eng.Job("start", id)
  602. if err := jobStart.ImportEnv(hc); err != nil {
  603. t.Fatal(err)
  604. }
  605. if err := jobStart.Run(); err != nil {
  606. t.Fatal(err)
  607. }
  608. c.WaitTimeout(500 * time.Millisecond)
  609. c.Wait()
  610. output, err := ioutil.ReadAll(stdout)
  611. if err != nil {
  612. t.Fatal(err)
  613. }
  614. interfaces := regexp.MustCompile(`(?m)^[0-9]+: [a-zA-Z0-9]+`).FindAllString(string(output), -1)
  615. if len(interfaces) != 1 {
  616. t.Fatalf("Wrong interface count in test container: expected [*: lo], got %s", interfaces)
  617. }
  618. if !strings.HasSuffix(interfaces[0], ": lo") {
  619. t.Fatalf("Wrong interface in test container: expected [*: lo], got %s", interfaces)
  620. }
  621. }
  622. func TestPrivilegedCanMknod(t *testing.T) {
  623. eng := NewTestEngine(t)
  624. daemon := mkDaemonFromEngine(eng, t)
  625. defer daemon.Nuke()
  626. if output, err := runContainer(eng, daemon, []string{"--privileged", "_", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok"}, t); output != "ok\n" {
  627. t.Fatalf("Could not mknod into privileged container %s %v", output, err)
  628. }
  629. }
  630. func TestPrivilegedCanMount(t *testing.T) {
  631. eng := NewTestEngine(t)
  632. daemon := mkDaemonFromEngine(eng, t)
  633. defer daemon.Nuke()
  634. if output, _ := runContainer(eng, daemon, []string{"--privileged", "_", "sh", "-c", "mount -t tmpfs none /tmp && echo ok"}, t); output != "ok\n" {
  635. t.Fatal("Could not mount into privileged container")
  636. }
  637. }
  638. func TestUnprivilegedCanMknod(t *testing.T) {
  639. eng := NewTestEngine(t)
  640. daemon := mkDaemonFromEngine(eng, t)
  641. defer daemon.Nuke()
  642. if output, _ := runContainer(eng, daemon, []string{"_", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok"}, t); output != "ok\n" {
  643. t.Fatal("Couldn't mknod into secure container")
  644. }
  645. }
  646. func TestUnprivilegedCannotMount(t *testing.T) {
  647. eng := NewTestEngine(t)
  648. daemon := mkDaemonFromEngine(eng, t)
  649. defer daemon.Nuke()
  650. if output, _ := runContainer(eng, daemon, []string{"_", "sh", "-c", "mount -t tmpfs none /tmp || echo ok"}, t); output != "ok\n" {
  651. t.Fatal("Could mount into secure container")
  652. }
  653. }