Merge pull request #40477 from cpuguy83/19.03_40446_check_other_mounts

[19.03] Check tmpfs mounts before create anon volume
This commit is contained in:
Akihiro Suda 2020-02-25 09:41:24 +09:00 committed by GitHub
commit ad2c5440b5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 69 additions and 3 deletions

View file

@ -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)

View file

@ -535,3 +535,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)
}
}

View file

@ -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) {