daemon_linux_test.go 19 KB

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