github.com/xdlianrong208/docker-ce-comments@v17.12.1-ce-rc2+incompatible/components/engine/integration-cli/docker_api_ipcmode_test.go (about) 1 // build +linux 2 package main 3 4 import ( 5 "bufio" 6 "fmt" 7 "io/ioutil" 8 "os" 9 "strings" 10 11 "github.com/docker/docker/api/types" 12 "github.com/docker/docker/api/types/container" 13 "github.com/docker/docker/integration-cli/checker" 14 "github.com/docker/docker/integration-cli/cli" 15 "github.com/docker/docker/integration-cli/request" 16 "github.com/go-check/check" 17 "golang.org/x/net/context" 18 ) 19 20 /* testIpcCheckDevExists checks whether a given mount (identified by its 21 * major:minor pair from /proc/self/mountinfo) exists on the host system. 22 * 23 * The format of /proc/self/mountinfo is like: 24 * 25 * 29 23 0:24 / /dev/shm rw,nosuid,nodev shared:4 - tmpfs tmpfs rw 26 * ^^^^\ 27 * - this is the minor:major we look for 28 */ 29 func testIpcCheckDevExists(mm string) (bool, error) { 30 f, err := os.Open("/proc/self/mountinfo") 31 if err != nil { 32 return false, err 33 } 34 defer f.Close() 35 36 s := bufio.NewScanner(f) 37 for s.Scan() { 38 fields := strings.Fields(s.Text()) 39 if len(fields) < 7 { 40 continue 41 } 42 if fields[2] == mm { 43 return true, nil 44 } 45 } 46 47 return false, s.Err() 48 } 49 50 // testIpcNonePrivateShareable is a helper function to test "none", 51 // "private" and "shareable" modes. 52 func testIpcNonePrivateShareable(c *check.C, mode string, mustBeMounted bool, mustBeShared bool) { 53 cfg := container.Config{ 54 Image: "busybox", 55 Cmd: []string{"top"}, 56 } 57 hostCfg := container.HostConfig{ 58 IpcMode: container.IpcMode(mode), 59 } 60 ctx := context.Background() 61 62 client, err := request.NewClient() 63 c.Assert(err, checker.IsNil) 64 65 resp, err := client.ContainerCreate(ctx, &cfg, &hostCfg, nil, "") 66 c.Assert(err, checker.IsNil) 67 c.Assert(len(resp.Warnings), checker.Equals, 0) 68 69 err = client.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{}) 70 c.Assert(err, checker.IsNil) 71 72 // get major:minor pair for /dev/shm from container's /proc/self/mountinfo 73 cmd := "awk '($5 == \"/dev/shm\") {printf $3}' /proc/self/mountinfo" 74 mm := cli.DockerCmd(c, "exec", "-i", resp.ID, "sh", "-c", cmd).Combined() 75 if !mustBeMounted { 76 c.Assert(mm, checker.Equals, "") 77 // no more checks to perform 78 return 79 } 80 c.Assert(mm, checker.Matches, "^[0-9]+:[0-9]+$") 81 82 shared, err := testIpcCheckDevExists(mm) 83 c.Assert(err, checker.IsNil) 84 c.Logf("[testIpcPrivateShareable] ipcmode: %v, ipcdev: %v, shared: %v, mustBeShared: %v\n", mode, mm, shared, mustBeShared) 85 c.Assert(shared, checker.Equals, mustBeShared) 86 } 87 88 /* TestAPIIpcModeNone checks the container "none" IPC mode 89 * (--ipc none) works as expected. It makes sure there is no 90 * /dev/shm mount inside the container. 91 */ 92 func (s *DockerSuite) TestAPIIpcModeNone(c *check.C) { 93 testRequires(c, DaemonIsLinux) 94 testIpcNonePrivateShareable(c, "none", false, false) 95 } 96 97 /* TestAPIIpcModePrivate checks the container private IPC mode 98 * (--ipc private) works as expected. It gets the minor:major pair 99 * of /dev/shm mount from the container, and makes sure there is no 100 * such pair on the host. 101 */ 102 func (s *DockerSuite) TestAPIIpcModePrivate(c *check.C) { 103 testRequires(c, DaemonIsLinux, SameHostDaemon) 104 testIpcNonePrivateShareable(c, "private", true, false) 105 } 106 107 /* TestAPIIpcModeShareable checks the container shareable IPC mode 108 * (--ipc shareable) works as expected. It gets the minor:major pair 109 * of /dev/shm mount from the container, and makes sure such pair 110 * also exists on the host. 111 */ 112 func (s *DockerSuite) TestAPIIpcModeShareable(c *check.C) { 113 testRequires(c, DaemonIsLinux, SameHostDaemon) 114 testIpcNonePrivateShareable(c, "shareable", true, true) 115 } 116 117 // testIpcContainer is a helper function to test --ipc container:NNN mode in various scenarios 118 func testIpcContainer(s *DockerSuite, c *check.C, donorMode string, mustWork bool) { 119 cfg := container.Config{ 120 Image: "busybox", 121 Cmd: []string{"top"}, 122 } 123 hostCfg := container.HostConfig{ 124 IpcMode: container.IpcMode(donorMode), 125 } 126 ctx := context.Background() 127 128 client, err := request.NewClient() 129 c.Assert(err, checker.IsNil) 130 131 // create and start the "donor" container 132 resp, err := client.ContainerCreate(ctx, &cfg, &hostCfg, nil, "") 133 c.Assert(err, checker.IsNil) 134 c.Assert(len(resp.Warnings), checker.Equals, 0) 135 name1 := resp.ID 136 137 err = client.ContainerStart(ctx, name1, types.ContainerStartOptions{}) 138 c.Assert(err, checker.IsNil) 139 140 // create and start the second container 141 hostCfg.IpcMode = container.IpcMode("container:" + name1) 142 resp, err = client.ContainerCreate(ctx, &cfg, &hostCfg, nil, "") 143 c.Assert(err, checker.IsNil) 144 c.Assert(len(resp.Warnings), checker.Equals, 0) 145 name2 := resp.ID 146 147 err = client.ContainerStart(ctx, name2, types.ContainerStartOptions{}) 148 if !mustWork { 149 // start should fail with a specific error 150 c.Assert(err, checker.NotNil) 151 c.Assert(fmt.Sprintf("%v", err), checker.Contains, "non-shareable IPC") 152 // no more checks to perform here 153 return 154 } 155 156 // start should succeed 157 c.Assert(err, checker.IsNil) 158 159 // check that IPC is shared 160 // 1. create a file in the first container 161 cli.DockerCmd(c, "exec", name1, "sh", "-c", "printf covfefe > /dev/shm/bar") 162 // 2. check it's the same file in the second one 163 out := cli.DockerCmd(c, "exec", "-i", name2, "cat", "/dev/shm/bar").Combined() 164 c.Assert(out, checker.Matches, "^covfefe$") 165 } 166 167 /* TestAPIIpcModeShareableAndContainer checks that a container created with 168 * --ipc container:ID can use IPC of another shareable container. 169 */ 170 func (s *DockerSuite) TestAPIIpcModeShareableAndContainer(c *check.C) { 171 testRequires(c, DaemonIsLinux) 172 testIpcContainer(s, c, "shareable", true) 173 } 174 175 /* TestAPIIpcModePrivateAndContainer checks that a container created with 176 * --ipc container:ID can NOT use IPC of another private container. 177 */ 178 func (s *DockerSuite) TestAPIIpcModePrivateAndContainer(c *check.C) { 179 testRequires(c, DaemonIsLinux) 180 testIpcContainer(s, c, "private", false) 181 } 182 183 /* TestAPIIpcModeHost checks that a container created with --ipc host 184 * can use IPC of the host system. 185 */ 186 func (s *DockerSuite) TestAPIIpcModeHost(c *check.C) { 187 testRequires(c, DaemonIsLinux, SameHostDaemon, NotUserNamespace) 188 189 cfg := container.Config{ 190 Image: "busybox", 191 Cmd: []string{"top"}, 192 } 193 hostCfg := container.HostConfig{ 194 IpcMode: container.IpcMode("host"), 195 } 196 ctx := context.Background() 197 198 client, err := request.NewClient() 199 c.Assert(err, checker.IsNil) 200 201 resp, err := client.ContainerCreate(ctx, &cfg, &hostCfg, nil, "") 202 c.Assert(err, checker.IsNil) 203 c.Assert(len(resp.Warnings), checker.Equals, 0) 204 name := resp.ID 205 206 err = client.ContainerStart(ctx, name, types.ContainerStartOptions{}) 207 c.Assert(err, checker.IsNil) 208 209 // check that IPC is shared 210 // 1. create a file inside container 211 cli.DockerCmd(c, "exec", name, "sh", "-c", "printf covfefe > /dev/shm/."+name) 212 // 2. check it's the same on the host 213 bytes, err := ioutil.ReadFile("/dev/shm/." + name) 214 c.Assert(err, checker.IsNil) 215 c.Assert(string(bytes), checker.Matches, "^covfefe$") 216 // 3. clean up 217 cli.DockerCmd(c, "exec", name, "rm", "-f", "/dev/shm/."+name) 218 }