github.com/wozhu6104/docker@v20.10.10+incompatible/daemon/daemon_linux_test.go (about) 1 // +build linux 2 3 package daemon // import "github.com/docker/docker/daemon" 4 5 import ( 6 "io/ioutil" 7 "os" 8 "path/filepath" 9 "strings" 10 "testing" 11 12 containertypes "github.com/docker/docker/api/types/container" 13 "github.com/docker/docker/daemon/config" 14 "github.com/moby/sys/mount" 15 "github.com/moby/sys/mountinfo" 16 "gotest.tools/v3/assert" 17 is "gotest.tools/v3/assert/cmp" 18 ) 19 20 const mountsFixture = `142 78 0:38 / / rw,relatime - aufs none rw,si=573b861da0b3a05b,dio 21 143 142 0:60 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw 22 144 142 0:67 / /dev rw,nosuid - tmpfs tmpfs rw,mode=755 23 145 144 0:78 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=666 24 146 144 0:49 / /dev/mqueue rw,nosuid,nodev,noexec,relatime - mqueue mqueue rw 25 147 142 0:84 / /sys rw,nosuid,nodev,noexec,relatime - sysfs sysfs rw 26 148 147 0:86 / /sys/fs/cgroup rw,nosuid,nodev,noexec,relatime - tmpfs tmpfs rw,mode=755 27 149 148 0:22 /docker/5425782a95e643181d8a485a2bab3c0bb21f51d7dfc03511f0e6fbf3f3aa356a /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,cpuset 28 150 148 0:25 /docker/5425782a95e643181d8a485a2bab3c0bb21f51d7dfc03511f0e6fbf3f3aa356a /sys/fs/cgroup/cpu rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,cpu 29 151 148 0:27 /docker/5425782a95e643181d8a485a2bab3c0bb21f51d7dfc03511f0e6fbf3f3aa356a /sys/fs/cgroup/cpuacct rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,cpuacct 30 152 148 0:28 /docker/5425782a95e643181d8a485a2bab3c0bb21f51d7dfc03511f0e6fbf3f3aa356a /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,memory 31 153 148 0:29 /docker/5425782a95e643181d8a485a2bab3c0bb21f51d7dfc03511f0e6fbf3f3aa356a /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,devices 32 154 148 0:30 /docker/5425782a95e643181d8a485a2bab3c0bb21f51d7dfc03511f0e6fbf3f3aa356a /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,freezer 33 155 148 0:31 /docker/5425782a95e643181d8a485a2bab3c0bb21f51d7dfc03511f0e6fbf3f3aa356a /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,blkio 34 156 148 0:32 /docker/5425782a95e643181d8a485a2bab3c0bb21f51d7dfc03511f0e6fbf3f3aa356a /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,perf_event 35 157 148 0:33 /docker/5425782a95e643181d8a485a2bab3c0bb21f51d7dfc03511f0e6fbf3f3aa356a /sys/fs/cgroup/hugetlb rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,hugetlb 36 158 148 0:35 /docker/5425782a95e643181d8a485a2bab3c0bb21f51d7dfc03511f0e6fbf3f3aa356a /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime - cgroup systemd rw,name=systemd 37 159 142 8:4 /home/mlaventure/gopath /home/mlaventure/gopath rw,relatime - ext4 /dev/disk/by-uuid/d99e196c-1fc4-4b4f-bab9-9962b2b34e99 rw,errors=remount-ro,data=ordered 38 160 142 8:4 /var/lib/docker/volumes/9a428b651ee4c538130143cad8d87f603a4bf31b928afe7ff3ecd65480692b35/_data /var/lib/docker rw,relatime - ext4 /dev/disk/by-uuid/d99e196c-1fc4-4b4f-bab9-9962b2b34e99 rw,errors=remount-ro,data=ordered 39 164 142 8:4 /home/mlaventure/gopath/src/github.com/docker/docker /go/src/github.com/docker/docker rw,relatime - ext4 /dev/disk/by-uuid/d99e196c-1fc4-4b4f-bab9-9962b2b34e99 rw,errors=remount-ro,data=ordered 40 165 142 8:4 /var/lib/docker/containers/5425782a95e643181d8a485a2bab3c0bb21f51d7dfc03511f0e6fbf3f3aa356a/resolv.conf /etc/resolv.conf rw,relatime - ext4 /dev/disk/by-uuid/d99e196c-1fc4-4b4f-bab9-9962b2b34e99 rw,errors=remount-ro,data=ordered 41 166 142 8:4 /var/lib/docker/containers/5425782a95e643181d8a485a2bab3c0bb21f51d7dfc03511f0e6fbf3f3aa356a/hostname /etc/hostname rw,relatime - ext4 /dev/disk/by-uuid/d99e196c-1fc4-4b4f-bab9-9962b2b34e99 rw,errors=remount-ro,data=ordered 42 167 142 8:4 /var/lib/docker/containers/5425782a95e643181d8a485a2bab3c0bb21f51d7dfc03511f0e6fbf3f3aa356a/hosts /etc/hosts rw,relatime - ext4 /dev/disk/by-uuid/d99e196c-1fc4-4b4f-bab9-9962b2b34e99 rw,errors=remount-ro,data=ordered 43 168 144 0:39 / /dev/shm rw,nosuid,nodev,noexec,relatime - tmpfs shm rw,size=65536k 44 169 144 0:12 /14 /dev/console rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=000 45 83 147 0:10 / /sys/kernel/security rw,relatime - securityfs none rw 46 89 142 0:87 / /tmp rw,relatime - tmpfs none rw 47 97 142 0:60 / /run/docker/netns/default rw,nosuid,nodev,noexec,relatime - proc proc rw 48 100 160 8:4 /var/lib/docker/volumes/9a428b651ee4c538130143cad8d87f603a4bf31b928afe7ff3ecd65480692b35/_data/aufs /var/lib/docker/aufs rw,relatime - ext4 /dev/disk/by-uuid/d99e196c-1fc4-4b4f-bab9-9962b2b34e99 rw,errors=remount-ro,data=ordered 49 115 100 0:102 / /var/lib/docker/aufs/mnt/0ecda1c63e5b58b3d89ff380bf646c95cc980252cf0b52466d43619aec7c8432 rw,relatime - aufs none rw,si=573b861dbc01905b,dio 50 116 160 0:107 / /var/lib/docker/containers/d045dc441d2e2e1d5b3e328d47e5943811a40819fb47497c5f5a5df2d6d13c37/shm rw,nosuid,nodev,noexec,relatime - tmpfs shm rw,size=65536k 51 118 142 0:102 / /run/docker/libcontainerd/d045dc441d2e2e1d5b3e328d47e5943811a40819fb47497c5f5a5df2d6d13c37/rootfs rw,relatime - aufs none rw,si=573b861dbc01905b,dio 52 242 142 0:60 / /run/docker/netns/c3664df2a0f7 rw,nosuid,nodev,noexec,relatime - proc proc rw 53 120 100 0:122 / /var/lib/docker/aufs/mnt/03ca4b49e71f1e49a41108829f4d5c70ac95934526e2af8984a1f65f1de0715d rw,relatime - aufs none rw,si=573b861eb147805b,dio 54 171 142 0:122 / /run/docker/libcontainerd/e406ff6f3e18516d50e03dbca4de54767a69a403a6f7ec1edc2762812824521e/rootfs rw,relatime - aufs none rw,si=573b861eb147805b,dio 55 310 142 0:60 / /run/docker/netns/71a18572176b rw,nosuid,nodev,noexec,relatime - proc proc rw 56 ` 57 58 func TestCleanupMounts(t *testing.T) { 59 d := &Daemon{ 60 root: "/var/lib/docker/", 61 } 62 63 expected := "/var/lib/docker/containers/d045dc441d2e2e1d5b3e328d47e5943811a40819fb47497c5f5a5df2d6d13c37/shm" 64 var unmounted int 65 unmount := func(target string) error { 66 if target == expected { 67 unmounted++ 68 } 69 return nil 70 } 71 72 d.cleanupMountsFromReaderByID(strings.NewReader(mountsFixture), "", unmount) 73 74 if unmounted != 1 { 75 t.Fatal("Expected to unmount the shm (and the shm only)") 76 } 77 } 78 79 func TestCleanupMountsByID(t *testing.T) { 80 d := &Daemon{ 81 root: "/var/lib/docker/", 82 } 83 84 expected := "/var/lib/docker/aufs/mnt/03ca4b49e71f1e49a41108829f4d5c70ac95934526e2af8984a1f65f1de0715d" 85 var unmounted int 86 unmount := func(target string) error { 87 if target == expected { 88 unmounted++ 89 } 90 return nil 91 } 92 93 d.cleanupMountsFromReaderByID(strings.NewReader(mountsFixture), "03ca4b49e71f1e49a41108829f4d5c70ac95934526e2af8984a1f65f1de0715d", unmount) 94 95 if unmounted != 1 { 96 t.Fatal("Expected to unmount the auf root (and that only)") 97 } 98 } 99 100 func TestNotCleanupMounts(t *testing.T) { 101 d := &Daemon{ 102 repository: "", 103 } 104 var unmounted bool 105 unmount := func(target string) error { 106 unmounted = true 107 return nil 108 } 109 mountInfo := `234 232 0:59 / /dev/shm rw,nosuid,nodev,noexec,relatime - tmpfs shm rw,size=65536k` 110 d.cleanupMountsFromReaderByID(strings.NewReader(mountInfo), "", unmount) 111 if unmounted { 112 t.Fatal("Expected not to clean up /dev/shm") 113 } 114 } 115 116 func TestValidateContainerIsolationLinux(t *testing.T) { 117 d := Daemon{} 118 119 _, err := d.verifyContainerSettings("linux", &containertypes.HostConfig{Isolation: containertypes.IsolationHyperV}, nil, false) 120 assert.Check(t, is.Error(err, "invalid isolation 'hyperv' on linux")) 121 } 122 123 func TestShouldUnmountRoot(t *testing.T) { 124 for _, test := range []struct { 125 desc string 126 root string 127 info *mountinfo.Info 128 expect bool 129 }{ 130 { 131 desc: "root is at /", 132 root: "/docker", 133 info: &mountinfo.Info{Root: "/docker", Mountpoint: "/docker"}, 134 expect: true, 135 }, 136 { 137 desc: "root is at in a submount from `/`", 138 root: "/foo/docker", 139 info: &mountinfo.Info{Root: "/docker", Mountpoint: "/foo/docker"}, 140 expect: true, 141 }, 142 { 143 desc: "root is mounted in from a parent mount namespace same root dir", // dind is an example of this 144 root: "/docker", 145 info: &mountinfo.Info{Root: "/docker/volumes/1234657/_data", Mountpoint: "/docker"}, 146 expect: false, 147 }, 148 } { 149 t.Run(test.desc, func(t *testing.T) { 150 for _, options := range []struct { 151 desc string 152 Optional string 153 expect bool 154 }{ 155 {desc: "shared", Optional: "shared:", expect: true}, 156 {desc: "slave", Optional: "slave:", expect: false}, 157 {desc: "private", Optional: "private:", expect: false}, 158 } { 159 t.Run(options.desc, func(t *testing.T) { 160 expect := options.expect 161 if expect { 162 expect = test.expect 163 } 164 if test.info != nil { 165 test.info.Optional = options.Optional 166 } 167 assert.Check(t, is.Equal(expect, shouldUnmountRoot(test.root, test.info))) 168 }) 169 } 170 }) 171 } 172 } 173 174 func checkMounted(t *testing.T, p string, expect bool) { 175 t.Helper() 176 mounted, err := mountinfo.Mounted(p) 177 assert.Check(t, err) 178 assert.Check(t, mounted == expect, "expected %v, actual %v", expect, mounted) 179 } 180 181 func TestRootMountCleanup(t *testing.T) { 182 if os.Getuid() != 0 { 183 t.Skip("root required") 184 } 185 186 t.Parallel() 187 188 testRoot, err := ioutil.TempDir("", t.Name()) 189 assert.NilError(t, err) 190 defer os.RemoveAll(testRoot) 191 cfg := &config.Config{} 192 193 err = mount.MakePrivate(testRoot) 194 assert.NilError(t, err) 195 defer mount.Unmount(testRoot) 196 197 cfg.ExecRoot = filepath.Join(testRoot, "exec") 198 cfg.Root = filepath.Join(testRoot, "daemon") 199 200 err = os.Mkdir(cfg.ExecRoot, 0755) 201 assert.NilError(t, err) 202 err = os.Mkdir(cfg.Root, 0755) 203 assert.NilError(t, err) 204 205 d := &Daemon{configStore: cfg, root: cfg.Root} 206 unmountFile := getUnmountOnShutdownPath(cfg) 207 208 t.Run("regular dir no mountpoint", func(t *testing.T) { 209 err = setupDaemonRootPropagation(cfg) 210 assert.NilError(t, err) 211 _, err = os.Stat(unmountFile) 212 assert.NilError(t, err) 213 checkMounted(t, cfg.Root, true) 214 215 assert.Assert(t, d.cleanupMounts()) 216 checkMounted(t, cfg.Root, false) 217 218 _, err = os.Stat(unmountFile) 219 assert.Assert(t, os.IsNotExist(err)) 220 }) 221 222 t.Run("root is a private mountpoint", func(t *testing.T) { 223 err = mount.MakePrivate(cfg.Root) 224 assert.NilError(t, err) 225 defer mount.Unmount(cfg.Root) 226 227 err = setupDaemonRootPropagation(cfg) 228 assert.NilError(t, err) 229 assert.Check(t, ensureShared(cfg.Root)) 230 231 _, err = os.Stat(unmountFile) 232 assert.Assert(t, os.IsNotExist(err)) 233 assert.Assert(t, d.cleanupMounts()) 234 checkMounted(t, cfg.Root, true) 235 }) 236 237 // mount is pre-configured with a shared mount 238 t.Run("root is a shared mountpoint", func(t *testing.T) { 239 err = mount.MakeShared(cfg.Root) 240 assert.NilError(t, err) 241 defer mount.Unmount(cfg.Root) 242 243 err = setupDaemonRootPropagation(cfg) 244 assert.NilError(t, err) 245 246 if _, err := os.Stat(unmountFile); err == nil { 247 t.Fatal("unmount file should not exist") 248 } 249 250 assert.Assert(t, d.cleanupMounts()) 251 checkMounted(t, cfg.Root, true) 252 assert.Assert(t, mount.Unmount(cfg.Root)) 253 }) 254 255 // does not need mount but unmount file exists from previous run 256 t.Run("old mount file is cleaned up on setup if not needed", func(t *testing.T) { 257 err = mount.MakeShared(testRoot) 258 assert.NilError(t, err) 259 defer mount.MakePrivate(testRoot) 260 err = ioutil.WriteFile(unmountFile, nil, 0644) 261 assert.NilError(t, err) 262 263 err = setupDaemonRootPropagation(cfg) 264 assert.NilError(t, err) 265 266 _, err = os.Stat(unmountFile) 267 assert.Check(t, os.IsNotExist(err), err) 268 checkMounted(t, cfg.Root, false) 269 assert.Assert(t, d.cleanupMounts()) 270 }) 271 272 }