Sfoglia il codice sorgente

Rewrite VolumesMountedAsShared/Slave as Integration tests

This moves the two tests from integration-CLI to integration.

Signed-off-by: Paul "TBBle" Hampson <Paul.Hampson@Pobox.com>
Paul "TBBle" Hampson 4 anni fa
parent
commit
7ba05f2b2b

+ 0 - 82
integration-cli/docker_cli_run_unix_test.go

@@ -10,7 +10,6 @@ import (
 	"io/ioutil"
 	"os"
 	"os/exec"
-	"path"
 	"path/filepath"
 	"regexp"
 	"strconv"
@@ -27,7 +26,6 @@ import (
 	"github.com/docker/docker/pkg/parsers"
 	"github.com/docker/docker/pkg/sysinfo"
 	"github.com/moby/sys/mount"
-	"github.com/moby/sys/mountinfo"
 	"gotest.tools/v3/assert"
 	"gotest.tools/v3/icmd"
 )
@@ -1601,83 +1599,3 @@ func (s *DockerSuite) TestRunWithNanoCPUs(c *testing.T) {
 	assert.ErrorContains(c, err, "")
 	assert.Assert(c, strings.Contains(out, "Conflicting options: Nano CPUs and CPU Period cannot both be set"))
 }
-
-func (s *DockerSuite) TestRunVolumesMountedAsShared(c *testing.T) {
-	// Volume propagation is linux only. Also it creates directories for
-	// bind mounting, so needs to be same host.
-	testRequires(c, DaemonIsLinux, testEnv.IsLocalDaemon, NotUserNamespace)
-
-	// Prepare a source directory to bind mount
-	tmpDir, err := ioutil.TempDir("", "volume-source")
-	if err != nil {
-		c.Fatal(err)
-	}
-	defer os.RemoveAll(tmpDir)
-
-	if err := os.Mkdir(path.Join(tmpDir, "mnt1"), 0755); err != nil {
-		c.Fatal(err)
-	}
-
-	// Convert this directory into a shared mount point so that we do
-	// not rely on propagation properties of parent mount.
-	icmd.RunCommand("mount", "--bind", tmpDir, tmpDir).Assert(c, icmd.Success)
-	icmd.RunCommand("mount", "--make-private", "--make-shared", tmpDir).Assert(c, icmd.Success)
-
-	dockerCmd(c, "run", "--privileged", "-v", fmt.Sprintf("%s:/volume-dest:shared", tmpDir), "busybox", "mount", "--bind", "/volume-dest/mnt1", "/volume-dest/mnt1")
-
-	// Make sure a bind mount under a shared volume propagated to host.
-	if mounted, _ := mountinfo.Mounted(path.Join(tmpDir, "mnt1")); !mounted {
-		c.Fatalf("Bind mount under shared volume did not propagate to host")
-	}
-
-	mount.Unmount(path.Join(tmpDir, "mnt1"))
-}
-
-func (s *DockerSuite) TestRunVolumesMountedAsSlave(c *testing.T) {
-	// Volume propagation is linux only. Also it creates directories for
-	// bind mounting, so needs to be same host.
-	testRequires(c, DaemonIsLinux, testEnv.IsLocalDaemon, NotUserNamespace)
-
-	// Prepare a source directory to bind mount
-	tmpDir, err := ioutil.TempDir("", "volume-source")
-	if err != nil {
-		c.Fatal(err)
-	}
-	defer os.RemoveAll(tmpDir)
-
-	if err := os.Mkdir(path.Join(tmpDir, "mnt1"), 0755); err != nil {
-		c.Fatal(err)
-	}
-
-	// Prepare a source directory with file in it. We will bind mount this
-	// directory and see if file shows up.
-	tmpDir2, err := ioutil.TempDir("", "volume-source2")
-	if err != nil {
-		c.Fatal(err)
-	}
-	defer os.RemoveAll(tmpDir2)
-
-	if err := ioutil.WriteFile(path.Join(tmpDir2, "slave-testfile"), []byte("Test"), 0644); err != nil {
-		c.Fatal(err)
-	}
-
-	// Convert this directory into a shared mount point so that we do
-	// not rely on propagation properties of parent mount.
-	icmd.RunCommand("mount", "--bind", tmpDir, tmpDir).Assert(c, icmd.Success)
-	icmd.RunCommand("mount", "--make-private", "--make-shared", tmpDir).Assert(c, icmd.Success)
-
-	dockerCmd(c, "run", "-i", "-d", "--name", "parent", "-v", fmt.Sprintf("%s:/volume-dest:slave", tmpDir), "busybox", "top")
-
-	// Bind mount tmpDir2/ onto tmpDir/mnt1. If mount propagates inside
-	// container then contents of tmpDir2/slave-testfile should become
-	// visible at "/volume-dest/mnt1/slave-testfile"
-	icmd.RunCommand("mount", "--bind", tmpDir2, path.Join(tmpDir, "mnt1")).Assert(c, icmd.Success)
-
-	out, _ := dockerCmd(c, "exec", "parent", "cat", "/volume-dest/mnt1/slave-testfile")
-
-	mount.Unmount(path.Join(tmpDir, "mnt1"))
-
-	if out != "Test" {
-		c.Fatalf("Bind mount under slave volume did not propagate to container")
-	}
-}

+ 125 - 0
integration/container/mounts_linux_test.go

@@ -16,6 +16,7 @@ import (
 	"github.com/docker/docker/integration/internal/container"
 	"github.com/docker/docker/pkg/system"
 	"github.com/moby/sys/mount"
+	"github.com/moby/sys/mountinfo"
 	"gotest.tools/v3/assert"
 	is "gotest.tools/v3/assert/cmp"
 	"gotest.tools/v3/fs"
@@ -266,3 +267,127 @@ func TestContainerBindMountNonRecursive(t *testing.T) {
 		poll.WaitOn(t, container.IsSuccessful(ctx, client, c), poll.WithDelay(100*time.Millisecond))
 	}
 }
+
+func TestContainerVolumesMountedAsShared(t *testing.T) {
+	// Volume propagation is linux only. Also it creates directories for
+	// bind mounting, so needs to be same host.
+	skip.If(t, testEnv.IsRemoteDaemon)
+	skip.If(t, testEnv.IsUserNamespace)
+	skip.If(t, testEnv.IsRootless, "cannot be tested because RootlessKit executes the daemon in private mount namespace (https://github.com/rootless-containers/rootlesskit/issues/97)")
+
+	defer setupTest(t)()
+
+	// Prepare a source directory to bind mount
+	tmpDir1 := fs.NewDir(t, "volume-source", fs.WithMode(0755),
+		fs.WithDir("mnt1", fs.WithMode(0755)))
+	defer tmpDir1.Remove()
+	tmpDir1Mnt := filepath.Join(tmpDir1.Path(), "mnt1")
+
+	// Convert this directory into a shared mount point so that we do
+	// not rely on propagation properties of parent mount.
+	if err := mount.Mount(tmpDir1.Path(), tmpDir1.Path(), "none", "bind,private"); err != nil {
+		t.Fatal(err)
+	}
+	defer func() {
+		if err := mount.Unmount(tmpDir1.Path()); err != nil {
+			t.Fatal(err)
+		}
+	}()
+	if err := mount.Mount("none", tmpDir1.Path(), "none", "shared"); err != nil {
+		t.Fatal(err)
+	}
+
+	sharedMount := mounttypes.Mount{
+		Type:   mounttypes.TypeBind,
+		Source: tmpDir1.Path(),
+		Target: "/volume-dest",
+		BindOptions: &mounttypes.BindOptions{
+			Propagation: mounttypes.PropagationShared,
+		},
+	}
+
+	bindMountCmd := []string{"mount", "--bind", "/volume-dest/mnt1", "/volume-dest/mnt1"}
+
+	ctx := context.Background()
+	client := testEnv.APIClient()
+	containerID := container.Run(ctx, t, client, container.WithPrivileged(true), container.WithMount(sharedMount), container.WithCmd(bindMountCmd...))
+	poll.WaitOn(t, container.IsSuccessful(ctx, client, containerID), poll.WithDelay(100*time.Millisecond))
+
+	// Make sure a bind mount under a shared volume propagated to host.
+	if mounted, _ := mountinfo.Mounted(tmpDir1Mnt); !mounted {
+		t.Fatalf("Bind mount under shared volume did not propagate to host")
+	}
+
+	mount.Unmount(tmpDir1Mnt)
+}
+
+func TestContainerVolumesMountedAsSlave(t *testing.T) {
+	// Volume propagation is linux only. Also it creates directories for
+	// bind mounting, so needs to be same host.
+	skip.If(t, testEnv.IsRemoteDaemon)
+	skip.If(t, testEnv.IsUserNamespace)
+	skip.If(t, testEnv.IsRootless, "cannot be tested because RootlessKit executes the daemon in private mount namespace (https://github.com/rootless-containers/rootlesskit/issues/97)")
+
+	// Prepare a source directory to bind mount
+	tmpDir1 := fs.NewDir(t, "volume-source", fs.WithMode(0755),
+		fs.WithDir("mnt1", fs.WithMode(0755)))
+	defer tmpDir1.Remove()
+	tmpDir1Mnt := filepath.Join(tmpDir1.Path(), "mnt1")
+
+	// Prepare a source directory with file in it. We will bind mount this
+	// directory and see if file shows up.
+	tmpDir2 := fs.NewDir(t, "volume-source2", fs.WithMode(0755),
+		fs.WithFile("slave-testfile", "Test", fs.WithMode(0644)))
+	defer tmpDir2.Remove()
+
+	// Convert this directory into a shared mount point so that we do
+	// not rely on propagation properties of parent mount.
+	if err := mount.Mount(tmpDir1.Path(), tmpDir1.Path(), "none", "bind,private"); err != nil {
+		t.Fatal(err)
+	}
+	defer func() {
+		if err := mount.Unmount(tmpDir1.Path()); err != nil {
+			t.Fatal(err)
+		}
+	}()
+	if err := mount.Mount("none", tmpDir1.Path(), "none", "shared"); err != nil {
+		t.Fatal(err)
+	}
+
+	slaveMount := mounttypes.Mount{
+		Type:   mounttypes.TypeBind,
+		Source: tmpDir1.Path(),
+		Target: "/volume-dest",
+		BindOptions: &mounttypes.BindOptions{
+			Propagation: mounttypes.PropagationSlave,
+		},
+	}
+
+	topCmd := []string{"top"}
+
+	ctx := context.Background()
+	client := testEnv.APIClient()
+	containerID := container.Run(ctx, t, client, container.WithTty(true), container.WithMount(slaveMount), container.WithCmd(topCmd...))
+
+	// Bind mount tmpDir2/ onto tmpDir1/mnt1. If mount propagates inside
+	// container then contents of tmpDir2/slave-testfile should become
+	// visible at "/volume-dest/mnt1/slave-testfile"
+	if err := mount.Mount(tmpDir2.Path(), tmpDir1Mnt, "none", "bind"); err != nil {
+		t.Fatal(err)
+	}
+	defer func() {
+		if err := mount.Unmount(tmpDir1Mnt); err != nil {
+			t.Fatal(err)
+		}
+	}()
+
+	mountCmd := []string{"cat", "/volume-dest/mnt1/slave-testfile"}
+
+	if result, err := container.Exec(ctx, client, containerID, mountCmd); err == nil {
+		if result.Stdout() != "Test" {
+			t.Fatalf("Bind mount under slave volume did not propagate to container")
+		}
+	} else {
+		t.Fatal(err)
+	}
+}