Pārlūkot izejas kodu

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>
Brian Goff 10 gadi atpakaļ
vecāks
revīzija
9acf7c765c

+ 1 - 3
daemon/daemon.go

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

+ 6 - 0
daemon/volumes.go

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

+ 34 - 0
integration-cli/docker_cli_daemon_test.go

@@ -1,6 +1,8 @@
 package main
 
 import (
+	"encoding/json"
+	"os"
 	"strings"
 	"testing"
 )
@@ -48,3 +50,35 @@ func TestDaemonRestartWithRunningContainersPorts(t *testing.T) {
 
 	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")
+}

+ 25 - 4
volumes/repository.go

@@ -8,6 +8,7 @@ import (
 	"sync"
 
 	"github.com/docker/docker/daemon/graphdriver"
+	"github.com/docker/docker/pkg/log"
 	"github.com/docker/docker/utils"
 )
 
@@ -83,11 +84,31 @@ func (r *Repository) restore() error {
 		return err
 	}
 
-	var ids []string
 	for _, v := range dir {
 		id := v.Name()
-		if r.driver.Exists(id) {
-			ids = append(ids, id)
+		path, err := r.driver.Get(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
@@ -173,7 +194,7 @@ func (r *Repository) createNewVolumePath(id string) (string, error) {
 
 	path, err := r.driver.Get(id, "")
 	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