1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Fix: Failed Start breaks VolumesFrom

Running parseVolumesFromSpec on all VolumesFrom specs before initialize
any mounts endures that we don't leave container.Volumes in an
inconsistent (partially initialized) if one of out mount groups is not
available (e.g. the container we're trying to mount from does not
exist).

Keeping container.Volumes in a consistent state ensures that next time
we Start() the container, it'll run prepareVolumes() again.

The attached test demonstrates that when a container fails to start due
to a missing container specified in VolumesFrom, it "remembers" a Volume
that worked.

Fixes: #8726

Signed-off-by: Thomas Orozco <thomas@orozco.fr>

Conflicts:
	integration-cli/docker_cli_start_test.go
		cli integration test
This commit is contained in:
Thomas Orozco 2014-10-23 14:50:06 +02:00 committed by unclejack
parent 8d90b0faf8
commit 967f80f3cc
2 changed files with 36 additions and 2 deletions

View file

@ -191,15 +191,20 @@ func parseBindMountSpec(spec string) (string, string, bool, error) {
func (container *Container) applyVolumesFrom() error {
volumesFrom := container.hostConfig.VolumesFrom
mountGroups := make([]map[string]*Mount, 0, len(volumesFrom))
for _, spec := range volumesFrom {
mounts, err := parseVolumesFromSpec(container.daemon, spec)
mountGroup, err := parseVolumesFromSpec(container.daemon, spec)
if err != nil {
return err
}
mountGroups = append(mountGroups, mountGroup)
}
for _, mounts := range mountGroups {
for _, mnt := range mounts {
mnt.container = container
if err = mnt.initialize(); err != nil {
if err := mnt.initialize(); err != nil {
return err
}
}

View file

@ -2,6 +2,7 @@ package main
import (
"os/exec"
"strings"
"testing"
"time"
)
@ -36,3 +37,31 @@ func TestStartAttachReturnsOnError(t *testing.T) {
logDone("start - error on start with attach exits")
}
// gh#8726: a failed Start() breaks --volumes-from on subsequent Start()'s
func TestStartVolumesFromFailsCleanly(t *testing.T) {
defer deleteAllContainers()
// Create the first data volume
cmd(t, "run", "-d", "--name", "data_before", "-v", "/foo", "busybox")
// Expect this to fail because the data test after contaienr doesn't exist yet
if _, err := runCommand(exec.Command(dockerBinary, "run", "-d", "--name", "consumer", "--volumes-from", "data_before", "--volumes-from", "data_after", "busybox")); err == nil {
t.Fatal("Expected error but got none")
}
// Create the second data volume
cmd(t, "run", "-d", "--name", "data_after", "-v", "/bar", "busybox")
// Now, all the volumes should be there
cmd(t, "start", "consumer")
// Check that we have the volumes we want
out, _, _ := cmd(t, "inspect", "--format='{{ len .Volumes }}'", "consumer")
n_volumes := strings.Trim(out, " \r\n'")
if n_volumes != "2" {
t.Fatalf("Missing volumes: expected 2, got %s", n_volumes)
}
logDone("start - missing containers in --volumes-from did not affect subsequent runs")
}