123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349 |
- // +build linux
- package mount // import "github.com/docker/docker/pkg/mount"
- import (
- "os"
- "path"
- "testing"
- "github.com/pkg/errors"
- "golang.org/x/sys/unix"
- )
- // nothing is propagated in or out
- func TestSubtreePrivate(t *testing.T) {
- if os.Getuid() != 0 {
- t.Skip("root required")
- }
- tmp := path.Join(os.TempDir(), "mount-tests")
- if err := os.MkdirAll(tmp, 0777); err != nil {
- t.Fatal(err)
- }
- defer os.RemoveAll(tmp)
- var (
- sourceDir = path.Join(tmp, "source")
- targetDir = path.Join(tmp, "target")
- outside1Dir = path.Join(tmp, "outside1")
- outside2Dir = path.Join(tmp, "outside2")
- outside1Path = path.Join(outside1Dir, "file.txt")
- outside2Path = path.Join(outside2Dir, "file.txt")
- outside1CheckPath = path.Join(targetDir, "a", "file.txt")
- outside2CheckPath = path.Join(sourceDir, "b", "file.txt")
- )
- if err := os.MkdirAll(path.Join(sourceDir, "a"), 0777); err != nil {
- t.Fatal(err)
- }
- if err := os.MkdirAll(path.Join(sourceDir, "b"), 0777); err != nil {
- t.Fatal(err)
- }
- if err := os.Mkdir(targetDir, 0777); err != nil {
- t.Fatal(err)
- }
- if err := os.Mkdir(outside1Dir, 0777); err != nil {
- t.Fatal(err)
- }
- if err := os.Mkdir(outside2Dir, 0777); err != nil {
- t.Fatal(err)
- }
- if err := createFile(outside1Path); err != nil {
- t.Fatal(err)
- }
- if err := createFile(outside2Path); err != nil {
- t.Fatal(err)
- }
- // mount the shared directory to a target
- if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil {
- t.Fatal(err)
- }
- defer func() {
- if err := Unmount(targetDir); err != nil {
- t.Fatal(err)
- }
- }()
- // next, make the target private
- if err := MakePrivate(targetDir); err != nil {
- t.Fatal(err)
- }
- defer func() {
- if err := Unmount(targetDir); err != nil {
- t.Fatal(err)
- }
- }()
- // mount in an outside path to a mounted path inside the _source_
- if err := Mount(outside1Dir, path.Join(sourceDir, "a"), "none", "bind,rw"); err != nil {
- t.Fatal(err)
- }
- defer func() {
- if err := Unmount(path.Join(sourceDir, "a")); err != nil {
- t.Fatal(err)
- }
- }()
- // check that this file _does_not_ show in the _target_
- if _, err := os.Stat(outside1CheckPath); err != nil && !os.IsNotExist(err) {
- t.Fatal(err)
- } else if err == nil {
- t.Fatalf("%q should not be visible, but is", outside1CheckPath)
- }
- // next mount outside2Dir into the _target_
- if err := Mount(outside2Dir, path.Join(targetDir, "b"), "none", "bind,rw"); err != nil {
- t.Fatal(err)
- }
- defer func() {
- if err := Unmount(path.Join(targetDir, "b")); err != nil {
- t.Fatal(err)
- }
- }()
- // check that this file _does_not_ show in the _source_
- if _, err := os.Stat(outside2CheckPath); err != nil && !os.IsNotExist(err) {
- t.Fatal(err)
- } else if err == nil {
- t.Fatalf("%q should not be visible, but is", outside2CheckPath)
- }
- }
- // Testing that when a target is a shared mount,
- // then child mounts propagate to the source
- func TestSubtreeShared(t *testing.T) {
- if os.Getuid() != 0 {
- t.Skip("root required")
- }
- tmp := path.Join(os.TempDir(), "mount-tests")
- if err := os.MkdirAll(tmp, 0777); err != nil {
- t.Fatal(err)
- }
- defer os.RemoveAll(tmp)
- var (
- sourceDir = path.Join(tmp, "source")
- targetDir = path.Join(tmp, "target")
- outsideDir = path.Join(tmp, "outside")
- outsidePath = path.Join(outsideDir, "file.txt")
- sourceCheckPath = path.Join(sourceDir, "a", "file.txt")
- )
- if err := os.MkdirAll(path.Join(sourceDir, "a"), 0777); err != nil {
- t.Fatal(err)
- }
- if err := os.Mkdir(targetDir, 0777); err != nil {
- t.Fatal(err)
- }
- if err := os.Mkdir(outsideDir, 0777); err != nil {
- t.Fatal(err)
- }
- if err := createFile(outsidePath); err != nil {
- t.Fatal(err)
- }
- // mount the source as shared
- if err := MakeShared(sourceDir); err != nil {
- t.Fatal(err)
- }
- defer func() {
- if err := Unmount(sourceDir); err != nil {
- t.Fatal(err)
- }
- }()
- // mount the shared directory to a target
- if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil {
- t.Fatal(err)
- }
- defer func() {
- if err := Unmount(targetDir); err != nil {
- t.Fatal(err)
- }
- }()
- // mount in an outside path to a mounted path inside the target
- if err := Mount(outsideDir, path.Join(targetDir, "a"), "none", "bind,rw"); err != nil {
- t.Fatal(err)
- }
- defer func() {
- if err := Unmount(path.Join(targetDir, "a")); err != nil {
- t.Fatal(err)
- }
- }()
- // NOW, check that the file from the outside directory is available in the source directory
- if _, err := os.Stat(sourceCheckPath); err != nil {
- t.Fatal(err)
- }
- }
- // testing that mounts to a shared source show up in the slave target,
- // and that mounts into a slave target do _not_ show up in the shared source
- func TestSubtreeSharedSlave(t *testing.T) {
- if os.Getuid() != 0 {
- t.Skip("root required")
- }
- tmp := path.Join(os.TempDir(), "mount-tests")
- if err := os.MkdirAll(tmp, 0777); err != nil {
- t.Fatal(err)
- }
- defer os.RemoveAll(tmp)
- var (
- sourceDir = path.Join(tmp, "source")
- targetDir = path.Join(tmp, "target")
- outside1Dir = path.Join(tmp, "outside1")
- outside2Dir = path.Join(tmp, "outside2")
- outside1Path = path.Join(outside1Dir, "file.txt")
- outside2Path = path.Join(outside2Dir, "file.txt")
- outside1CheckPath = path.Join(targetDir, "a", "file.txt")
- outside2CheckPath = path.Join(sourceDir, "b", "file.txt")
- )
- if err := os.MkdirAll(path.Join(sourceDir, "a"), 0777); err != nil {
- t.Fatal(err)
- }
- if err := os.MkdirAll(path.Join(sourceDir, "b"), 0777); err != nil {
- t.Fatal(err)
- }
- if err := os.Mkdir(targetDir, 0777); err != nil {
- t.Fatal(err)
- }
- if err := os.Mkdir(outside1Dir, 0777); err != nil {
- t.Fatal(err)
- }
- if err := os.Mkdir(outside2Dir, 0777); err != nil {
- t.Fatal(err)
- }
- if err := createFile(outside1Path); err != nil {
- t.Fatal(err)
- }
- if err := createFile(outside2Path); err != nil {
- t.Fatal(err)
- }
- // mount the source as shared
- if err := MakeShared(sourceDir); err != nil {
- t.Fatal(err)
- }
- defer func() {
- if err := Unmount(sourceDir); err != nil {
- t.Fatal(err)
- }
- }()
- // mount the shared directory to a target
- if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil {
- t.Fatal(err)
- }
- defer func() {
- if err := Unmount(targetDir); err != nil {
- t.Fatal(err)
- }
- }()
- // next, make the target slave
- if err := MakeSlave(targetDir); err != nil {
- t.Fatal(err)
- }
- defer func() {
- if err := Unmount(targetDir); err != nil {
- t.Fatal(err)
- }
- }()
- // mount in an outside path to a mounted path inside the _source_
- if err := Mount(outside1Dir, path.Join(sourceDir, "a"), "none", "bind,rw"); err != nil {
- t.Fatal(err)
- }
- defer func() {
- if err := Unmount(path.Join(sourceDir, "a")); err != nil {
- t.Fatal(err)
- }
- }()
- // check that this file _does_ show in the _target_
- if _, err := os.Stat(outside1CheckPath); err != nil {
- t.Fatal(err)
- }
- // next mount outside2Dir into the _target_
- if err := Mount(outside2Dir, path.Join(targetDir, "b"), "none", "bind,rw"); err != nil {
- t.Fatal(err)
- }
- defer func() {
- if err := Unmount(path.Join(targetDir, "b")); err != nil {
- t.Fatal(err)
- }
- }()
- // check that this file _does_not_ show in the _source_
- if _, err := os.Stat(outside2CheckPath); err != nil && !os.IsNotExist(err) {
- t.Fatal(err)
- } else if err == nil {
- t.Fatalf("%q should not be visible, but is", outside2CheckPath)
- }
- }
- func TestSubtreeUnbindable(t *testing.T) {
- if os.Getuid() != 0 {
- t.Skip("root required")
- }
- tmp := path.Join(os.TempDir(), "mount-tests")
- if err := os.MkdirAll(tmp, 0777); err != nil {
- t.Fatal(err)
- }
- defer os.RemoveAll(tmp)
- var (
- sourceDir = path.Join(tmp, "source")
- targetDir = path.Join(tmp, "target")
- )
- if err := os.MkdirAll(sourceDir, 0777); err != nil {
- t.Fatal(err)
- }
- if err := os.MkdirAll(targetDir, 0777); err != nil {
- t.Fatal(err)
- }
- // next, make the source unbindable
- if err := MakeUnbindable(sourceDir); err != nil {
- t.Fatal(err)
- }
- defer func() {
- if err := Unmount(sourceDir); err != nil {
- t.Fatal(err)
- }
- }()
- // then attempt to mount it to target. It should fail
- if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil && errors.Cause(err) != unix.EINVAL {
- t.Fatal(err)
- } else if err == nil {
- t.Fatalf("%q should not have been bindable", sourceDir)
- }
- defer func() {
- if err := Unmount(targetDir); err != nil {
- t.Fatal(err)
- }
- }()
- }
- func createFile(path string) error {
- f, err := os.Create(path)
- if err != nil {
- return err
- }
- f.WriteString("hello world!")
- return f.Close()
- }
|