Check tmpfs mounts before create anon volume
This makes sure that things like `--tmpfs` mounts over an anonymous volume don't create volumes uneccessarily. One method only checks mountpoints, the other checks both mountpoints and tmpfs... the usage of these should likely be consolidated. Ideally, processing for `--tmpfs` mounts would get merged in with the rest of the mount parsing. I opted not to do that for this change so the fix is minimal and can potentially be backported with fewer changes of breaking things. Merging the mount processing for tmpfs can be handled in a followup. Signed-off-by: Brian Goff <cpuguy83@gmail.com>
This commit is contained in:
parent
46ec8731fb
commit
f464c31668
3 changed files with 69 additions and 3 deletions
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue