github.com/moby/docker@v26.1.3+incompatible/daemon/daemon_linux_test.go (about) 1 //go:build linux 2 3 package daemon // import "github.com/docker/docker/daemon" 4 5 import ( 6 "net" 7 "os" 8 "path/filepath" 9 "strings" 10 "testing" 11 12 containertypes "github.com/docker/docker/api/types/container" 13 "github.com/docker/docker/internal/testutils/netnsutils" 14 "github.com/docker/docker/libnetwork/types" 15 "github.com/google/go-cmp/cmp/cmpopts" 16 "github.com/moby/sys/mount" 17 "github.com/moby/sys/mountinfo" 18 "github.com/vishvananda/netlink" 19 "gotest.tools/v3/assert" 20 is "gotest.tools/v3/assert/cmp" 21 ) 22 23 //nolint:dupword 24 const mountsFixture = `142 78 0:38 / / rw,relatime - aufs none rw,si=573b861da0b3a05b,dio 25 143 142 0:60 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw 26 144 142 0:67 / /dev rw,nosuid - tmpfs tmpfs rw,mode=755 27 145 144 0:78 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=666 28 146 144 0:49 / /dev/mqueue rw,nosuid,nodev,noexec,relatime - mqueue mqueue rw 29 147 142 0:84 / /sys rw,nosuid,nodev,noexec,relatime - sysfs sysfs rw 30 148 147 0:86 / /sys/fs/cgroup rw,nosuid,nodev,noexec,relatime - tmpfs tmpfs rw,mode=755 31 149 148 0:22 /docker/5425782a95e643181d8a485a2bab3c0bb21f51d7dfc03511f0e6fbf3f3aa356a /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,cpuset 32 150 148 0:25 /docker/5425782a95e643181d8a485a2bab3c0bb21f51d7dfc03511f0e6fbf3f3aa356a /sys/fs/cgroup/cpu rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,cpu 33 151 148 0:27 /docker/5425782a95e643181d8a485a2bab3c0bb21f51d7dfc03511f0e6fbf3f3aa356a /sys/fs/cgroup/cpuacct rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,cpuacct 34 152 148 0:28 /docker/5425782a95e643181d8a485a2bab3c0bb21f51d7dfc03511f0e6fbf3f3aa356a /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,memory 35 153 148 0:29 /docker/5425782a95e643181d8a485a2bab3c0bb21f51d7dfc03511f0e6fbf3f3aa356a /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,devices 36 154 148 0:30 /docker/5425782a95e643181d8a485a2bab3c0bb21f51d7dfc03511f0e6fbf3f3aa356a /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,freezer 37 155 148 0:31 /docker/5425782a95e643181d8a485a2bab3c0bb21f51d7dfc03511f0e6fbf3f3aa356a /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,blkio 38 156 148 0:32 /docker/5425782a95e643181d8a485a2bab3c0bb21f51d7dfc03511f0e6fbf3f3aa356a /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,perf_event 39 157 148 0:33 /docker/5425782a95e643181d8a485a2bab3c0bb21f51d7dfc03511f0e6fbf3f3aa356a /sys/fs/cgroup/hugetlb rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,hugetlb 40 158 148 0:35 /docker/5425782a95e643181d8a485a2bab3c0bb21f51d7dfc03511f0e6fbf3f3aa356a /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime - cgroup systemd rw,name=systemd 41 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 42 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 43 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 44 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 45 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 46 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 47 168 144 0:39 / /dev/shm rw,nosuid,nodev,noexec,relatime - tmpfs shm rw,size=65536k 48 169 144 0:12 /14 /dev/console rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=000 49 83 147 0:10 / /sys/kernel/security rw,relatime - securityfs none rw 50 89 142 0:87 / /tmp rw,relatime - tmpfs none rw 51 97 142 0:60 / /run/docker/netns/default rw,nosuid,nodev,noexec,relatime - proc proc rw 52 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 53 115 100 0:102 / /var/lib/docker/aufs/mnt/0ecda1c63e5b58b3d89ff380bf646c95cc980252cf0b52466d43619aec7c8432 rw,relatime - aufs none rw,si=573b861dbc01905b,dio 54 116 160 0:107 / /var/lib/docker/containers/d045dc441d2e2e1d5b3e328d47e5943811a40819fb47497c5f5a5df2d6d13c37/shm rw,nosuid,nodev,noexec,relatime - tmpfs shm rw,size=65536k 55 118 142 0:102 / /run/docker/libcontainerd/d045dc441d2e2e1d5b3e328d47e5943811a40819fb47497c5f5a5df2d6d13c37/rootfs rw,relatime - aufs none rw,si=573b861dbc01905b,dio 56 242 142 0:60 / /run/docker/netns/c3664df2a0f7 rw,nosuid,nodev,noexec,relatime - proc proc rw 57 120 100 0:122 / /var/lib/docker/aufs/mnt/03ca4b49e71f1e49a41108829f4d5c70ac95934526e2af8984a1f65f1de0715d rw,relatime - aufs none rw,si=573b861eb147805b,dio 58 171 142 0:122 / /run/docker/libcontainerd/e406ff6f3e18516d50e03dbca4de54767a69a403a6f7ec1edc2762812824521e/rootfs rw,relatime - aufs none rw,si=573b861eb147805b,dio 59 310 142 0:60 / /run/docker/netns/71a18572176b rw,nosuid,nodev,noexec,relatime - proc proc rw 60 ` 61 62 //nolint:dupword 63 const mountsFixtureOverlay2 = `23 28 0:22 / /sys rw,nosuid,nodev,noexec,relatime shared:7 - sysfs sysfs rw 64 24 28 0:4 / /proc rw,nosuid,nodev,noexec,relatime shared:13 - proc proc rw 65 25 28 0:6 / /dev rw,nosuid,relatime shared:2 - devtmpfs udev rw,size=491380k,nr_inodes=122845,mode=755 66 26 25 0:23 / /dev/pts rw,nosuid,noexec,relatime shared:3 - devpts devpts rw,gid=5,mode=620,ptmxmode=000 67 27 28 0:24 / /run rw,nosuid,noexec,relatime shared:5 - tmpfs tmpfs rw,size=100884k,mode=755 68 28 0 252:1 / / rw,relatime shared:1 - ext4 /dev/vda1 rw,data=ordered 69 29 23 0:7 / /sys/kernel/security rw,nosuid,nodev,noexec,relatime shared:8 - securityfs securityfs rw 70 30 25 0:25 / /dev/shm rw,nosuid,nodev shared:4 - tmpfs tmpfs rw 71 31 27 0:26 / /run/lock rw,nosuid,nodev,noexec,relatime shared:6 - tmpfs tmpfs rw,size=5120k 72 32 23 0:27 / /sys/fs/cgroup ro,nosuid,nodev,noexec shared:9 - tmpfs tmpfs ro,mode=755 73 33 32 0:28 / /sys/fs/cgroup/unified rw,nosuid,nodev,noexec,relatime shared:10 - cgroup2 cgroup rw 74 34 32 0:29 / /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime shared:11 - cgroup cgroup rw,xattr,name=systemd 75 35 23 0:30 / /sys/fs/pstore rw,nosuid,nodev,noexec,relatime shared:12 - pstore pstore rw 76 36 32 0:31 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime shared:14 - cgroup cgroup rw,blkio 77 37 32 0:32 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:15 - cgroup cgroup rw,memory 78 38 32 0:33 / /sys/fs/cgroup/hugetlb rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,hugetlb 79 39 32 0:34 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime shared:17 - cgroup cgroup rw,freezer 80 40 32 0:35 / /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime shared:18 - cgroup cgroup rw,perf_event 81 41 32 0:36 / /sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime shared:19 - cgroup cgroup rw,pids 82 42 32 0:37 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:20 - cgroup cgroup rw,cpuset 83 43 32 0:38 / /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime shared:21 - cgroup cgroup rw,cpu,cpuacct 84 44 32 0:39 / /sys/fs/cgroup/rdma rw,nosuid,nodev,noexec,relatime shared:22 - cgroup cgroup rw,rdma 85 45 32 0:40 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime shared:23 - cgroup cgroup rw,devices 86 46 32 0:41 / /sys/fs/cgroup/net_cls,net_prio rw,nosuid,nodev,noexec,relatime shared:24 - cgroup cgroup rw,net_cls,net_prio 87 47 24 0:42 / /proc/sys/fs/binfmt_misc rw,relatime shared:25 - autofs systemd-1 rw,fd=33,pgrp=1,timeout=0,minproto=5,maxproto=5,direct,pipe_ino=11725 88 48 23 0:8 / /sys/kernel/debug rw,relatime shared:26 - debugfs debugfs rw 89 49 25 0:19 / /dev/mqueue rw,relatime shared:27 - mqueue mqueue rw 90 50 25 0:43 / /dev/hugepages rw,relatime shared:28 - hugetlbfs hugetlbfs rw,pagesize=2M 91 80 23 0:20 / /sys/kernel/config rw,relatime shared:29 - configfs configfs rw 92 82 23 0:44 / /sys/fs/fuse/connections rw,relatime shared:30 - fusectl fusectl rw 93 84 28 252:15 / /boot/efi rw,relatime shared:31 - vfat /dev/vda15 rw,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro 94 391 28 0:49 / /var/lib/lxcfs rw,nosuid,nodev,relatime shared:208 - fuse.lxcfs lxcfs rw,user_id=0,group_id=0,allow_other 95 401 48 0:11 / /sys/kernel/debug/tracing rw,relatime shared:213 - tracefs tracefs rw 96 421 47 0:93 / /proc/sys/fs/binfmt_misc rw,relatime shared:223 - binfmt_misc binfmt_misc rw 97 510 27 0:3 net:[4026531993] /run/docker/netns/default rw shared:255 - nsfs nsfs rw 98 60 27 0:3 net:[4026532265] /run/docker/netns/ingress_sbox rw shared:40 - nsfs nsfs rw 99 162 27 0:3 net:[4026532331] /run/docker/netns/1-bj0aarwy1n rw shared:41 - nsfs nsfs rw 100 450 28 0:51 / /var/lib/docker/overlay2/3a4b807fcb98c208573f368c5654a6568545a7f92404a07d0045eb5c85acaf67/merged rw,relatime shared:231 - overlay overlay rw,lowerdir=/var/lib/docker/overlay2/l/E6KNVZ2QUCIXY5VT7E5LO3PVCA:/var/lib/docker/overlay2/l/64XI57TRGG6QS4K6DCSREZXBN2:/var/lib/docker/overlay2/l/TWXZ4ANJR6BDLDZMWZ4Y6AICAR:/var/lib/docker/overlay2/l/VRLSNSG3PKZELC5O66TVTQ7EH5:/var/lib/docker/overlay2/l/HOLV4F57X56TRLVACMRLFVW7YD:/var/lib/docker/overlay2/l/JJQFBBBT6LWLQS35XBADV6BLAM:/var/lib/docker/overlay2/l/FZTPKHZGP2Z6DBPFEEL2IK3I5Y,upperdir=/var/lib/docker/overlay2/3a4b807fcb98c208573f368c5654a6568545a7f92404a07d0045eb5c85acaf67/diff,workdir=/var/lib/docker/overlay2/3a4b807fcb98c208573f368c5654a6568545a7f92404a07d0045eb5c85acaf67/work 101 569 27 0:3 net:[4026532353] /run/docker/netns/7de1071d0d8b rw shared:245 - nsfs nsfs rw 102 245 27 0:50 / /run/user/0 rw,nosuid,nodev,relatime shared:160 - tmpfs tmpfs rw,size=100880k,mode=700 103 482 28 0:69 / /var/lib/docker/overlay2/df4ee7b0bac7bda30e6e3d24a1153b288ebda50ffe68aae7ae0f38bc9286a01a/merged rw,relatime shared:250 - overlay overlay rw,lowerdir=/var/lib/docker/overlay2/l/CNZ3ATGGHMUTPPJBBU2OL4GLL6:/var/lib/docker/overlay2/l/64XI57TRGG6QS4K6DCSREZXBN2:/var/lib/docker/overlay2/l/TWXZ4ANJR6BDLDZMWZ4Y6AICAR:/var/lib/docker/overlay2/l/VRLSNSG3PKZELC5O66TVTQ7EH5:/var/lib/docker/overlay2/l/HOLV4F57X56TRLVACMRLFVW7YD:/var/lib/docker/overlay2/l/JJQFBBBT6LWLQS35XBADV6BLAM:/var/lib/docker/overlay2/l/FZTPKHZGP2Z6DBPFEEL2IK3I5Y,upperdir=/var/lib/docker/overlay2/df4ee7b0bac7bda30e6e3d24a1153b288ebda50ffe68aae7ae0f38bc9286a01a/diff,workdir=/var/lib/docker/overlay2/df4ee7b0bac7bda30e6e3d24a1153b288ebda50ffe68aae7ae0f38bc9286a01a/work 104 528 28 0:77 / /var/lib/docker/containers/404a7f860e600bfc144f7b5d9140d80bf3072fbb97659f98bc47039fd73d2695/mounts/shm rw,nosuid,nodev,noexec,relatime shared:260 - tmpfs shm rw,size=65536k 105 649 27 0:3 net:[4026532429] /run/docker/netns/7f85bc5ef3ba rw shared:265 - nsfs nsfs rw 106 ` 107 108 func TestCleanupMounts(t *testing.T) { 109 d := &Daemon{ 110 root: "/var/lib/docker/", 111 } 112 113 t.Run("aufs", func(t *testing.T) { 114 expected := "/var/lib/docker/containers/d045dc441d2e2e1d5b3e328d47e5943811a40819fb47497c5f5a5df2d6d13c37/shm" 115 var unmounted int 116 unmount := func(target string) error { 117 if target == expected { 118 unmounted++ 119 } 120 return nil 121 } 122 123 err := d.cleanupMountsFromReaderByID(strings.NewReader(mountsFixture), "", unmount) 124 assert.NilError(t, err) 125 assert.Equal(t, unmounted, 1, "Expected to unmount the shm (and the shm only)") 126 }) 127 128 t.Run("overlay2", func(t *testing.T) { 129 expected := "/var/lib/docker/containers/404a7f860e600bfc144f7b5d9140d80bf3072fbb97659f98bc47039fd73d2695/mounts/shm" 130 var unmounted int 131 unmount := func(target string) error { 132 if target == expected { 133 unmounted++ 134 } 135 return nil 136 } 137 138 err := d.cleanupMountsFromReaderByID(strings.NewReader(mountsFixtureOverlay2), "", unmount) 139 assert.NilError(t, err) 140 assert.Equal(t, unmounted, 1, "Expected to unmount the shm (and the shm only)") 141 }) 142 } 143 144 func TestCleanupMountsByID(t *testing.T) { 145 d := &Daemon{ 146 root: "/var/lib/docker/", 147 } 148 t.Run("overlay2", func(t *testing.T) { 149 expected := "/var/lib/docker/overlay2/3a4b807fcb98c208573f368c5654a6568545a7f92404a07d0045eb5c85acaf67/merged" 150 var unmounted int 151 unmount := func(target string) error { 152 if target == expected { 153 unmounted++ 154 } 155 return nil 156 } 157 158 err := d.cleanupMountsFromReaderByID(strings.NewReader(mountsFixtureOverlay2), "3a4b807fcb98c208573f368c5654a6568545a7f92404a07d0045eb5c85acaf67", unmount) 159 assert.NilError(t, err) 160 assert.Equal(t, unmounted, 1, "Expected to unmount the root (and that only)") 161 }) 162 } 163 164 func TestNotCleanupMounts(t *testing.T) { 165 d := &Daemon{ 166 repository: "", 167 } 168 var unmounted bool 169 unmount := func(target string) error { 170 unmounted = true 171 return nil 172 } 173 mountInfo := `234 232 0:59 / /dev/shm rw,nosuid,nodev,noexec,relatime - tmpfs shm rw,size=65536k` 174 err := d.cleanupMountsFromReaderByID(strings.NewReader(mountInfo), "", unmount) 175 assert.NilError(t, err) 176 assert.Equal(t, unmounted, false, "Expected not to clean up /dev/shm") 177 } 178 179 func TestValidateContainerIsolationLinux(t *testing.T) { 180 d := Daemon{} 181 182 _, err := d.verifyContainerSettings(&configStore{}, &containertypes.HostConfig{Isolation: containertypes.IsolationHyperV}, nil, false) 183 assert.Check(t, is.Error(err, "invalid isolation 'hyperv' on linux")) 184 } 185 186 func TestShouldUnmountRoot(t *testing.T) { 187 for _, test := range []struct { 188 desc string 189 root string 190 info *mountinfo.Info 191 expect bool 192 }{ 193 { 194 desc: "root is at /", 195 root: "/docker", 196 info: &mountinfo.Info{Root: "/docker", Mountpoint: "/docker"}, 197 expect: true, 198 }, 199 { 200 desc: "root is at in a submount from `/`", 201 root: "/foo/docker", 202 info: &mountinfo.Info{Root: "/docker", Mountpoint: "/foo/docker"}, 203 expect: true, 204 }, 205 { 206 desc: "root is mounted in from a parent mount namespace same root dir", // dind is an example of this 207 root: "/docker", 208 info: &mountinfo.Info{Root: "/docker/volumes/1234657/_data", Mountpoint: "/docker"}, 209 expect: false, 210 }, 211 } { 212 t.Run(test.desc, func(t *testing.T) { 213 for _, options := range []struct { 214 desc string 215 Optional string 216 expect bool 217 }{ 218 {desc: "shared", Optional: "shared:", expect: true}, 219 {desc: "slave", Optional: "slave:", expect: false}, 220 {desc: "private", Optional: "private:", expect: false}, 221 } { 222 t.Run(options.desc, func(t *testing.T) { 223 expect := options.expect 224 if expect { 225 expect = test.expect 226 } 227 if test.info != nil { 228 test.info.Optional = options.Optional 229 } 230 assert.Check(t, is.Equal(expect, shouldUnmountRoot(test.root, test.info))) 231 }) 232 } 233 }) 234 } 235 } 236 237 func checkMounted(t *testing.T, p string, expect bool) { 238 t.Helper() 239 mounted, err := mountinfo.Mounted(p) 240 assert.Check(t, err) 241 assert.Check(t, mounted == expect, "expected %v, actual %v", expect, mounted) 242 } 243 244 func TestRootMountCleanup(t *testing.T) { 245 if os.Getuid() != 0 { 246 t.Skip("root required") 247 } 248 249 t.Parallel() 250 251 testRoot, err := os.MkdirTemp("", t.Name()) 252 assert.NilError(t, err) 253 defer os.RemoveAll(testRoot) 254 cfg := &configStore{} 255 256 err = mount.MakePrivate(testRoot) 257 assert.NilError(t, err) 258 defer mount.Unmount(testRoot) 259 260 cfg.ExecRoot = filepath.Join(testRoot, "exec") 261 cfg.Root = filepath.Join(testRoot, "daemon") 262 263 err = os.Mkdir(cfg.ExecRoot, 0o755) 264 assert.NilError(t, err) 265 err = os.Mkdir(cfg.Root, 0o755) 266 assert.NilError(t, err) 267 268 d := &Daemon{root: cfg.Root} 269 d.configStore.Store(cfg) 270 unmountFile := getUnmountOnShutdownPath(&cfg.Config) 271 272 t.Run("regular dir no mountpoint", func(t *testing.T) { 273 err = setupDaemonRootPropagation(&cfg.Config) 274 assert.NilError(t, err) 275 _, err = os.Stat(unmountFile) 276 assert.NilError(t, err) 277 checkMounted(t, cfg.Root, true) 278 279 assert.Assert(t, d.cleanupMounts(&cfg.Config)) 280 checkMounted(t, cfg.Root, false) 281 282 _, err = os.Stat(unmountFile) 283 assert.Assert(t, os.IsNotExist(err)) 284 }) 285 286 t.Run("root is a private mountpoint", func(t *testing.T) { 287 err = mount.MakePrivate(cfg.Root) 288 assert.NilError(t, err) 289 defer mount.Unmount(cfg.Root) 290 291 err = setupDaemonRootPropagation(&cfg.Config) 292 assert.NilError(t, err) 293 assert.Check(t, ensureShared(cfg.Root)) 294 295 _, err = os.Stat(unmountFile) 296 assert.Assert(t, os.IsNotExist(err)) 297 assert.Assert(t, d.cleanupMounts(&cfg.Config)) 298 checkMounted(t, cfg.Root, true) 299 }) 300 301 // mount is pre-configured with a shared mount 302 t.Run("root is a shared mountpoint", func(t *testing.T) { 303 err = mount.MakeShared(cfg.Root) 304 assert.NilError(t, err) 305 defer mount.Unmount(cfg.Root) 306 307 err = setupDaemonRootPropagation(&cfg.Config) 308 assert.NilError(t, err) 309 310 if _, err := os.Stat(unmountFile); err == nil { 311 t.Fatal("unmount file should not exist") 312 } 313 314 assert.Assert(t, d.cleanupMounts(&cfg.Config)) 315 checkMounted(t, cfg.Root, true) 316 assert.Assert(t, mount.Unmount(cfg.Root)) 317 }) 318 319 // does not need mount but unmount file exists from previous run 320 t.Run("old mount file is cleaned up on setup if not needed", func(t *testing.T) { 321 err = mount.MakeShared(testRoot) 322 assert.NilError(t, err) 323 defer mount.MakePrivate(testRoot) 324 err = os.WriteFile(unmountFile, nil, 0o644) 325 assert.NilError(t, err) 326 327 err = setupDaemonRootPropagation(&cfg.Config) 328 assert.NilError(t, err) 329 330 _, err = os.Stat(unmountFile) 331 assert.Check(t, os.IsNotExist(err), err) 332 checkMounted(t, cfg.Root, false) 333 assert.Assert(t, d.cleanupMounts(&cfg.Config)) 334 }) 335 } 336 337 func TestIfaceAddrs(t *testing.T) { 338 CIDR := func(cidr string) *net.IPNet { 339 t.Helper() 340 nw, err := types.ParseCIDR(cidr) 341 assert.NilError(t, err) 342 return nw 343 } 344 345 for _, tt := range []struct { 346 name string 347 nws []*net.IPNet 348 }{ 349 { 350 name: "Single", 351 nws: []*net.IPNet{CIDR("172.101.202.254/16")}, 352 }, 353 { 354 name: "Multiple", 355 nws: []*net.IPNet{ 356 CIDR("172.101.202.254/16"), 357 CIDR("172.102.202.254/16"), 358 }, 359 }, 360 } { 361 t.Run(tt.name, func(t *testing.T) { 362 defer netnsutils.SetupTestOSContext(t)() 363 364 createBridge(t, "test", tt.nws...) 365 366 ipv4Nw, ipv6Nw, err := ifaceAddrs("test") 367 if err != nil { 368 t.Fatal(err) 369 } 370 371 assert.Check(t, is.DeepEqual(tt.nws, ipv4Nw, 372 cmpopts.SortSlices(func(a, b *net.IPNet) bool { return a.String() < b.String() }))) 373 // IPv6 link-local address 374 assert.Check(t, is.Len(ipv6Nw, 1)) 375 }) 376 } 377 } 378 379 func createBridge(t *testing.T, name string, bips ...*net.IPNet) { 380 t.Helper() 381 382 link := &netlink.Bridge{ 383 LinkAttrs: netlink.LinkAttrs{ 384 Name: name, 385 }, 386 } 387 if err := netlink.LinkAdd(link); err != nil { 388 t.Fatalf("Failed to create interface via netlink: %v", err) 389 } 390 for _, bip := range bips { 391 if err := netlink.AddrAdd(link, &netlink.Addr{IPNet: bip}); err != nil { 392 t.Fatal(err) 393 } 394 } 395 if err := netlink.LinkSetUp(link); err != nil { 396 t.Fatal(err) 397 } 398 }