github.com/rita33cool1/iot-system-gateway@v0.0.0-20200911033302-e65bde238cc5/docker-engine/integration/container/mounts_linux_test.go (about)

     1  package container // import "github.com/docker/docker/integration/container"
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"path/filepath"
     7  	"testing"
     8  
     9  	"github.com/docker/docker/api/types"
    10  	"github.com/docker/docker/api/types/container"
    11  	"github.com/docker/docker/api/types/mount"
    12  	"github.com/docker/docker/api/types/network"
    13  	"github.com/docker/docker/client"
    14  	"github.com/docker/docker/integration/internal/request"
    15  	"github.com/docker/docker/pkg/system"
    16  	"github.com/gotestyourself/gotestyourself/assert"
    17  	is "github.com/gotestyourself/gotestyourself/assert/cmp"
    18  	"github.com/gotestyourself/gotestyourself/fs"
    19  	"github.com/gotestyourself/gotestyourself/skip"
    20  )
    21  
    22  func TestContainerNetworkMountsNoChown(t *testing.T) {
    23  	// chown only applies to Linux bind mounted volumes; must be same host to verify
    24  	skip.If(t, testEnv.DaemonInfo.OSType != "linux" || testEnv.IsRemoteDaemon())
    25  
    26  	defer setupTest(t)()
    27  
    28  	ctx := context.Background()
    29  
    30  	tmpDir := fs.NewDir(t, "network-file-mounts", fs.WithMode(0755), fs.WithFile("nwfile", "network file bind mount", fs.WithMode(0644)))
    31  	defer tmpDir.Remove()
    32  
    33  	tmpNWFileMount := tmpDir.Join("nwfile")
    34  
    35  	config := container.Config{
    36  		Image: "busybox",
    37  	}
    38  	hostConfig := container.HostConfig{
    39  		Mounts: []mount.Mount{
    40  			{
    41  				Type:   "bind",
    42  				Source: tmpNWFileMount,
    43  				Target: "/etc/resolv.conf",
    44  			},
    45  			{
    46  				Type:   "bind",
    47  				Source: tmpNWFileMount,
    48  				Target: "/etc/hostname",
    49  			},
    50  			{
    51  				Type:   "bind",
    52  				Source: tmpNWFileMount,
    53  				Target: "/etc/hosts",
    54  			},
    55  		},
    56  	}
    57  
    58  	cli, err := client.NewEnvClient()
    59  	assert.NilError(t, err)
    60  	defer cli.Close()
    61  
    62  	ctrCreate, err := cli.ContainerCreate(ctx, &config, &hostConfig, &network.NetworkingConfig{}, "")
    63  	assert.NilError(t, err)
    64  	// container will exit immediately because of no tty, but we only need the start sequence to test the condition
    65  	err = cli.ContainerStart(ctx, ctrCreate.ID, types.ContainerStartOptions{})
    66  	assert.NilError(t, err)
    67  
    68  	// Check that host-located bind mount network file did not change ownership when the container was started
    69  	// Note: If the user specifies a mountpath from the host, we should not be
    70  	// attempting to chown files outside the daemon's metadata directory
    71  	// (represented by `daemon.repository` at init time).
    72  	// This forces users who want to use user namespaces to handle the
    73  	// ownership needs of any external files mounted as network files
    74  	// (/etc/resolv.conf, /etc/hosts, /etc/hostname) separately from the
    75  	// daemon. In all other volume/bind mount situations we have taken this
    76  	// same line--we don't chown host file content.
    77  	// See GitHub PR 34224 for details.
    78  	statT, err := system.Stat(tmpNWFileMount)
    79  	assert.NilError(t, err)
    80  	assert.Check(t, is.Equal(uint32(0), statT.UID()), "bind mounted network file should not change ownership from root")
    81  }
    82  
    83  func TestMountDaemonRoot(t *testing.T) {
    84  	skip.If(t, testEnv.DaemonInfo.OSType != "linux" || testEnv.IsRemoteDaemon())
    85  	t.Parallel()
    86  
    87  	client := request.NewAPIClient(t)
    88  	ctx := context.Background()
    89  	info, err := client.Info(ctx)
    90  	if err != nil {
    91  		t.Fatal(err)
    92  	}
    93  
    94  	for _, test := range []struct {
    95  		desc        string
    96  		propagation mount.Propagation
    97  		expected    mount.Propagation
    98  	}{
    99  		{
   100  			desc:        "default",
   101  			propagation: "",
   102  			expected:    mount.PropagationRSlave,
   103  		},
   104  		{
   105  			desc:        "private",
   106  			propagation: mount.PropagationPrivate,
   107  		},
   108  		{
   109  			desc:        "rprivate",
   110  			propagation: mount.PropagationRPrivate,
   111  		},
   112  		{
   113  			desc:        "slave",
   114  			propagation: mount.PropagationSlave,
   115  		},
   116  		{
   117  			desc:        "rslave",
   118  			propagation: mount.PropagationRSlave,
   119  			expected:    mount.PropagationRSlave,
   120  		},
   121  		{
   122  			desc:        "shared",
   123  			propagation: mount.PropagationShared,
   124  		},
   125  		{
   126  			desc:        "rshared",
   127  			propagation: mount.PropagationRShared,
   128  			expected:    mount.PropagationRShared,
   129  		},
   130  	} {
   131  		t.Run(test.desc, func(t *testing.T) {
   132  			test := test
   133  			t.Parallel()
   134  
   135  			propagationSpec := fmt.Sprintf(":%s", test.propagation)
   136  			if test.propagation == "" {
   137  				propagationSpec = ""
   138  			}
   139  			bindSpecRoot := info.DockerRootDir + ":" + "/foo" + propagationSpec
   140  			bindSpecSub := filepath.Join(info.DockerRootDir, "containers") + ":/foo" + propagationSpec
   141  
   142  			for name, hc := range map[string]*container.HostConfig{
   143  				"bind root":    {Binds: []string{bindSpecRoot}},
   144  				"bind subpath": {Binds: []string{bindSpecSub}},
   145  				"mount root": {
   146  					Mounts: []mount.Mount{
   147  						{
   148  							Type:        mount.TypeBind,
   149  							Source:      info.DockerRootDir,
   150  							Target:      "/foo",
   151  							BindOptions: &mount.BindOptions{Propagation: test.propagation},
   152  						},
   153  					},
   154  				},
   155  				"mount subpath": {
   156  					Mounts: []mount.Mount{
   157  						{
   158  							Type:        mount.TypeBind,
   159  							Source:      filepath.Join(info.DockerRootDir, "containers"),
   160  							Target:      "/foo",
   161  							BindOptions: &mount.BindOptions{Propagation: test.propagation},
   162  						},
   163  					},
   164  				},
   165  			} {
   166  				t.Run(name, func(t *testing.T) {
   167  					hc := hc
   168  					t.Parallel()
   169  
   170  					c, err := client.ContainerCreate(ctx, &container.Config{
   171  						Image: "busybox",
   172  						Cmd:   []string{"true"},
   173  					}, hc, nil, "")
   174  
   175  					if err != nil {
   176  						if test.expected != "" {
   177  							t.Fatal(err)
   178  						}
   179  						// expected an error, so this is ok and should not continue
   180  						return
   181  					}
   182  					if test.expected == "" {
   183  						t.Fatal("expected create to fail")
   184  					}
   185  
   186  					defer func() {
   187  						if err := client.ContainerRemove(ctx, c.ID, types.ContainerRemoveOptions{Force: true}); err != nil {
   188  							panic(err)
   189  						}
   190  					}()
   191  
   192  					inspect, err := client.ContainerInspect(ctx, c.ID)
   193  					if err != nil {
   194  						t.Fatal(err)
   195  					}
   196  					if len(inspect.Mounts) != 1 {
   197  						t.Fatalf("unexpected number of mounts: %+v", inspect.Mounts)
   198  					}
   199  
   200  					m := inspect.Mounts[0]
   201  					if m.Propagation != test.expected {
   202  						t.Fatalf("got unexpected propagation mode, expected %q, got: %v", test.expected, m.Propagation)
   203  					}
   204  				})
   205  			}
   206  		})
   207  	}
   208  }