Ver Fonte

Merge pull request #40451 from cpuguy83/40446_check_other_mounts

Check tmpfs mounts before create anon volume
Akihiro Suda há 5 anos atrás
pai
commit
ce21a16833

+ 3 - 1
daemon/create_unix.go

@@ -46,7 +46,9 @@ func (daemon *Daemon) createContainerOSSpecificSettings(container *container.Con
 
 		// Skip volumes for which we already have something mounted on that
 		// destination because of a --volume-from.
-		if container.IsDestinationMounted(destination) {
+		if container.HasMountFor(destination) {
+			logrus.WithField("container", container.ID).WithField("destination", spec).Debug("mountpoint already exists, skipping anonymous volume")
+			// Not an error, this could easily have come from the image config.
 			continue
 		}
 		path, err := container.GetResourcePath(destination)

+ 47 - 0
integration/container/create_test.go

@@ -534,3 +534,50 @@ func TestCreateWithInvalidHealthcheckParams(t *testing.T) {
 		})
 	}
 }
+
+// Make sure that anonymous volumes can be overritten by tmpfs
+// https://github.com/moby/moby/issues/40446
+func TestCreateTmpfsOverrideAnonymousVolume(t *testing.T) {
+	skip.If(t, testEnv.DaemonInfo.OSType == "windows", "windows does not support tmpfs")
+	defer setupTest(t)()
+	client := testEnv.APIClient()
+	ctx := context.Background()
+
+	id := ctr.Create(ctx, t, client,
+		ctr.WithVolume("/foo"),
+		ctr.WithTmpfs("/foo"),
+		ctr.WithVolume("/bar"),
+		ctr.WithTmpfs("/bar:size=999"),
+		ctr.WithCmd("/bin/sh", "-c", "mount | grep '/foo' | grep tmpfs && mount | grep '/bar' | grep tmpfs"),
+	)
+
+	defer func() {
+		err := client.ContainerRemove(ctx, id, types.ContainerRemoveOptions{Force: true})
+		assert.NilError(t, err)
+	}()
+
+	inspect, err := client.ContainerInspect(ctx, id)
+	assert.NilError(t, err)
+	// tmpfs do not currently get added to inspect.Mounts
+	// Normally an anoynmous volume would, except now tmpfs should prevent that.
+	assert.Assert(t, is.Len(inspect.Mounts, 0))
+
+	chWait, chErr := client.ContainerWait(ctx, id, container.WaitConditionNextExit)
+	assert.NilError(t, client.ContainerStart(ctx, id, types.ContainerStartOptions{}))
+
+	timeout := time.NewTimer(30 * time.Second)
+	defer timeout.Stop()
+
+	select {
+	case <-timeout.C:
+		t.Fatal("timeout waiting for container to exit")
+	case status := <-chWait:
+		var errMsg string
+		if status.Error != nil {
+			errMsg = status.Error.Message
+		}
+		assert.Equal(t, int(status.StatusCode), 0, errMsg)
+	case err := <-chErr:
+		assert.NilError(t, err)
+	}
+}

+ 19 - 2
integration/internal/container/ops.go

@@ -2,6 +2,7 @@ package container
 
 import (
 	"fmt"
+	"strings"
 
 	containertypes "github.com/docker/docker/api/types/container"
 	mounttypes "github.com/docker/docker/api/types/mount"
@@ -77,12 +78,12 @@ func WithMount(m mounttypes.Mount) func(*TestContainerConfig) {
 }
 
 // WithVolume sets the volume of the container
-func WithVolume(name string) func(*TestContainerConfig) {
+func WithVolume(target string) func(*TestContainerConfig) {
 	return func(c *TestContainerConfig) {
 		if c.Config.Volumes == nil {
 			c.Config.Volumes = map[string]struct{}{}
 		}
-		c.Config.Volumes[name] = struct{}{}
+		c.Config.Volumes[target] = struct{}{}
 	}
 }
 
@@ -93,6 +94,22 @@ func WithBind(src, target string) func(*TestContainerConfig) {
 	}
 }
 
+// WithTmpfs sets a target path in the container to a tmpfs
+func WithTmpfs(target string) func(config *TestContainerConfig) {
+	return func(c *TestContainerConfig) {
+		if c.HostConfig.Tmpfs == nil {
+			c.HostConfig.Tmpfs = make(map[string]string)
+		}
+
+		spec := strings.SplitN(target, ":", 2)
+		var opts string
+		if len(spec) > 1 {
+			opts = spec[1]
+		}
+		c.HostConfig.Tmpfs[spec[0]] = opts
+	}
+}
+
 // WithIPv4 sets the specified ip for the specified network of the container
 func WithIPv4(network, ip string) func(*TestContainerConfig) {
 	return func(c *TestContainerConfig) {