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