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>
This commit is contained in:
parent
7bb729e928
commit
7ba05f2b2b
2 changed files with 125 additions and 82 deletions
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue