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  }