github.com/sijibomii/docker@v0.0.0-20231230191044-5cf6ca554647/pkg/mount/sharedsubtree_linux_test.go (about) 1 // +build linux 2 3 package mount 4 5 import ( 6 "os" 7 "path" 8 "syscall" 9 "testing" 10 ) 11 12 // nothing is propagated in or out 13 func TestSubtreePrivate(t *testing.T) { 14 tmp := path.Join(os.TempDir(), "mount-tests") 15 if err := os.MkdirAll(tmp, 0777); err != nil { 16 t.Fatal(err) 17 } 18 defer os.RemoveAll(tmp) 19 20 var ( 21 sourceDir = path.Join(tmp, "source") 22 targetDir = path.Join(tmp, "target") 23 outside1Dir = path.Join(tmp, "outside1") 24 outside2Dir = path.Join(tmp, "outside2") 25 26 outside1Path = path.Join(outside1Dir, "file.txt") 27 outside2Path = path.Join(outside2Dir, "file.txt") 28 outside1CheckPath = path.Join(targetDir, "a", "file.txt") 29 outside2CheckPath = path.Join(sourceDir, "b", "file.txt") 30 ) 31 if err := os.MkdirAll(path.Join(sourceDir, "a"), 0777); err != nil { 32 t.Fatal(err) 33 } 34 if err := os.MkdirAll(path.Join(sourceDir, "b"), 0777); err != nil { 35 t.Fatal(err) 36 } 37 if err := os.Mkdir(targetDir, 0777); err != nil { 38 t.Fatal(err) 39 } 40 if err := os.Mkdir(outside1Dir, 0777); err != nil { 41 t.Fatal(err) 42 } 43 if err := os.Mkdir(outside2Dir, 0777); err != nil { 44 t.Fatal(err) 45 } 46 47 if err := createFile(outside1Path); err != nil { 48 t.Fatal(err) 49 } 50 if err := createFile(outside2Path); err != nil { 51 t.Fatal(err) 52 } 53 54 // mount the shared directory to a target 55 if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil { 56 t.Fatal(err) 57 } 58 defer func() { 59 if err := Unmount(targetDir); err != nil { 60 t.Fatal(err) 61 } 62 }() 63 64 // next, make the target private 65 if err := MakePrivate(targetDir); err != nil { 66 t.Fatal(err) 67 } 68 defer func() { 69 if err := Unmount(targetDir); err != nil { 70 t.Fatal(err) 71 } 72 }() 73 74 // mount in an outside path to a mounted path inside the _source_ 75 if err := Mount(outside1Dir, path.Join(sourceDir, "a"), "none", "bind,rw"); err != nil { 76 t.Fatal(err) 77 } 78 defer func() { 79 if err := Unmount(path.Join(sourceDir, "a")); err != nil { 80 t.Fatal(err) 81 } 82 }() 83 84 // check that this file _does_not_ show in the _target_ 85 if _, err := os.Stat(outside1CheckPath); err != nil && !os.IsNotExist(err) { 86 t.Fatal(err) 87 } else if err == nil { 88 t.Fatalf("%q should not be visible, but is", outside1CheckPath) 89 } 90 91 // next mount outside2Dir into the _target_ 92 if err := Mount(outside2Dir, path.Join(targetDir, "b"), "none", "bind,rw"); err != nil { 93 t.Fatal(err) 94 } 95 defer func() { 96 if err := Unmount(path.Join(targetDir, "b")); err != nil { 97 t.Fatal(err) 98 } 99 }() 100 101 // check that this file _does_not_ show in the _source_ 102 if _, err := os.Stat(outside2CheckPath); err != nil && !os.IsNotExist(err) { 103 t.Fatal(err) 104 } else if err == nil { 105 t.Fatalf("%q should not be visible, but is", outside2CheckPath) 106 } 107 } 108 109 // Testing that when a target is a shared mount, 110 // then child mounts propagate to the source 111 func TestSubtreeShared(t *testing.T) { 112 tmp := path.Join(os.TempDir(), "mount-tests") 113 if err := os.MkdirAll(tmp, 0777); err != nil { 114 t.Fatal(err) 115 } 116 defer os.RemoveAll(tmp) 117 118 var ( 119 sourceDir = path.Join(tmp, "source") 120 targetDir = path.Join(tmp, "target") 121 outsideDir = path.Join(tmp, "outside") 122 123 outsidePath = path.Join(outsideDir, "file.txt") 124 sourceCheckPath = path.Join(sourceDir, "a", "file.txt") 125 ) 126 127 if err := os.MkdirAll(path.Join(sourceDir, "a"), 0777); err != nil { 128 t.Fatal(err) 129 } 130 if err := os.Mkdir(targetDir, 0777); err != nil { 131 t.Fatal(err) 132 } 133 if err := os.Mkdir(outsideDir, 0777); err != nil { 134 t.Fatal(err) 135 } 136 137 if err := createFile(outsidePath); err != nil { 138 t.Fatal(err) 139 } 140 141 // mount the source as shared 142 if err := MakeShared(sourceDir); err != nil { 143 t.Fatal(err) 144 } 145 defer func() { 146 if err := Unmount(sourceDir); err != nil { 147 t.Fatal(err) 148 } 149 }() 150 151 // mount the shared directory to a target 152 if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil { 153 t.Fatal(err) 154 } 155 defer func() { 156 if err := Unmount(targetDir); err != nil { 157 t.Fatal(err) 158 } 159 }() 160 161 // mount in an outside path to a mounted path inside the target 162 if err := Mount(outsideDir, path.Join(targetDir, "a"), "none", "bind,rw"); err != nil { 163 t.Fatal(err) 164 } 165 defer func() { 166 if err := Unmount(path.Join(targetDir, "a")); err != nil { 167 t.Fatal(err) 168 } 169 }() 170 171 // NOW, check that the file from the outside directory is available in the source directory 172 if _, err := os.Stat(sourceCheckPath); err != nil { 173 t.Fatal(err) 174 } 175 } 176 177 // testing that mounts to a shared source show up in the slave target, 178 // and that mounts into a slave target do _not_ show up in the shared source 179 func TestSubtreeSharedSlave(t *testing.T) { 180 tmp := path.Join(os.TempDir(), "mount-tests") 181 if err := os.MkdirAll(tmp, 0777); err != nil { 182 t.Fatal(err) 183 } 184 defer os.RemoveAll(tmp) 185 186 var ( 187 sourceDir = path.Join(tmp, "source") 188 targetDir = path.Join(tmp, "target") 189 outside1Dir = path.Join(tmp, "outside1") 190 outside2Dir = path.Join(tmp, "outside2") 191 192 outside1Path = path.Join(outside1Dir, "file.txt") 193 outside2Path = path.Join(outside2Dir, "file.txt") 194 outside1CheckPath = path.Join(targetDir, "a", "file.txt") 195 outside2CheckPath = path.Join(sourceDir, "b", "file.txt") 196 ) 197 if err := os.MkdirAll(path.Join(sourceDir, "a"), 0777); err != nil { 198 t.Fatal(err) 199 } 200 if err := os.MkdirAll(path.Join(sourceDir, "b"), 0777); err != nil { 201 t.Fatal(err) 202 } 203 if err := os.Mkdir(targetDir, 0777); err != nil { 204 t.Fatal(err) 205 } 206 if err := os.Mkdir(outside1Dir, 0777); err != nil { 207 t.Fatal(err) 208 } 209 if err := os.Mkdir(outside2Dir, 0777); err != nil { 210 t.Fatal(err) 211 } 212 213 if err := createFile(outside1Path); err != nil { 214 t.Fatal(err) 215 } 216 if err := createFile(outside2Path); err != nil { 217 t.Fatal(err) 218 } 219 220 // mount the source as shared 221 if err := MakeShared(sourceDir); err != nil { 222 t.Fatal(err) 223 } 224 defer func() { 225 if err := Unmount(sourceDir); err != nil { 226 t.Fatal(err) 227 } 228 }() 229 230 // mount the shared directory to a target 231 if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil { 232 t.Fatal(err) 233 } 234 defer func() { 235 if err := Unmount(targetDir); err != nil { 236 t.Fatal(err) 237 } 238 }() 239 240 // next, make the target slave 241 if err := MakeSlave(targetDir); err != nil { 242 t.Fatal(err) 243 } 244 defer func() { 245 if err := Unmount(targetDir); err != nil { 246 t.Fatal(err) 247 } 248 }() 249 250 // mount in an outside path to a mounted path inside the _source_ 251 if err := Mount(outside1Dir, path.Join(sourceDir, "a"), "none", "bind,rw"); err != nil { 252 t.Fatal(err) 253 } 254 defer func() { 255 if err := Unmount(path.Join(sourceDir, "a")); err != nil { 256 t.Fatal(err) 257 } 258 }() 259 260 // check that this file _does_ show in the _target_ 261 if _, err := os.Stat(outside1CheckPath); err != nil { 262 t.Fatal(err) 263 } 264 265 // next mount outside2Dir into the _target_ 266 if err := Mount(outside2Dir, path.Join(targetDir, "b"), "none", "bind,rw"); err != nil { 267 t.Fatal(err) 268 } 269 defer func() { 270 if err := Unmount(path.Join(targetDir, "b")); err != nil { 271 t.Fatal(err) 272 } 273 }() 274 275 // check that this file _does_not_ show in the _source_ 276 if _, err := os.Stat(outside2CheckPath); err != nil && !os.IsNotExist(err) { 277 t.Fatal(err) 278 } else if err == nil { 279 t.Fatalf("%q should not be visible, but is", outside2CheckPath) 280 } 281 } 282 283 func TestSubtreeUnbindable(t *testing.T) { 284 tmp := path.Join(os.TempDir(), "mount-tests") 285 if err := os.MkdirAll(tmp, 0777); err != nil { 286 t.Fatal(err) 287 } 288 defer os.RemoveAll(tmp) 289 290 var ( 291 sourceDir = path.Join(tmp, "source") 292 targetDir = path.Join(tmp, "target") 293 ) 294 if err := os.MkdirAll(sourceDir, 0777); err != nil { 295 t.Fatal(err) 296 } 297 if err := os.MkdirAll(targetDir, 0777); err != nil { 298 t.Fatal(err) 299 } 300 301 // next, make the source unbindable 302 if err := MakeUnbindable(sourceDir); err != nil { 303 t.Fatal(err) 304 } 305 defer func() { 306 if err := Unmount(sourceDir); err != nil { 307 t.Fatal(err) 308 } 309 }() 310 311 // then attempt to mount it to target. It should fail 312 if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil && err != syscall.EINVAL { 313 t.Fatal(err) 314 } else if err == nil { 315 t.Fatalf("%q should not have been bindable", sourceDir) 316 } 317 defer func() { 318 if err := Unmount(targetDir); err != nil { 319 t.Fatal(err) 320 } 321 }() 322 } 323 324 func createFile(path string) error { 325 f, err := os.Create(path) 326 if err != nil { 327 return err 328 } 329 f.WriteString("hello world!") 330 return f.Close() 331 }