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 }