diff --git a/container.go b/container.go index c20ee11f55..0578a81b3c 100644 --- a/container.go +++ b/container.go @@ -577,40 +577,12 @@ func (container *Container) Start(hostConfig *HostConfig) error { binds[path.Clean(dst)] = bindMap } - // FIXME: evaluate volumes-from before individual volumes, so that the latter can override the former. - // Create the requested volumes volumes if container.Volumes == nil || len(container.Volumes) == 0 { container.Volumes = make(map[string]string) container.VolumesRW = make(map[string]bool) - - for volPath := range container.Config.Volumes { - volPath = path.Clean(volPath) - // If an external bind is defined for this volume, use that as a source - if bindMap, exists := binds[volPath]; exists { - container.Volumes[volPath] = bindMap.SrcPath - if strings.ToLower(bindMap.Mode) == "rw" { - container.VolumesRW[volPath] = true - } - // Otherwise create an directory in $ROOT/volumes/ and use that - } else { - c, err := container.runtime.volumes.Create(nil, container, "", "", nil) - if err != nil { - return err - } - srcPath, err := c.layer() - if err != nil { - return err - } - container.Volumes[volPath] = srcPath - container.VolumesRW[volPath] = true // RW by default - } - // Create the mountpoint - if err := os.MkdirAll(path.Join(container.RootfsPath(), volPath), 0755); err != nil { - return nil - } - } } + // Apply volumes from another container if requested if container.Config.VolumesFrom != "" { c := container.runtime.Get(container.Config.VolumesFrom) if c == nil { @@ -618,7 +590,7 @@ func (container *Container) Start(hostConfig *HostConfig) error { } for volPath, id := range c.Volumes { if _, exists := container.Volumes[volPath]; exists { - return fmt.Errorf("The requested volume %s overlap one of the volume of the container %s", volPath, c.ID) + continue } if err := os.MkdirAll(path.Join(container.RootfsPath(), volPath), 0755); err != nil { return nil @@ -630,6 +602,38 @@ func (container *Container) Start(hostConfig *HostConfig) error { } } + // Create the requested volumes if they don't exist + for volPath := range container.Config.Volumes { + volPath = path.Clean(volPath) + // Skip existing volumes + if _, exists := container.Volumes[volPath]; exists { + continue + } + // If an external bind is defined for this volume, use that as a source + if bindMap, exists := binds[volPath]; exists { + container.Volumes[volPath] = bindMap.SrcPath + if strings.ToLower(bindMap.Mode) == "rw" { + container.VolumesRW[volPath] = true + } + // Otherwise create an directory in $ROOT/volumes/ and use that + } else { + c, err := container.runtime.volumes.Create(nil, container, "", "", nil) + if err != nil { + return err + } + srcPath, err := c.layer() + if err != nil { + return err + } + container.Volumes[volPath] = srcPath + container.VolumesRW[volPath] = true // RW by default + } + // Create the mountpoint + if err := os.MkdirAll(path.Join(container.RootfsPath(), volPath), 0755); err != nil { + return nil + } + } + if err := container.generateLXCConfig(); err != nil { return err } diff --git a/container_test.go b/container_test.go index 34ebb5fb87..3752615a3c 100644 --- a/container_test.go +++ b/container_test.go @@ -1283,6 +1283,71 @@ func TestRestartWithVolumes(t *testing.T) { } } +// Test for #1351 +func TestVolumesFromWithVolumes(t *testing.T) { + runtime := mkRuntime(t) + defer nuke(runtime) + + container, err := NewBuilder(runtime).Create(&Config{ + Image: GetTestImage(runtime).ID, + Cmd: []string{"sh", "-c", "echo -n bar > /test/foo"}, + Volumes: map[string]struct{}{"/test": {}}, + }, + ) + if err != nil { + t.Fatal(err) + } + defer runtime.Destroy(container) + + for key := range container.Config.Volumes { + if key != "/test" { + t.Fail() + } + } + + _, err = container.Output() + if err != nil { + t.Fatal(err) + } + + expected := container.Volumes["/test"] + if expected == "" { + t.Fail() + } + + container2, err := NewBuilder(runtime).Create( + &Config{ + Image: GetTestImage(runtime).ID, + Cmd: []string{"cat", "/test/foo"}, + VolumesFrom: container.ID, + Volumes: map[string]struct{}{"/test": {}}, + }, + ) + if err != nil { + t.Fatal(err) + } + defer runtime.Destroy(container2) + + output, err := container2.Output() + if err != nil { + t.Fatal(err) + } + + if string(output) != "bar" { + t.Fail() + } + + if container.Volumes["/test"] != container2.Volumes["/test"] { + t.Fail() + } + + // Ensure it restarts successfully + _, err = container2.Output() + if err != nil { + t.Fatal(err) + } +} + func TestOnlyLoopbackExistsWhenUsingDisableNetworkOption(t *testing.T) { runtime := mkRuntime(t) defer nuke(runtime)