Browse code

Fix volume ref restore process

Fixes #9629 #9768

A couple of issues:

1) Volume config is not restored if we couldn't find it with the graph
driver, but bind-mounts would never be found by the graph driver since
they aren't in that dir

2) container volumes were only being restored if they were found in the
volumes repo, but volumes created by old daemons wouldn't be in the
repo until the container is at least started.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>

Brian Goff authored on 2015/01/17 04:48:25
Showing 4 changed files
... ...
@@ -7,6 +7,7 @@ import (
7 7
 	"io/ioutil"
8 8
 	"os"
9 9
 	"path"
10
+	"path/filepath"
10 11
 	"regexp"
11 12
 	"runtime"
12 13
 	"strings"
... ...
@@ -237,6 +238,8 @@ func (daemon *Daemon) register(container *Container, updateSuffixarray bool) err
237 237
 	// we'll waste time if we update it for every container
238 238
 	daemon.idIndex.Add(container.ID)
239 239
 
240
+	container.registerVolumes()
241
+
240 242
 	// FIXME: if the container is supposed to be running but is not, auto restart it?
241 243
 	//        if so, then we need to restart monitor and init a new lock
242 244
 	// If the container is supposed to be running, make sure of it
... ...
@@ -400,10 +403,6 @@ func (daemon *Daemon) restore() error {
400 400
 		}
401 401
 	}
402 402
 
403
-	for _, c := range registeredContainers {
404
-		c.registerVolumes()
405
-	}
406
-
407 403
 	if !debug {
408 404
 		fmt.Println()
409 405
 		log.Infof("Loading containers: done.")
... ...
@@ -890,7 +889,7 @@ func NewDaemonFromDirectory(config *Config, eng *engine.Engine) (*Daemon, error)
890 890
 		return nil, err
891 891
 	}
892 892
 
893
-	volumes, err := volumes.NewRepository(path.Join(config.Root, "volumes"), volumesDriver)
893
+	volumes, err := volumes.NewRepository(filepath.Join(config.Root, "volumes"), volumesDriver)
894 894
 	if err != nil {
895 895
 		return nil, err
896 896
 	}
... ...
@@ -119,8 +119,23 @@ func (container *Container) VolumePaths() map[string]struct{} {
119 119
 }
120 120
 
121 121
 func (container *Container) registerVolumes() {
122
-	for _, mnt := range container.VolumeMounts() {
123
-		mnt.volume.AddContainer(container.ID)
122
+	for path := range container.VolumePaths() {
123
+		if v := container.daemon.volumes.Get(path); v != nil {
124
+			v.AddContainer(container.ID)
125
+			continue
126
+		}
127
+
128
+		// if container was created with an old daemon, this volume may not be registered so we need to make sure it gets registered
129
+		writable := true
130
+		if rw, exists := container.VolumesRW[path]; exists {
131
+			writable = rw
132
+		}
133
+		v, err := container.daemon.volumes.FindOrCreateVolume(path, writable)
134
+		if err != nil {
135
+			log.Debugf("error registering volume %s: %v", path, err)
136
+			continue
137
+		}
138
+		v.AddContainer(container.ID)
124 139
 	}
125 140
 }
126 141
 
... ...
@@ -317,3 +317,36 @@ func TestDaemonAllocatesListeningPort(t *testing.T) {
317 317
 
318 318
 	logDone("daemon - daemon listening port is allocated")
319 319
 }
320
+
321
+// #9629
322
+func TestDaemonVolumesBindsRefs(t *testing.T) {
323
+	d := NewDaemon(t)
324
+
325
+	if err := d.StartWithBusybox(); err != nil {
326
+		t.Fatal(err)
327
+	}
328
+
329
+	tmp, err := ioutil.TempDir(os.TempDir(), "")
330
+	if err != nil {
331
+		t.Fatal(err)
332
+	}
333
+	defer os.RemoveAll(tmp)
334
+
335
+	if err := ioutil.WriteFile(tmp+"/test", []byte("testing"), 0655); err != nil {
336
+		t.Fatal(err)
337
+	}
338
+
339
+	if out, err := d.Cmd("create", "-v", tmp+":/foo", "--name=voltest", "busybox"); err != nil {
340
+		t.Fatal(err, out)
341
+	}
342
+
343
+	if err := d.Restart(); err != nil {
344
+		t.Fatal(err)
345
+	}
346
+
347
+	if out, err := d.Cmd("run", "--volumes-from=voltest", "--name=consumer", "busybox", "/bin/sh", "-c", "[ -f /foo/test ]"); err != nil {
348
+		t.Fatal(err, out)
349
+	}
350
+
351
+	logDone("daemon - bind refs in data-containers survive daemon restart")
352
+}
... ...
@@ -87,16 +87,10 @@ func (r *Repository) restore() error {
87 87
 
88 88
 	for _, v := range dir {
89 89
 		id := v.Name()
90
-		path, err := r.driver.Get(id, "")
91
-		if err != nil {
92
-			log.Debugf("Could not find volume for %s: %v", id, err)
93
-			continue
94
-		}
95 90
 		vol := &Volume{
96 91
 			ID:         id,
97 92
 			configPath: r.configPath + "/" + id,
98 93
 			containers: make(map[string]struct{}),
99
-			Path:       path,
100 94
 		}
101 95
 		if err := vol.FromDisk(); err != nil {
102 96
 			if !os.IsNotExist(err) {