docker_api_ipcmode_test.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. // build +linux
  2. package main
  3. import (
  4. "bufio"
  5. "context"
  6. "fmt"
  7. "io/ioutil"
  8. "os"
  9. "strings"
  10. "github.com/docker/docker/api/types"
  11. "github.com/docker/docker/api/types/container"
  12. "github.com/docker/docker/integration-cli/checker"
  13. "github.com/docker/docker/integration-cli/cli"
  14. "github.com/go-check/check"
  15. )
  16. /* testIpcCheckDevExists checks whether a given mount (identified by its
  17. * major:minor pair from /proc/self/mountinfo) exists on the host system.
  18. *
  19. * The format of /proc/self/mountinfo is like:
  20. *
  21. * 29 23 0:24 / /dev/shm rw,nosuid,nodev shared:4 - tmpfs tmpfs rw
  22. * ^^^^\
  23. * - this is the minor:major we look for
  24. */
  25. func testIpcCheckDevExists(mm string) (bool, error) {
  26. f, err := os.Open("/proc/self/mountinfo")
  27. if err != nil {
  28. return false, err
  29. }
  30. defer f.Close()
  31. s := bufio.NewScanner(f)
  32. for s.Scan() {
  33. fields := strings.Fields(s.Text())
  34. if len(fields) < 7 {
  35. continue
  36. }
  37. if fields[2] == mm {
  38. return true, nil
  39. }
  40. }
  41. return false, s.Err()
  42. }
  43. // testIpcContainer is a helper function to test --ipc container:NNN mode in various scenarios
  44. func testIpcContainer(s *DockerSuite, c *check.C, donorMode string, mustWork bool) {
  45. cfg := container.Config{
  46. Image: "busybox",
  47. Cmd: []string{"top"},
  48. }
  49. hostCfg := container.HostConfig{
  50. IpcMode: container.IpcMode(donorMode),
  51. }
  52. ctx := context.Background()
  53. client := testEnv.APIClient()
  54. // create and start the "donor" container
  55. resp, err := client.ContainerCreate(ctx, &cfg, &hostCfg, nil, "")
  56. c.Assert(err, checker.IsNil)
  57. c.Assert(len(resp.Warnings), checker.Equals, 0)
  58. name1 := resp.ID
  59. err = client.ContainerStart(ctx, name1, types.ContainerStartOptions{})
  60. c.Assert(err, checker.IsNil)
  61. // create and start the second container
  62. hostCfg.IpcMode = container.IpcMode("container:" + name1)
  63. resp, err = client.ContainerCreate(ctx, &cfg, &hostCfg, nil, "")
  64. c.Assert(err, checker.IsNil)
  65. c.Assert(len(resp.Warnings), checker.Equals, 0)
  66. name2 := resp.ID
  67. err = client.ContainerStart(ctx, name2, types.ContainerStartOptions{})
  68. if !mustWork {
  69. // start should fail with a specific error
  70. c.Assert(err, checker.NotNil)
  71. c.Assert(fmt.Sprintf("%v", err), checker.Contains, "non-shareable IPC")
  72. // no more checks to perform here
  73. return
  74. }
  75. // start should succeed
  76. c.Assert(err, checker.IsNil)
  77. // check that IPC is shared
  78. // 1. create a file in the first container
  79. cli.DockerCmd(c, "exec", name1, "sh", "-c", "printf covfefe > /dev/shm/bar")
  80. // 2. check it's the same file in the second one
  81. out := cli.DockerCmd(c, "exec", "-i", name2, "cat", "/dev/shm/bar").Combined()
  82. c.Assert(out, checker.Matches, "^covfefe$")
  83. }
  84. /* TestAPIIpcModeShareableAndContainer checks that a container created with
  85. * --ipc container:ID can use IPC of another shareable container.
  86. */
  87. func (s *DockerSuite) TestAPIIpcModeShareableAndContainer(c *check.C) {
  88. testRequires(c, DaemonIsLinux)
  89. testIpcContainer(s, c, "shareable", true)
  90. }
  91. /* TestAPIIpcModePrivateAndContainer checks that a container created with
  92. * --ipc container:ID can NOT use IPC of another private container.
  93. */
  94. func (s *DockerSuite) TestAPIIpcModePrivateAndContainer(c *check.C) {
  95. testRequires(c, DaemonIsLinux, MinimumAPIVersion("1.32"))
  96. testIpcContainer(s, c, "private", false)
  97. }
  98. /* TestAPIIpcModeHost checks that a container created with --ipc host
  99. * can use IPC of the host system.
  100. */
  101. func (s *DockerSuite) TestAPIIpcModeHost(c *check.C) {
  102. testRequires(c, DaemonIsLinux, SameHostDaemon, NotUserNamespace)
  103. cfg := container.Config{
  104. Image: "busybox",
  105. Cmd: []string{"top"},
  106. }
  107. hostCfg := container.HostConfig{
  108. IpcMode: container.IpcMode("host"),
  109. }
  110. ctx := context.Background()
  111. client := testEnv.APIClient()
  112. resp, err := client.ContainerCreate(ctx, &cfg, &hostCfg, nil, "")
  113. c.Assert(err, checker.IsNil)
  114. c.Assert(len(resp.Warnings), checker.Equals, 0)
  115. name := resp.ID
  116. err = client.ContainerStart(ctx, name, types.ContainerStartOptions{})
  117. c.Assert(err, checker.IsNil)
  118. // check that IPC is shared
  119. // 1. create a file inside container
  120. cli.DockerCmd(c, "exec", name, "sh", "-c", "printf covfefe > /dev/shm/."+name)
  121. // 2. check it's the same on the host
  122. bytes, err := ioutil.ReadFile("/dev/shm/." + name)
  123. c.Assert(err, checker.IsNil)
  124. c.Assert(string(bytes), checker.Matches, "^covfefe$")
  125. // 3. clean up
  126. cli.DockerCmd(c, "exec", name, "rm", "-f", "/dev/shm/."+name)
  127. }