Restore volume refs after daemon restart

Volume refs were not being restored on daemon restart.
This made it possible to remove a volume being used by other containers
after a daemon restart.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
This commit is contained in:
Brian Goff 2014-10-08 13:13:32 -04:00
parent 0d5daa4a8f
commit 9acf7c765c
4 changed files with 66 additions and 7 deletions

View File

@ -400,9 +400,7 @@ func (daemon *Daemon) restore() error {
} }
for _, c := range registeredContainers { for _, c := range registeredContainers {
for _, mnt := range c.VolumeMounts() { c.registerVolumes()
daemon.volumes.Add(mnt.volume)
}
} }
if !debug { if !debug {

View File

@ -92,6 +92,12 @@ func (container *Container) VolumePaths() map[string]struct{} {
return paths return paths
} }
func (container *Container) registerVolumes() {
for _, mnt := range container.VolumeMounts() {
mnt.volume.AddContainer(container.ID)
}
}
func (container *Container) derefVolumes() { func (container *Container) derefVolumes() {
for path := range container.VolumePaths() { for path := range container.VolumePaths() {
vol := container.daemon.volumes.Get(path) vol := container.daemon.volumes.Get(path)

View File

@ -1,6 +1,8 @@
package main package main
import ( import (
"encoding/json"
"os"
"strings" "strings"
"testing" "testing"
) )
@ -48,3 +50,35 @@ func TestDaemonRestartWithRunningContainersPorts(t *testing.T) {
logDone("daemon - running containers on daemon restart") logDone("daemon - running containers on daemon restart")
} }
func TestDaemonRestartWithVolumesRefs(t *testing.T) {
d := NewDaemon(t)
if err := d.StartWithBusybox(); err != nil {
t.Fatal(err)
}
defer d.Stop()
if out, err := d.Cmd("run", "-d", "--name", "volrestarttest1", "-v", "/foo", "busybox"); err != nil {
t.Fatal(err, out)
}
if err := d.Restart(); err != nil {
t.Fatal(err)
}
if _, err := d.Cmd("run", "-d", "--volumes-from", "volrestarttest1", "--name", "volrestarttest2", "busybox"); err != nil {
t.Fatal(err)
}
if out, err := d.Cmd("rm", "-fv", "volrestarttest2"); err != nil {
t.Fatal(err, out)
}
v, err := d.Cmd("inspect", "--format", "{{ json .Volumes }}", "volrestarttest1")
if err != nil {
t.Fatal(err)
}
volumes := make(map[string]string)
json.Unmarshal([]byte(v), &volumes)
if _, err := os.Stat(volumes["/foo"]); err != nil {
t.Fatalf("Expected volume to exist: %s - %s", volumes["/foo"], err)
}
logDone("daemon - volume refs are restored")
}

View File

@ -8,6 +8,7 @@ import (
"sync" "sync"
"github.com/docker/docker/daemon/graphdriver" "github.com/docker/docker/daemon/graphdriver"
"github.com/docker/docker/pkg/log"
"github.com/docker/docker/utils" "github.com/docker/docker/utils"
) )
@ -83,11 +84,31 @@ func (r *Repository) restore() error {
return err return err
} }
var ids []string
for _, v := range dir { for _, v := range dir {
id := v.Name() id := v.Name()
if r.driver.Exists(id) { path, err := r.driver.Get(id, "")
ids = append(ids, id) if err != nil {
log.Debugf("Could not find volume for %s: %v", id, err)
continue
}
vol := &Volume{
ID: id,
configPath: r.configPath + "/" + id,
containers: make(map[string]struct{}),
Path: path,
}
if err := vol.FromDisk(); err != nil {
if !os.IsNotExist(err) {
log.Debugf("Error restoring volume: %v", err)
continue
}
if err := vol.initialize(); err != nil {
log.Debugf("%s", err)
continue
}
}
if err := r.add(vol); err != nil {
log.Debugf("Error restoring volume: %v", err)
} }
} }
return nil return nil
@ -173,7 +194,7 @@ func (r *Repository) createNewVolumePath(id string) (string, error) {
path, err := r.driver.Get(id, "") path, err := r.driver.Get(id, "")
if err != nil { if err != nil {
return "", fmt.Errorf("Driver %s failed to get volume rootfs %s: %s", r.driver, id, err) return "", fmt.Errorf("Driver %s failed to get volume rootfs %s: %v", r.driver, id, err)
} }
return path, nil return path, nil