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  }