github.com/cdoern/storage@v1.12.13/pkg/mount/sharedsubtree_linux_test.go (about)

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