Browse code

Merge pull request #16534 from cpuguy83/make_volume_drivers_responsible

Move responsibility of ls/inspect to volume driver

Phil Estes authored on 2016/01/06 07:29:51
Showing 30 changed files
... ...
@@ -65,6 +65,9 @@ func (cli *DockerCli) CmdVolumeLs(args ...string) error {
65 65
 
66 66
 	w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
67 67
 	if !*quiet {
68
+		for _, warn := range volumes.Warnings {
69
+			fmt.Fprintln(cli.err, warn)
70
+		}
68 71
 		fmt.Fprintf(w, "DRIVER \tVOLUME NAME")
69 72
 		fmt.Fprintf(w, "\n")
70 73
 	}
... ...
@@ -102,7 +105,7 @@ func (cli *DockerCli) CmdVolumeInspect(args ...string) error {
102 102
 	return cli.inspectElements(*tmplStr, cmd.Args(), inspectSearcher)
103 103
 }
104 104
 
105
-// CmdVolumeCreate creates a new container from a given image.
105
+// CmdVolumeCreate creates a new volume.
106 106
 //
107 107
 // Usage: docker volume create [OPTIONS]
108 108
 func (cli *DockerCli) CmdVolumeCreate(args ...string) error {
... ...
@@ -131,7 +134,7 @@ func (cli *DockerCli) CmdVolumeCreate(args ...string) error {
131 131
 	return nil
132 132
 }
133 133
 
134
-// CmdVolumeRm removes one or more containers.
134
+// CmdVolumeRm removes one or more volumes.
135 135
 //
136 136
 // Usage: docker volume rm VOLUME [VOLUME...]
137 137
 func (cli *DockerCli) CmdVolumeRm(args ...string) error {
... ...
@@ -140,6 +143,7 @@ func (cli *DockerCli) CmdVolumeRm(args ...string) error {
140 140
 	cmd.ParseFlags(args, true)
141 141
 
142 142
 	var status = 0
143
+
143 144
 	for _, name := range cmd.Args() {
144 145
 		if err := cli.client.VolumeRemove(name); err != nil {
145 146
 			fmt.Fprintf(cli.err, "%s\n", err)
... ...
@@ -8,7 +8,7 @@ import (
8 8
 // Backend is the methods that need to be implemented to provide
9 9
 // volume specific functionality
10 10
 type Backend interface {
11
-	Volumes(filter string) ([]*types.Volume, error)
11
+	Volumes(filter string) ([]*types.Volume, []string, error)
12 12
 	VolumeInspect(name string) (*types.Volume, error)
13 13
 	VolumeCreate(name, driverName string,
14 14
 		opts map[string]string) (*types.Volume, error)
... ...
@@ -14,11 +14,11 @@ func (v *volumeRouter) getVolumesList(ctx context.Context, w http.ResponseWriter
14 14
 		return err
15 15
 	}
16 16
 
17
-	volumes, err := v.backend.Volumes(r.Form.Get("filters"))
17
+	volumes, warnings, err := v.backend.Volumes(r.Form.Get("filters"))
18 18
 	if err != nil {
19 19
 		return err
20 20
 	}
21
-	return httputils.WriteJSON(w, http.StatusOK, &types.VolumesListResponse{Volumes: volumes})
21
+	return httputils.WriteJSON(w, http.StatusOK, &types.VolumesListResponse{Volumes: volumes, Warnings: warnings})
22 22
 }
23 23
 
24 24
 func (v *volumeRouter) getVolumeByName(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
... ...
@@ -366,7 +366,8 @@ type Volume struct {
366 366
 // VolumesListResponse contains the response for the remote API:
367 367
 // GET "/volumes"
368 368
 type VolumesListResponse struct {
369
-	Volumes []*Volume // Volumes is the list of volumes being returned
369
+	Volumes  []*Volume // Volumes is the list of volumes being returned
370
+	Warnings []string  // Warnings is a list of warnings that occurred when getting the list from the volume drivers
370 371
 }
371 372
 
372 373
 // VolumeCreateRequest contains the response for the remote API:
... ...
@@ -10,7 +10,7 @@ import (
10 10
 	"github.com/docker/docker/layer"
11 11
 	"github.com/docker/docker/pkg/idtools"
12 12
 	"github.com/docker/docker/pkg/stringid"
13
-	"github.com/docker/docker/volume"
13
+	volumestore "github.com/docker/docker/volume/store"
14 14
 	"github.com/opencontainers/runc/libcontainer/label"
15 15
 )
16 16
 
... ...
@@ -162,17 +162,12 @@ func (daemon *Daemon) VolumeCreate(name, driverName string, opts map[string]stri
162 162
 
163 163
 	v, err := daemon.volumes.Create(name, driverName, opts)
164 164
 	if err != nil {
165
+		if volumestore.IsNameConflict(err) {
166
+			return nil, derr.ErrorVolumeNameTaken.WithArgs(name)
167
+		}
165 168
 		return nil, err
166 169
 	}
167 170
 
168
-	// keep "docker run -v existing_volume:/foo --volume-driver other_driver" work
169
-	if (driverName != "" && v.DriverName() != driverName) || (driverName == "" && v.DriverName() != volume.DefaultDriverName) {
170
-		return nil, derr.ErrorVolumeNameTaken.WithArgs(name, v.DriverName())
171
-	}
172
-
173
-	if driverName == "" {
174
-		driverName = volume.DefaultDriverName
175
-	}
176
-	daemon.LogVolumeEvent(name, "create", map[string]string{"driver": driverName})
171
+	daemon.LogVolumeEvent(v.Name(), "create", map[string]string{"driver": v.DriverName()})
177 172
 	return volumeToAPIType(v), nil
178 173
 }
... ...
@@ -51,7 +51,7 @@ func (daemon *Daemon) createContainerPlatformSpecificSettings(container *contain
51 51
 			}
52 52
 		}
53 53
 
54
-		v, err := daemon.createVolume(name, volumeDriver, nil)
54
+		v, err := daemon.volumes.CreateWithRef(name, volumeDriver, container.ID, nil)
55 55
 		if err != nil {
56 56
 			return err
57 57
 		}
... ...
@@ -42,7 +42,7 @@ func (daemon *Daemon) createContainerPlatformSpecificSettings(container *contain
42 42
 
43 43
 		// Create the volume in the volume driver. If it doesn't exist,
44 44
 		// a new one will be created.
45
-		v, err := daemon.createVolume(mp.Name, volumeDriver, nil)
45
+		v, err := daemon.volumes.CreateWithRef(mp.Name, volumeDriver, container.ID, nil)
46 46
 		if err != nil {
47 47
 			return err
48 48
 		}
... ...
@@ -1487,10 +1487,7 @@ func configureVolumes(config *Config, rootUID, rootGID int) (*store.VolumeStore,
1487 1487
 	}
1488 1488
 
1489 1489
 	volumedrivers.Register(volumesDriver, volumesDriver.Name())
1490
-	s := store.New()
1491
-	s.AddAll(volumesDriver.List())
1492
-
1493
-	return s, nil
1490
+	return store.New(), nil
1494 1491
 }
1495 1492
 
1496 1493
 // AuthenticateToRegistry checks the validity of credentials in authConfig
... ...
@@ -151,6 +151,7 @@ func (daemon *Daemon) VolumeRm(name string) error {
151 151
 	if err != nil {
152 152
 		return err
153 153
 	}
154
+
154 155
 	if err := daemon.volumes.Remove(v); err != nil {
155 156
 		if volumestore.IsInUse(err) {
156 157
 			return derr.ErrorCodeRmVolumeInUse.WithArgs(err)
... ...
@@ -392,24 +392,27 @@ func (daemon *Daemon) transformContainer(container *container.Container, ctx *li
392 392
 
393 393
 // Volumes lists known volumes, using the filter to restrict the range
394 394
 // of volumes returned.
395
-func (daemon *Daemon) Volumes(filter string) ([]*types.Volume, error) {
395
+func (daemon *Daemon) Volumes(filter string) ([]*types.Volume, []string, error) {
396 396
 	var volumesOut []*types.Volume
397 397
 	volFilters, err := filters.FromParam(filter)
398 398
 	if err != nil {
399
-		return nil, err
399
+		return nil, nil, err
400 400
 	}
401 401
 
402 402
 	filterUsed := volFilters.Include("dangling") &&
403 403
 		(volFilters.ExactMatch("dangling", "true") || volFilters.ExactMatch("dangling", "1"))
404 404
 
405
-	volumes := daemon.volumes.List()
405
+	volumes, warnings, err := daemon.volumes.List()
406
+	if err != nil {
407
+		return nil, nil, err
408
+	}
409
+	if filterUsed {
410
+		volumes = daemon.volumes.FilterByUsed(volumes)
411
+	}
406 412
 	for _, v := range volumes {
407
-		if filterUsed && daemon.volumes.Count(v) > 0 {
408
-			continue
409
-		}
410 413
 		volumesOut = append(volumesOut, volumeToAPIType(v))
411 414
 	}
412
-	return volumesOut, nil
415
+	return volumesOut, warnings, nil
413 416
 }
414 417
 
415 418
 func populateImageFilterByParents(ancestorMap map[image.ID]bool, imageID image.ID, getChildren func(image.ID) []image.ID) {
... ...
@@ -11,10 +11,11 @@ import (
11 11
 func (daemon *Daemon) prepareMountPoints(container *container.Container) error {
12 12
 	for _, config := range container.MountPoints {
13 13
 		if len(config.Driver) > 0 {
14
-			v, err := daemon.createVolume(config.Name, config.Driver, nil)
14
+			v, err := daemon.volumes.GetWithRef(config.Name, config.Driver, container.ID)
15 15
 			if err != nil {
16 16
 				return err
17 17
 			}
18
+
18 19
 			config.Volume = v
19 20
 		}
20 21
 	}
... ...
@@ -27,10 +28,10 @@ func (daemon *Daemon) removeMountPoints(container *container.Container, rm bool)
27 27
 		if m.Volume == nil {
28 28
 			continue
29 29
 		}
30
-		daemon.volumes.Decrement(m.Volume)
30
+		daemon.volumes.Dereference(m.Volume, container.ID)
31 31
 		if rm {
32 32
 			err := daemon.volumes.Remove(m.Volume)
33
-			// ErrVolumeInUse is ignored because having this
33
+			// Ignore volume in use errors because having this
34 34
 			// volume being referenced by other container is
35 35
 			// not an error, but an implementation detail.
36 36
 			// This prevents docker from logging "ERROR: Volume in use"
... ...
@@ -32,16 +32,6 @@ func volumeToAPIType(v volume.Volume) *types.Volume {
32 32
 	}
33 33
 }
34 34
 
35
-// createVolume creates a volume.
36
-func (daemon *Daemon) createVolume(name, driverName string, opts map[string]string) (volume.Volume, error) {
37
-	v, err := daemon.volumes.Create(name, driverName, opts)
38
-	if err != nil {
39
-		return nil, err
40
-	}
41
-	daemon.volumes.Increment(v)
42
-	return v, nil
43
-}
44
-
45 35
 // Len returns the number of mounts. Used in sorting.
46 36
 func (m mounts) Len() int {
47 37
 	return len(m)
... ...
@@ -103,7 +93,7 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
103 103
 			}
104 104
 
105 105
 			if len(cp.Source) == 0 {
106
-				v, err := daemon.createVolume(cp.Name, cp.Driver, nil)
106
+				v, err := daemon.volumes.GetWithRef(cp.Name, cp.Driver, container.ID)
107 107
 				if err != nil {
108 108
 					return err
109 109
 				}
... ...
@@ -128,7 +118,7 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
128 128
 
129 129
 		if len(bind.Name) > 0 && len(bind.Driver) > 0 {
130 130
 			// create the volume
131
-			v, err := daemon.createVolume(bind.Name, bind.Driver, nil)
131
+			v, err := daemon.volumes.CreateWithRef(bind.Name, bind.Driver, container.ID, nil)
132 132
 			if err != nil {
133 133
 				return err
134 134
 			}
... ...
@@ -153,7 +143,7 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
153 153
 	for _, m := range mountPoints {
154 154
 		if m.BackwardsCompatible() {
155 155
 			if mp, exists := container.MountPoints[m.Destination]; exists && mp.Volume != nil {
156
-				daemon.volumes.Decrement(mp.Volume)
156
+				daemon.volumes.Dereference(mp.Volume, container.ID)
157 157
 			}
158 158
 		}
159 159
 	}
... ...
@@ -908,7 +908,7 @@ var (
908 908
 	// trying to create a volume that has existed using different driver.
909 909
 	ErrorVolumeNameTaken = errcode.Register(errGroup, errcode.ErrorDescriptor{
910 910
 		Value:          "VOLUME_NAME_TAKEN",
911
-		Message:        "A volume named %q already exists with the %q driver. Choose a different volume name.",
911
+		Message:        "A volume named %s already exists. Choose a different volume name.",
912 912
 		Description:    "An attempt to create a volume using a driver but the volume already exists with a different driver",
913 913
 		HTTPStatusCode: http.StatusInternalServerError,
914 914
 	})
... ...
@@ -1733,8 +1733,8 @@ func (s *DockerDaemonSuite) TestDaemonRestartRmVolumeInUse(c *check.C) {
1733 1733
 	c.Assert(s.d.Restart(), check.IsNil)
1734 1734
 
1735 1735
 	out, err = s.d.Cmd("volume", "rm", "test")
1736
-	c.Assert(err, check.Not(check.IsNil), check.Commentf("should not be able to remove in use volume after daemon restart"))
1737
-	c.Assert(strings.Contains(out, "in use"), check.Equals, true)
1736
+	c.Assert(err, check.NotNil, check.Commentf("should not be able to remove in use volume after daemon restart"))
1737
+	c.Assert(out, checker.Contains, "in use")
1738 1738
 }
1739 1739
 
1740 1740
 func (s *DockerDaemonSuite) TestDaemonRestartLocalVolumes(c *check.C) {
... ...
@@ -32,6 +32,8 @@ type eventCounter struct {
32 32
 	mounts      int
33 33
 	unmounts    int
34 34
 	paths       int
35
+	lists       int
36
+	gets        int
35 37
 }
36 38
 
37 39
 type DockerExternalVolumeSuite struct {
... ...
@@ -64,6 +66,12 @@ func (s *DockerExternalVolumeSuite) SetUpSuite(c *check.C) {
64 64
 		Err        string `json:",omitempty"`
65 65
 	}
66 66
 
67
+	type vol struct {
68
+		Name       string
69
+		Mountpoint string
70
+	}
71
+	var volList []vol
72
+
67 73
 	read := func(b io.ReadCloser) (pluginRequest, error) {
68 74
 		defer b.Close()
69 75
 		var pr pluginRequest
... ...
@@ -93,29 +101,61 @@ func (s *DockerExternalVolumeSuite) SetUpSuite(c *check.C) {
93 93
 
94 94
 	mux.HandleFunc("/VolumeDriver.Create", func(w http.ResponseWriter, r *http.Request) {
95 95
 		s.ec.creations++
96
+		pr, err := read(r.Body)
97
+		if err != nil {
98
+			send(w, err)
99
+			return
100
+		}
101
+		volList = append(volList, vol{Name: pr.Name})
102
+		send(w, nil)
103
+	})
96 104
 
97
-		_, err := read(r.Body)
105
+	mux.HandleFunc("/VolumeDriver.List", func(w http.ResponseWriter, r *http.Request) {
106
+		s.ec.lists++
107
+		send(w, map[string][]vol{"Volumes": volList})
108
+	})
109
+
110
+	mux.HandleFunc("/VolumeDriver.Get", func(w http.ResponseWriter, r *http.Request) {
111
+		s.ec.gets++
112
+		pr, err := read(r.Body)
98 113
 		if err != nil {
99 114
 			send(w, err)
100 115
 			return
101 116
 		}
102 117
 
103
-		send(w, nil)
118
+		for _, v := range volList {
119
+			if v.Name == pr.Name {
120
+				v.Mountpoint = hostVolumePath(pr.Name)
121
+				send(w, map[string]vol{"Volume": v})
122
+				return
123
+			}
124
+		}
125
+		send(w, `{"Err": "no such volume"}`)
104 126
 	})
105 127
 
106 128
 	mux.HandleFunc("/VolumeDriver.Remove", func(w http.ResponseWriter, r *http.Request) {
107 129
 		s.ec.removals++
108
-
109 130
 		pr, err := read(r.Body)
110 131
 		if err != nil {
111 132
 			send(w, err)
112 133
 			return
113 134
 		}
135
+
114 136
 		if err := os.RemoveAll(hostVolumePath(pr.Name)); err != nil {
115 137
 			send(w, &pluginResp{Err: err.Error()})
116 138
 			return
117 139
 		}
118 140
 
141
+		for i, v := range volList {
142
+			if v.Name == pr.Name {
143
+				if err := os.RemoveAll(hostVolumePath(v.Name)); err != nil {
144
+					send(w, fmt.Sprintf(`{"Err": "%v"}`, err))
145
+					return
146
+				}
147
+				volList = append(volList[:i], volList[i+1:]...)
148
+				break
149
+			}
150
+		}
119 151
 		send(w, nil)
120 152
 	})
121 153
 
... ...
@@ -128,8 +168,7 @@ func (s *DockerExternalVolumeSuite) SetUpSuite(c *check.C) {
128 128
 			return
129 129
 		}
130 130
 		p := hostVolumePath(pr.Name)
131
-
132
-		fmt.Fprintln(w, fmt.Sprintf("{\"Mountpoint\": \"%s\"}", p))
131
+		send(w, &pluginResp{Mountpoint: p})
133 132
 	})
134 133
 
135 134
 	mux.HandleFunc("/VolumeDriver.Mount", func(w http.ResponseWriter, r *http.Request) {
... ...
@@ -164,7 +203,7 @@ func (s *DockerExternalVolumeSuite) SetUpSuite(c *check.C) {
164 164
 			return
165 165
 		}
166 166
 
167
-		fmt.Fprintln(w, nil)
167
+		send(w, nil)
168 168
 	})
169 169
 
170 170
 	err := os.MkdirAll("/etc/docker/plugins", 0755)
... ...
@@ -287,8 +326,8 @@ func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverNamedCheckBindLocalV
287 287
 // Make sure a request to use a down driver doesn't block other requests
288 288
 func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverLookupNotBlocked(c *check.C) {
289 289
 	specPath := "/etc/docker/plugins/down-driver.spec"
290
-	err := ioutil.WriteFile("/etc/docker/plugins/down-driver.spec", []byte("tcp://127.0.0.7:9999"), 0644)
291
-	c.Assert(err, checker.IsNil)
290
+	err := ioutil.WriteFile(specPath, []byte("tcp://127.0.0.7:9999"), 0644)
291
+	c.Assert(err, check.IsNil)
292 292
 	defer os.RemoveAll(specPath)
293 293
 
294 294
 	chCmd1 := make(chan struct{})
... ...
@@ -316,10 +355,11 @@ func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverLookupNotBlocked(c *
316 316
 	case err := <-chCmd2:
317 317
 		c.Assert(err, checker.IsNil)
318 318
 	case <-time.After(5 * time.Second):
319
-		c.Fatal("volume creates are blocked by previous create requests when previous driver is down")
320 319
 		cmd2.Process.Kill()
320
+		c.Fatal("volume creates are blocked by previous create requests when previous driver is down")
321 321
 	}
322 322
 }
323
+
323 324
 func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverRetryNotImmediatelyExists(c *check.C) {
324 325
 	err := s.d.StartWithBusybox()
325 326
 	c.Assert(err, checker.IsNil)
... ...
@@ -371,3 +411,24 @@ func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverBindExternalVolume(c
371 371
 	c.Assert(mounts[0].Name, checker.Equals, "foo")
372 372
 	c.Assert(mounts[0].Driver, checker.Equals, "test-external-volume-driver")
373 373
 }
374
+
375
+func (s *DockerExternalVolumeSuite) TestStartExternalVolumeDriverList(c *check.C) {
376
+	dockerCmd(c, "volume", "create", "-d", "test-external-volume-driver", "--name", "abc")
377
+	out, _ := dockerCmd(c, "volume", "ls")
378
+	ls := strings.Split(strings.TrimSpace(out), "\n")
379
+	c.Assert(len(ls), check.Equals, 2, check.Commentf("\n%s", out))
380
+
381
+	vol := strings.Fields(ls[len(ls)-1])
382
+	c.Assert(len(vol), check.Equals, 2, check.Commentf("%v", vol))
383
+	c.Assert(vol[0], check.Equals, "test-external-volume-driver")
384
+	c.Assert(vol[1], check.Equals, "abc")
385
+
386
+	c.Assert(s.ec.lists, check.Equals, 1)
387
+}
388
+
389
+func (s *DockerExternalVolumeSuite) TestStartExternalVolumeDriverGet(c *check.C) {
390
+	out, _, err := dockerCmdWithError("volume", "inspect", "dummy")
391
+	c.Assert(err, check.NotNil, check.Commentf(out))
392
+	c.Assert(s.ec.gets, check.Equals, 1)
393
+	c.Assert(out, checker.Contains, "No such volume")
394
+}
... ...
@@ -4,9 +4,7 @@ import (
4 4
 	"os/exec"
5 5
 	"strings"
6 6
 
7
-	derr "github.com/docker/docker/errors"
8 7
 	"github.com/docker/docker/pkg/integration/checker"
9
-	"github.com/docker/docker/volume"
10 8
 	"github.com/go-check/check"
11 9
 )
12 10
 
... ...
@@ -25,8 +23,7 @@ func (s *DockerSuite) TestVolumeCliCreateOptionConflict(c *check.C) {
25 25
 	dockerCmd(c, "volume", "create", "--name=test")
26 26
 	out, _, err := dockerCmdWithError("volume", "create", "--name", "test", "--driver", "nosuchdriver")
27 27
 	c.Assert(err, check.NotNil, check.Commentf("volume create exception name already in use with another driver"))
28
-	stderr := derr.ErrorVolumeNameTaken.WithArgs("test", volume.DefaultDriverName).Error()
29
-	c.Assert(strings.Contains(out, strings.TrimPrefix(stderr, "volume name taken: ")), check.Equals, true)
28
+	c.Assert(out, checker.Contains, "A volume named test already exists")
30 29
 
31 30
 	out, _ = dockerCmd(c, "volume", "inspect", "--format='{{ .Driver }}'", "test")
32 31
 	_, _, err = dockerCmdWithError("volume", "create", "--name", "test", "--driver", strings.TrimSpace(out))
... ...
@@ -25,6 +25,38 @@ func newLocalRegistry() localRegistry {
25 25
 	return localRegistry{}
26 26
 }
27 27
 
28
+// Scan scans all the plugin paths and returns all the names it found
29
+func Scan() ([]string, error) {
30
+	var names []string
31
+	if err := filepath.Walk(socketsPath, func(path string, fi os.FileInfo, err error) error {
32
+		if err != nil {
33
+			return nil
34
+		}
35
+
36
+		if fi.Mode()&os.ModeSocket != 0 {
37
+			name := strings.TrimSuffix(fi.Name(), filepath.Ext(fi.Name()))
38
+			names = append(names, name)
39
+		}
40
+		return nil
41
+	}); err != nil {
42
+		return nil, err
43
+	}
44
+
45
+	for _, path := range specsPaths {
46
+		if err := filepath.Walk(path, func(p string, fi os.FileInfo, err error) error {
47
+			if err != nil || fi.IsDir() {
48
+				return nil
49
+			}
50
+			name := strings.TrimSuffix(fi.Name(), filepath.Ext(fi.Name()))
51
+			names = append(names, name)
52
+			return nil
53
+		}); err != nil {
54
+			return nil, err
55
+		}
56
+	}
57
+	return names, nil
58
+}
59
+
28 60
 // Plugin returns the plugin registered with the given name (or returns an error).
29 61
 func (l *localRegistry) Plugin(name string) (*Plugin, error) {
30 62
 	socketpaths := pluginPaths(socketsPath, name, ".sock")
... ...
@@ -108,6 +108,15 @@ func (p *Plugin) activateWithLock() error {
108 108
 	return nil
109 109
 }
110 110
 
111
+func (p *Plugin) implements(kind string) bool {
112
+	for _, driver := range p.Manifest.Implements {
113
+		if driver == kind {
114
+			return true
115
+		}
116
+	}
117
+	return false
118
+}
119
+
111 120
 func load(name string) (*Plugin, error) {
112 121
 	return loadWithRetry(name, true)
113 122
 }
... ...
@@ -166,11 +175,9 @@ func Get(name, imp string) (*Plugin, error) {
166 166
 	if err != nil {
167 167
 		return nil, err
168 168
 	}
169
-	for _, driver := range pl.Manifest.Implements {
170
-		logrus.Debugf("%s implements: %s", name, driver)
171
-		if driver == imp {
172
-			return pl, nil
173
-		}
169
+	if pl.implements(imp) {
170
+		logrus.Debugf("%s implements: %s", name, imp)
171
+		return pl, nil
174 172
 	}
175 173
 	return nil, ErrNotImplements
176 174
 }
... ...
@@ -179,3 +186,37 @@ func Get(name, imp string) (*Plugin, error) {
179 179
 func Handle(iface string, fn func(string, *Client)) {
180 180
 	extpointHandlers[iface] = fn
181 181
 }
182
+
183
+// GetAll returns all the plugins for the specified implementation
184
+func GetAll(imp string) ([]*Plugin, error) {
185
+	pluginNames, err := Scan()
186
+	if err != nil {
187
+		return nil, err
188
+	}
189
+
190
+	type plLoad struct {
191
+		pl  *Plugin
192
+		err error
193
+	}
194
+
195
+	chPl := make(chan plLoad, len(pluginNames))
196
+	for _, name := range pluginNames {
197
+		go func(name string) {
198
+			pl, err := loadWithRetry(name, false)
199
+			chPl <- plLoad{pl, err}
200
+		}(name)
201
+	}
202
+
203
+	var out []*Plugin
204
+	for i := 0; i < len(pluginNames); i++ {
205
+		pl := <-chPl
206
+		if pl.err != nil {
207
+			logrus.Error(err)
208
+			continue
209
+		}
210
+		if pl.pl.implements(imp) {
211
+			out = append(out, pl.pl)
212
+		}
213
+	}
214
+	return out, nil
215
+}
... ...
@@ -26,6 +26,38 @@ func (a *volumeDriverAdapter) Remove(v volume.Volume) error {
26 26
 	return a.proxy.Remove(v.Name())
27 27
 }
28 28
 
29
+func (a *volumeDriverAdapter) List() ([]volume.Volume, error) {
30
+	ls, err := a.proxy.List()
31
+	if err != nil {
32
+		return nil, err
33
+	}
34
+
35
+	var out []volume.Volume
36
+	for _, vp := range ls {
37
+		out = append(out, &volumeAdapter{
38
+			proxy:      a.proxy,
39
+			name:       vp.Name,
40
+			driverName: a.name,
41
+			eMount:     vp.Mountpoint,
42
+		})
43
+	}
44
+	return out, nil
45
+}
46
+
47
+func (a *volumeDriverAdapter) Get(name string) (volume.Volume, error) {
48
+	v, err := a.proxy.Get(name)
49
+	if err != nil {
50
+		return nil, err
51
+	}
52
+
53
+	return &volumeAdapter{
54
+		proxy:      a.proxy,
55
+		name:       v.Name,
56
+		driverName: a.Name(),
57
+		eMount:     v.Mountpoint,
58
+	}, nil
59
+}
60
+
29 61
 type volumeAdapter struct {
30 62
 	proxy      *volumeDriverProxy
31 63
 	name       string
... ...
@@ -15,6 +15,8 @@ import (
15 15
 
16 16
 var drivers = &driverExtpoint{extensions: make(map[string]volume.Driver)}
17 17
 
18
+const extName = "VolumeDriver"
19
+
18 20
 // NewVolumeDriver returns a driver has the given name mapped on the given client.
19 21
 func NewVolumeDriver(name string, c client) volume.Driver {
20 22
 	proxy := &volumeDriverProxy{c}
... ...
@@ -22,6 +24,7 @@ func NewVolumeDriver(name string, c client) volume.Driver {
22 22
 }
23 23
 
24 24
 type opts map[string]string
25
+type list []*proxyVolume
25 26
 
26 27
 // volumeDriver defines the available functions that volume plugins must implement.
27 28
 // This interface is only defined to generate the proxy objects.
... ...
@@ -37,6 +40,10 @@ type volumeDriver interface {
37 37
 	Mount(name string) (mountpoint string, err error)
38 38
 	// Unmount the given volume
39 39
 	Unmount(name string) (err error)
40
+	// List lists all the volumes known to the driver
41
+	List() (volumes list, err error)
42
+	// Get retreives the volume with the requested name
43
+	Get(name string) (volume *proxyVolume, err error)
40 44
 }
41 45
 
42 46
 type driverExtpoint struct {
... ...
@@ -82,7 +89,7 @@ func Lookup(name string) (volume.Driver, error) {
82 82
 	if ok {
83 83
 		return ext, nil
84 84
 	}
85
-	pl, err := plugins.Get(name, "VolumeDriver")
85
+	pl, err := plugins.Get(name, extName)
86 86
 	if err != nil {
87 87
 		return nil, fmt.Errorf("Error looking up volume plugin %s: %v", name, err)
88 88
 	}
... ...
@@ -116,3 +123,30 @@ func GetDriverList() []string {
116 116
 	}
117 117
 	return driverList
118 118
 }
119
+
120
+// GetAllDrivers lists all the registered drivers
121
+func GetAllDrivers() ([]volume.Driver, error) {
122
+	plugins, err := plugins.GetAll(extName)
123
+	if err != nil {
124
+		return nil, err
125
+	}
126
+	var ds []volume.Driver
127
+
128
+	drivers.Lock()
129
+	defer drivers.Unlock()
130
+
131
+	for _, d := range drivers.extensions {
132
+		ds = append(ds, d)
133
+	}
134
+
135
+	for _, p := range plugins {
136
+		ext, ok := drivers.extensions[p.Name]
137
+		if ok {
138
+			continue
139
+		}
140
+		ext = NewVolumeDriver(p.Name, p.Client)
141
+		drivers.extensions[p.Name] = ext
142
+		ds = append(ds, ext)
143
+	}
144
+	return ds, nil
145
+}
... ...
@@ -11,7 +11,8 @@ func TestGetDriver(t *testing.T) {
11 11
 	if err == nil {
12 12
 		t.Fatal("Expected error, was nil")
13 13
 	}
14
-	Register(volumetestutils.FakeDriver{}, "fake")
14
+
15
+	Register(volumetestutils.NewFakeDriver("fake"), "fake")
15 16
 	d, err := GetDriver("fake")
16 17
 	if err != nil {
17 18
 		t.Fatal(err)
... ...
@@ -149,3 +149,59 @@ func (pp *volumeDriverProxy) Unmount(name string) (err error) {
149 149
 
150 150
 	return
151 151
 }
152
+
153
+type volumeDriverProxyListRequest struct {
154
+}
155
+
156
+type volumeDriverProxyListResponse struct {
157
+	Volumes list
158
+	Err     string
159
+}
160
+
161
+func (pp *volumeDriverProxy) List() (volumes list, err error) {
162
+	var (
163
+		req volumeDriverProxyListRequest
164
+		ret volumeDriverProxyListResponse
165
+	)
166
+
167
+	if err = pp.Call("VolumeDriver.List", req, &ret); err != nil {
168
+		return
169
+	}
170
+
171
+	volumes = ret.Volumes
172
+
173
+	if ret.Err != "" {
174
+		err = errors.New(ret.Err)
175
+	}
176
+
177
+	return
178
+}
179
+
180
+type volumeDriverProxyGetRequest struct {
181
+	Name string
182
+}
183
+
184
+type volumeDriverProxyGetResponse struct {
185
+	Volume *proxyVolume
186
+	Err    string
187
+}
188
+
189
+func (pp *volumeDriverProxy) Get(name string) (volume *proxyVolume, err error) {
190
+	var (
191
+		req volumeDriverProxyGetRequest
192
+		ret volumeDriverProxyGetResponse
193
+	)
194
+
195
+	req.Name = name
196
+	if err = pp.Call("VolumeDriver.Get", req, &ret); err != nil {
197
+		return
198
+	}
199
+
200
+	volume = ret.Volume
201
+
202
+	if ret.Err != "" {
203
+		err = errors.New(ret.Err)
204
+	}
205
+
206
+	return
207
+}
... ...
@@ -42,6 +42,16 @@ func TestVolumeRequestError(t *testing.T) {
42 42
 		fmt.Fprintln(w, `{"Err": "Unknown volume"}`)
43 43
 	})
44 44
 
45
+	mux.HandleFunc("/VolumeDriver.List", func(w http.ResponseWriter, r *http.Request) {
46
+		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
47
+		fmt.Fprintln(w, `{"Err": "Cannot list volumes"}`)
48
+	})
49
+
50
+	mux.HandleFunc("/VolumeDriver.Get", func(w http.ResponseWriter, r *http.Request) {
51
+		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
52
+		fmt.Fprintln(w, `{"Err": "Cannot get volume"}`)
53
+	})
54
+
45 55
 	u, _ := url.Parse(server.URL)
46 56
 	client, err := plugins.NewClient("tcp://"+u.Host, tlsconfig.Options{InsecureSkipVerify: true})
47 57
 	if err != nil {
... ...
@@ -93,4 +103,20 @@ func TestVolumeRequestError(t *testing.T) {
93 93
 	if !strings.Contains(err.Error(), "Unknown volume") {
94 94
 		t.Fatalf("Unexpected error: %v\n", err)
95 95
 	}
96
+
97
+	_, err = driver.List()
98
+	if err == nil {
99
+		t.Fatal("Expected error, was nil")
100
+	}
101
+	if !strings.Contains(err.Error(), "Cannot list volumes") {
102
+		t.Fatalf("Unexpected error: %v\n", err)
103
+	}
104
+
105
+	_, err = driver.Get("volume")
106
+	if err == nil {
107
+		t.Fatal("Expected error, was nil")
108
+	}
109
+	if !strings.Contains(err.Error(), "Cannot get volume") {
110
+		t.Fatalf("Unexpected error: %v\n", err)
111
+	}
96 112
 }
... ...
@@ -82,12 +82,12 @@ type Root struct {
82 82
 }
83 83
 
84 84
 // List lists all the volumes
85
-func (r *Root) List() []volume.Volume {
85
+func (r *Root) List() ([]volume.Volume, error) {
86 86
 	var ls []volume.Volume
87 87
 	for _, v := range r.volumes {
88 88
 		ls = append(ls, v)
89 89
 	}
90
-	return ls
90
+	return ls, nil
91 91
 }
92 92
 
93 93
 // DataPath returns the constructed path of this volume.
... ...
@@ -43,7 +43,7 @@ func TestRemove(t *testing.T) {
43 43
 		t.Fatal("volume dir not removed")
44 44
 	}
45 45
 
46
-	if len(r.List()) != 0 {
46
+	if l, _ := r.List(); len(l) != 0 {
47 47
 		t.Fatal("expected there to be no volumes")
48 48
 	}
49 49
 }
... ...
@@ -1,6 +1,9 @@
1 1
 package store
2 2
 
3
-import "errors"
3
+import (
4
+	"errors"
5
+	"strings"
6
+)
4 7
 
5 8
 var (
6 9
 	// errVolumeInUse is a typed error returned when trying to remove a volume that is currently in use by a container
... ...
@@ -9,6 +12,8 @@ var (
9 9
 	errNoSuchVolume = errors.New("no such volume")
10 10
 	// errInvalidName is a typed error returned when creating a volume with a name that is not valid on the platform
11 11
 	errInvalidName = errors.New("volume name is not valid on this platform")
12
+	// errNameConflict is a typed error returned on create when a volume exists with the given name, but for a different driver
13
+	errNameConflict = errors.New("conflict: volume name must be unique")
12 14
 )
13 15
 
14 16
 // OpErr is the error type returned by functions in the store package. It describes
... ...
@@ -20,6 +25,8 @@ type OpErr struct {
20 20
 	Op string
21 21
 	// Name is the name of the resource being requested for this op, typically the volume name or the driver name.
22 22
 	Name string
23
+	// Refs is the list of references associated with the resource.
24
+	Refs []string
23 25
 }
24 26
 
25 27
 // Error satisfies the built-in error interface type.
... ...
@@ -33,6 +40,9 @@ func (e *OpErr) Error() string {
33 33
 	}
34 34
 
35 35
 	s = s + ": " + e.Err.Error()
36
+	if len(e.Refs) > 0 {
37
+		s = s + " - " + "[" + strings.Join(e.Refs, ", ") + "]"
38
+	}
36 39
 	return s
37 40
 }
38 41
 
... ...
@@ -47,6 +57,12 @@ func IsNotExist(err error) bool {
47 47
 	return isErr(err, errNoSuchVolume)
48 48
 }
49 49
 
50
+// IsNameConflict returns a boolean indicating whether the error indicates that a
51
+// volume name is already taken
52
+func IsNameConflict(err error) bool {
53
+	return isErr(err, errNameConflict)
54
+}
55
+
50 56
 func isErr(err error, expected error) bool {
51 57
 	switch pe := err.(type) {
52 58
 	case nil:
... ...
@@ -13,66 +13,153 @@ import (
13 13
 // reference counting of volumes in the system.
14 14
 func New() *VolumeStore {
15 15
 	return &VolumeStore{
16
-		vols:  make(map[string]*volumeCounter),
17 16
 		locks: &locker.Locker{},
17
+		names: make(map[string]string),
18
+		refs:  make(map[string][]string),
18 19
 	}
19 20
 }
20 21
 
21
-func (s *VolumeStore) get(name string) (*volumeCounter, bool) {
22
+func (s *VolumeStore) getNamed(name string) (string, bool) {
22 23
 	s.globalLock.Lock()
23
-	vc, exists := s.vols[name]
24
+	driverName, exists := s.names[name]
24 25
 	s.globalLock.Unlock()
25
-	return vc, exists
26
+	return driverName, exists
26 27
 }
27 28
 
28
-func (s *VolumeStore) set(name string, vc *volumeCounter) {
29
+func (s *VolumeStore) setNamed(name, driver, ref string) {
29 30
 	s.globalLock.Lock()
30
-	s.vols[name] = vc
31
+	s.names[name] = driver
32
+	if len(ref) > 0 {
33
+		s.refs[name] = append(s.refs[name], ref)
34
+	}
31 35
 	s.globalLock.Unlock()
32 36
 }
33 37
 
34
-func (s *VolumeStore) remove(name string) {
38
+func (s *VolumeStore) purge(name string) {
35 39
 	s.globalLock.Lock()
36
-	delete(s.vols, name)
40
+	delete(s.names, name)
41
+	delete(s.refs, name)
37 42
 	s.globalLock.Unlock()
38 43
 }
39 44
 
40 45
 // VolumeStore is a struct that stores the list of volumes available and keeps track of their usage counts
41 46
 type VolumeStore struct {
42
-	vols       map[string]*volumeCounter
43 47
 	locks      *locker.Locker
44 48
 	globalLock sync.Mutex
49
+	// names stores the volume name -> driver name relationship.
50
+	// This is used for making lookups faster so we don't have to probe all drivers
51
+	names map[string]string
52
+	// refs stores the volume name and the list of things referencing it
53
+	refs map[string][]string
45 54
 }
46 55
 
47
-// volumeCounter keeps track of references to a volume
48
-type volumeCounter struct {
49
-	volume.Volume
50
-	count uint
51
-}
56
+// List proxies to all registered volume drivers to get the full list of volumes
57
+// If a driver returns a volume that has name which conflicts with a another volume from a different driver,
58
+// the first volume is chosen and the conflicting volume is dropped.
59
+func (s *VolumeStore) List() ([]volume.Volume, []string, error) {
60
+	vols, warnings, err := s.list()
61
+	if err != nil {
62
+		return nil, nil, &OpErr{Err: err, Op: "list"}
63
+	}
64
+	var out []volume.Volume
52 65
 
53
-// AddAll adds a list of volumes to the store
54
-func (s *VolumeStore) AddAll(vols []volume.Volume) {
55 66
 	for _, v := range vols {
56
-		s.vols[normaliseVolumeName(v.Name())] = &volumeCounter{v, 0}
67
+		name := normaliseVolumeName(v.Name())
68
+
69
+		s.locks.Lock(name)
70
+		driverName, exists := s.getNamed(name)
71
+		if !exists {
72
+			s.setNamed(name, v.DriverName(), "")
73
+		}
74
+		if exists && driverName != v.DriverName() {
75
+			logrus.Warnf("Volume name %s already exists for driver %s, not including volume returned by %s", v.Name(), driverName, v.DriverName())
76
+			s.locks.Unlock(v.Name())
77
+			continue
78
+		}
79
+
80
+		out = append(out, v)
81
+		s.locks.Unlock(v.Name())
57 82
 	}
83
+	return out, warnings, nil
58 84
 }
59 85
 
60
-// Create tries to find an existing volume with the given name or create a new one from the passed in driver
61
-func (s *VolumeStore) Create(name, driverName string, opts map[string]string) (volume.Volume, error) {
86
+// list goes through each volume driver and asks for its list of volumes.
87
+func (s *VolumeStore) list() ([]volume.Volume, []string, error) {
88
+	drivers, err := volumedrivers.GetAllDrivers()
89
+	if err != nil {
90
+		return nil, nil, err
91
+	}
92
+	var (
93
+		ls       []volume.Volume
94
+		warnings []string
95
+	)
96
+
97
+	type vols struct {
98
+		vols []volume.Volume
99
+		err  error
100
+	}
101
+	chVols := make(chan vols, len(drivers))
102
+
103
+	for _, vd := range drivers {
104
+		go func(d volume.Driver) {
105
+			vs, err := d.List()
106
+			if err != nil {
107
+				chVols <- vols{err: &OpErr{Err: err, Name: d.Name(), Op: "list"}}
108
+				return
109
+			}
110
+			chVols <- vols{vols: vs}
111
+		}(vd)
112
+	}
113
+
114
+	for i := 0; i < len(drivers); i++ {
115
+		vs := <-chVols
116
+
117
+		if vs.err != nil {
118
+			warnings = append(warnings, vs.err.Error())
119
+			logrus.Warn(vs.err)
120
+			continue
121
+		}
122
+		ls = append(ls, vs.vols...)
123
+	}
124
+	return ls, warnings, nil
125
+}
126
+
127
+// CreateWithRef creates a volume with the given name and driver and stores the ref
128
+// This is just like Create() except we store the reference while holding the lock.
129
+// This ensures there's no race between creating a volume and then storing a reference.
130
+func (s *VolumeStore) CreateWithRef(name, driverName, ref string, opts map[string]string) (volume.Volume, error) {
62 131
 	name = normaliseVolumeName(name)
63 132
 	s.locks.Lock(name)
64 133
 	defer s.locks.Unlock(name)
65 134
 
66
-	if vc, exists := s.get(name); exists {
67
-		v := vc.Volume
68
-		return v, nil
135
+	v, err := s.create(name, driverName, opts)
136
+	if err != nil {
137
+		return nil, &OpErr{Err: err, Name: name, Op: "create"}
69 138
 	}
70 139
 
71
-	vd, err := volumedrivers.GetDriver(driverName)
140
+	s.setNamed(name, v.DriverName(), ref)
141
+	return v, nil
142
+}
143
+
144
+// Create creates a volume with the given name and driver.
145
+func (s *VolumeStore) Create(name, driverName string, opts map[string]string) (volume.Volume, error) {
146
+	name = normaliseVolumeName(name)
147
+	s.locks.Lock(name)
148
+	defer s.locks.Unlock(name)
149
+
150
+	v, err := s.create(name, driverName, opts)
72 151
 	if err != nil {
73
-		return nil, &OpErr{Err: err, Name: driverName, Op: "create"}
152
+		return nil, &OpErr{Err: err, Name: name, Op: "create"}
74 153
 	}
154
+	s.setNamed(name, v.DriverName(), "")
155
+	return v, nil
156
+}
75 157
 
158
+// create asks the given driver to create a volume with the name/opts.
159
+// If a volume with the name is already known, it will ask the stored driver for the volume.
160
+// If the passed in driver name does not match the driver name which is stored for the given volume name, an error is returned.
161
+// It is expected that callers of this function hold any neccessary locks.
162
+func (s *VolumeStore) create(name, driverName string, opts map[string]string) (volume.Volume, error) {
76 163
 	// Validate the name in a platform-specific manner
77 164
 	valid, err := volume.IsVolumeNameValid(name)
78 165
 	if err != nil {
... ...
@@ -82,135 +169,164 @@ func (s *VolumeStore) Create(name, driverName string, opts map[string]string) (v
82 82
 		return nil, &OpErr{Err: errInvalidName, Name: name, Op: "create"}
83 83
 	}
84 84
 
85
-	v, err := vd.Create(name, opts)
85
+	vdName, exists := s.getNamed(name)
86
+	if exists {
87
+		if vdName != driverName && driverName != "" && driverName != volume.DefaultDriverName {
88
+			return nil, errNameConflict
89
+		}
90
+		driverName = vdName
91
+	}
92
+
93
+	logrus.Debugf("Registering new volume reference: driver %s, name %s", driverName, name)
94
+	vd, err := volumedrivers.GetDriver(driverName)
86 95
 	if err != nil {
87 96
 		return nil, &OpErr{Op: "create", Name: name, Err: err}
88 97
 	}
89 98
 
90
-	s.set(name, &volumeCounter{v, 0})
91
-	return v, nil
99
+	if v, err := vd.Get(name); err == nil {
100
+		return v, nil
101
+	}
102
+	return vd.Create(name, opts)
92 103
 }
93 104
 
94
-// Get looks if a volume with the given name exists and returns it if so
95
-func (s *VolumeStore) Get(name string) (volume.Volume, error) {
105
+// GetWithRef gets a volume with the given name from the passed in driver and stores the ref
106
+// This is just like Get(), but we store the reference while holding the lock.
107
+// This makes sure there are no races between checking for the existance of a volume and adding a reference for it
108
+func (s *VolumeStore) GetWithRef(name, driverName, ref string) (volume.Volume, error) {
96 109
 	name = normaliseVolumeName(name)
97 110
 	s.locks.Lock(name)
98 111
 	defer s.locks.Unlock(name)
99 112
 
100
-	vc, exists := s.get(name)
101
-	if !exists {
102
-		return nil, &OpErr{Err: errNoSuchVolume, Name: name, Op: "get"}
113
+	vd, err := volumedrivers.GetDriver(driverName)
114
+	if err != nil {
115
+		return nil, &OpErr{Err: err, Name: name, Op: "get"}
116
+	}
117
+
118
+	v, err := vd.Get(name)
119
+	if err != nil {
120
+		return nil, &OpErr{Err: err, Name: name, Op: "get"}
103 121
 	}
104
-	return vc.Volume, nil
122
+
123
+	s.setNamed(name, v.DriverName(), ref)
124
+	return v, nil
105 125
 }
106 126
 
107
-// Remove removes the requested volume. A volume is not removed if the usage count is > 0
108
-func (s *VolumeStore) Remove(v volume.Volume) error {
109
-	name := normaliseVolumeName(v.Name())
127
+// Get looks if a volume with the given name exists and returns it if so
128
+func (s *VolumeStore) Get(name string) (volume.Volume, error) {
129
+	name = normaliseVolumeName(name)
110 130
 	s.locks.Lock(name)
111 131
 	defer s.locks.Unlock(name)
112 132
 
113
-	logrus.Debugf("Removing volume reference: driver %s, name %s", v.DriverName(), name)
114
-	vc, exists := s.get(name)
115
-	if !exists {
116
-		return &OpErr{Err: errNoSuchVolume, Name: name, Op: "remove"}
133
+	v, err := s.getVolume(name)
134
+	if err != nil {
135
+		return nil, &OpErr{Err: err, Name: name, Op: "get"}
117 136
 	}
137
+	return v, nil
138
+}
118 139
 
119
-	if vc.count > 0 {
120
-		return &OpErr{Err: errVolumeInUse, Name: name, Op: "remove"}
140
+// get requests the volume, if the driver info is stored it just access that driver,
141
+// if the driver is unknown it probes all drivers until it finds the first volume with that name.
142
+// it is expected that callers of this function hold any neccessary locks
143
+func (s *VolumeStore) getVolume(name string) (volume.Volume, error) {
144
+	logrus.Debugf("Getting volume reference for name: %s", name)
145
+	if vdName, exists := s.names[name]; exists {
146
+		vd, err := volumedrivers.GetDriver(vdName)
147
+		if err != nil {
148
+			return nil, err
149
+		}
150
+		return vd.Get(name)
121 151
 	}
122 152
 
123
-	vd, err := volumedrivers.GetDriver(vc.DriverName())
153
+	logrus.Debugf("Probing all drivers for volume with name: %s", name)
154
+	drivers, err := volumedrivers.GetAllDrivers()
124 155
 	if err != nil {
125
-		return &OpErr{Err: err, Name: vc.DriverName(), Op: "remove"}
126
-	}
127
-	if err := vd.Remove(vc.Volume); err != nil {
128
-		return &OpErr{Err: err, Name: name, Op: "remove"}
156
+		return nil, err
129 157
 	}
130 158
 
131
-	s.remove(name)
132
-	return nil
159
+	for _, d := range drivers {
160
+		v, err := d.Get(name)
161
+		if err != nil {
162
+			continue
163
+		}
164
+		return v, nil
165
+	}
166
+	return nil, errNoSuchVolume
133 167
 }
134 168
 
135
-// Increment increments the usage count of the passed in volume by 1
136
-func (s *VolumeStore) Increment(v volume.Volume) {
169
+// Remove removes the requested volume. A volume is not removed if it has any refs
170
+func (s *VolumeStore) Remove(v volume.Volume) error {
137 171
 	name := normaliseVolumeName(v.Name())
138 172
 	s.locks.Lock(name)
139 173
 	defer s.locks.Unlock(name)
140 174
 
141
-	logrus.Debugf("Incrementing volume reference: driver %s, name %s", v.DriverName(), v.Name())
142
-	vc, exists := s.get(name)
143
-	if !exists {
144
-		s.set(name, &volumeCounter{v, 1})
145
-		return
175
+	if refs, exists := s.refs[name]; exists && len(refs) > 0 {
176
+		return &OpErr{Err: errVolumeInUse, Name: v.Name(), Op: "remove", Refs: refs}
146 177
 	}
147
-	vc.count++
148
-}
149 178
 
150
-// Decrement decrements the usage count of the passed in volume by 1
151
-func (s *VolumeStore) Decrement(v volume.Volume) {
152
-	name := normaliseVolumeName(v.Name())
153
-	s.locks.Lock(name)
154
-	defer s.locks.Unlock(name)
155
-	logrus.Debugf("Decrementing volume reference: driver %s, name %s", v.DriverName(), v.Name())
156
-
157
-	vc, exists := s.get(name)
158
-	if !exists {
159
-		return
179
+	vd, err := volumedrivers.GetDriver(v.DriverName())
180
+	if err != nil {
181
+		return &OpErr{Err: err, Name: vd.Name(), Op: "remove"}
160 182
 	}
161
-	if vc.count == 0 {
162
-		return
183
+
184
+	logrus.Debugf("Removing volume reference: driver %s, name %s", v.DriverName(), name)
185
+	if err := vd.Remove(v); err != nil {
186
+		return &OpErr{Err: err, Name: name, Op: "remove"}
163 187
 	}
164
-	vc.count--
188
+
189
+	s.purge(name)
190
+	return nil
165 191
 }
166 192
 
167
-// Count returns the usage count of the passed in volume
168
-func (s *VolumeStore) Count(v volume.Volume) uint {
169
-	name := normaliseVolumeName(v.Name())
170
-	s.locks.Lock(name)
171
-	defer s.locks.Unlock(name)
193
+// Dereference removes the specified reference to the volume
194
+func (s *VolumeStore) Dereference(v volume.Volume, ref string) {
195
+	s.locks.Lock(v.Name())
196
+	defer s.locks.Unlock(v.Name())
172 197
 
173
-	vc, exists := s.get(name)
198
+	s.globalLock.Lock()
199
+	refs, exists := s.refs[v.Name()]
174 200
 	if !exists {
175
-		return 0
201
+		return
176 202
 	}
177
-	return vc.count
178
-}
179 203
 
180
-// List returns all the available volumes
181
-func (s *VolumeStore) List() []volume.Volume {
182
-	s.globalLock.Lock()
183
-	defer s.globalLock.Unlock()
184
-	var ls []volume.Volume
185
-	for _, vc := range s.vols {
186
-		ls = append(ls, vc.Volume)
204
+	for i, r := range refs {
205
+		if r == ref {
206
+			s.refs[v.Name()] = append(s.refs[v.Name()][:i], s.refs[v.Name()][i+1:]...)
207
+		}
187 208
 	}
188
-	return ls
209
+	s.globalLock.Unlock()
189 210
 }
190 211
 
191 212
 // FilterByDriver returns the available volumes filtered by driver name
192
-func (s *VolumeStore) FilterByDriver(name string) []volume.Volume {
193
-	return s.filter(byDriver(name))
213
+func (s *VolumeStore) FilterByDriver(name string) ([]volume.Volume, error) {
214
+	vd, err := volumedrivers.GetDriver(name)
215
+	if err != nil {
216
+		return nil, &OpErr{Err: err, Name: name, Op: "list"}
217
+	}
218
+	ls, err := vd.List()
219
+	if err != nil {
220
+		return nil, &OpErr{Err: err, Name: name, Op: "list"}
221
+	}
222
+	return ls, nil
223
+}
224
+
225
+// FilterByUsed returns the available volumes filtered by if they are not in use
226
+func (s *VolumeStore) FilterByUsed(vols []volume.Volume) []volume.Volume {
227
+	return s.filter(vols, func(v volume.Volume) bool {
228
+		s.locks.Lock(v.Name())
229
+		defer s.locks.Unlock(v.Name())
230
+		return len(s.refs[v.Name()]) == 0
231
+	})
194 232
 }
195 233
 
196 234
 // filterFunc defines a function to allow filter volumes in the store
197 235
 type filterFunc func(vol volume.Volume) bool
198 236
 
199
-// byDriver generates a filterFunc to filter volumes by their driver name
200
-func byDriver(name string) filterFunc {
201
-	return func(vol volume.Volume) bool {
202
-		return vol.DriverName() == name
203
-	}
204
-}
205
-
206 237
 // filter returns the available volumes filtered by a filterFunc function
207
-func (s *VolumeStore) filter(f filterFunc) []volume.Volume {
208
-	s.globalLock.Lock()
209
-	defer s.globalLock.Unlock()
238
+func (s *VolumeStore) filter(vols []volume.Volume, f filterFunc) []volume.Volume {
210 239
 	var ls []volume.Volume
211
-	for _, vc := range s.vols {
212
-		if f(vc.Volume) {
213
-			ls = append(ls, vc.Volume)
240
+	for _, v := range vols {
241
+		if f(v) {
242
+			ls = append(ls, v)
214 243
 		}
215 244
 	}
216 245
 	return ls
... ...
@@ -2,42 +2,16 @@ package store
2 2
 
3 3
 import (
4 4
 	"errors"
5
+	"strings"
5 6
 	"testing"
6 7
 
7
-	"github.com/docker/docker/volume"
8 8
 	"github.com/docker/docker/volume/drivers"
9 9
 	vt "github.com/docker/docker/volume/testutils"
10 10
 )
11 11
 
12
-func TestList(t *testing.T) {
13
-	volumedrivers.Register(vt.FakeDriver{}, "fake")
14
-	s := New()
15
-	s.AddAll([]volume.Volume{vt.NewFakeVolume("fake1"), vt.NewFakeVolume("fake2")})
16
-	l := s.List()
17
-	if len(l) != 2 {
18
-		t.Fatalf("Expected 2 volumes in the store, got %v: %v", len(l), l)
19
-	}
20
-}
21
-
22
-func TestGet(t *testing.T) {
23
-	volumedrivers.Register(vt.FakeDriver{}, "fake")
24
-	s := New()
25
-	s.AddAll([]volume.Volume{vt.NewFakeVolume("fake1"), vt.NewFakeVolume("fake2")})
26
-	v, err := s.Get("fake1")
27
-	if err != nil {
28
-		t.Fatal(err)
29
-	}
30
-	if v.Name() != "fake1" {
31
-		t.Fatalf("Expected fake1 volume, got %v", v)
32
-	}
33
-
34
-	if _, err := s.Get("fake4"); !IsNotExist(err) {
35
-		t.Fatalf("Expected IsNotExist error, got %v", err)
36
-	}
37
-}
38
-
39 12
 func TestCreate(t *testing.T) {
40
-	volumedrivers.Register(vt.FakeDriver{}, "fake")
13
+	volumedrivers.Register(vt.NewFakeDriver("fake"), "fake")
14
+	defer volumedrivers.Unregister("fake")
41 15
 	s := New()
42 16
 	v, err := s.Create("fake1", "fake", nil)
43 17
 	if err != nil {
... ...
@@ -46,7 +20,7 @@ func TestCreate(t *testing.T) {
46 46
 	if v.Name() != "fake1" {
47 47
 		t.Fatalf("Expected fake1 volume, got %v", v)
48 48
 	}
49
-	if l := s.List(); len(l) != 1 {
49
+	if l, _, _ := s.List(); len(l) != 1 {
50 50
 		t.Fatalf("Expected 1 volume in the store, got %v: %v", len(l), l)
51 51
 	}
52 52
 
... ...
@@ -62,93 +36,90 @@ func TestCreate(t *testing.T) {
62 62
 }
63 63
 
64 64
 func TestRemove(t *testing.T) {
65
-	volumedrivers.Register(vt.FakeDriver{}, "fake")
65
+	volumedrivers.Register(vt.NewFakeDriver("fake"), "fake")
66
+	volumedrivers.Register(vt.NewFakeDriver("noop"), "noop")
67
+	defer volumedrivers.Unregister("fake")
68
+	defer volumedrivers.Unregister("noop")
66 69
 	s := New()
67
-	if err := s.Remove(vt.NoopVolume{}); !IsNotExist(err) {
68
-		t.Fatalf("Expected IsNotExist error, got %v", err)
70
+
71
+	// doing string compare here since this error comes directly from the driver
72
+	expected := "no such volume"
73
+	if err := s.Remove(vt.NoopVolume{}); err == nil || !strings.Contains(err.Error(), expected) {
74
+		t.Fatalf("Expected error %q, got %v", expected, err)
69 75
 	}
70
-	v, err := s.Create("fake1", "fake", nil)
76
+
77
+	v, err := s.CreateWithRef("fake1", "fake", "fake", nil)
71 78
 	if err != nil {
72 79
 		t.Fatal(err)
73 80
 	}
74
-	s.Increment(v)
81
+
75 82
 	if err := s.Remove(v); !IsInUse(err) {
76
-		t.Fatalf("Expected IsInUse error, got %v", err)
83
+		t.Fatalf("Expected ErrVolumeInUse error, got %v", err)
77 84
 	}
78
-	s.Decrement(v)
85
+	s.Dereference(v, "fake")
79 86
 	if err := s.Remove(v); err != nil {
80 87
 		t.Fatal(err)
81 88
 	}
82
-	if l := s.List(); len(l) != 0 {
89
+	if l, _, _ := s.List(); len(l) != 0 {
83 90
 		t.Fatalf("Expected 0 volumes in the store, got %v, %v", len(l), l)
84 91
 	}
85 92
 }
86 93
 
87
-func TestIncrement(t *testing.T) {
94
+func TestList(t *testing.T) {
95
+	volumedrivers.Register(vt.NewFakeDriver("fake"), "fake")
96
+	volumedrivers.Register(vt.NewFakeDriver("fake2"), "fake2")
97
+	defer volumedrivers.Unregister("fake")
98
+	defer volumedrivers.Unregister("fake2")
99
+
88 100
 	s := New()
89
-	v := vt.NewFakeVolume("fake1")
90
-	s.Increment(v)
91
-	if l := s.List(); len(l) != 1 {
92
-		t.Fatalf("Expected 1 volume, got %v, %v", len(l), l)
101
+	if _, err := s.Create("test", "fake", nil); err != nil {
102
+		t.Fatal(err)
93 103
 	}
94
-	if c := s.Count(v); c != 1 {
95
-		t.Fatalf("Expected 1 counter, got %v", c)
104
+	if _, err := s.Create("test2", "fake2", nil); err != nil {
105
+		t.Fatal(err)
96 106
 	}
97 107
 
98
-	s.Increment(v)
99
-	if l := s.List(); len(l) != 1 {
100
-		t.Fatalf("Expected 1 volume, got %v, %v", len(l), l)
108
+	ls, _, err := s.List()
109
+	if err != nil {
110
+		t.Fatal(err)
101 111
 	}
102
-	if c := s.Count(v); c != 2 {
103
-		t.Fatalf("Expected 2 counter, got %v", c)
112
+	if len(ls) != 2 {
113
+		t.Fatalf("expected 2 volumes, got: %d", len(ls))
104 114
 	}
105 115
 
106
-	v2 := vt.NewFakeVolume("fake2")
107
-	s.Increment(v2)
108
-	if l := s.List(); len(l) != 2 {
109
-		t.Fatalf("Expected 2 volume, got %v, %v", len(l), l)
116
+	// and again with a new store
117
+	s = New()
118
+	ls, _, err = s.List()
119
+	if err != nil {
120
+		t.Fatal(err)
121
+	}
122
+	if len(ls) != 2 {
123
+		t.Fatalf("expected 2 volumes, got: %d", len(ls))
110 124
 	}
111 125
 }
112 126
 
113
-func TestDecrement(t *testing.T) {
127
+func TestFilterByDriver(t *testing.T) {
128
+	volumedrivers.Register(vt.NewFakeDriver("fake"), "fake")
129
+	volumedrivers.Register(vt.NewFakeDriver("noop"), "noop")
130
+	defer volumedrivers.Unregister("fake")
131
+	defer volumedrivers.Unregister("noop")
114 132
 	s := New()
115
-	v := vt.NoopVolume{}
116
-	s.Decrement(v)
117
-	if c := s.Count(v); c != 0 {
118
-		t.Fatalf("Expected 0 volumes, got %v", c)
119
-	}
120 133
 
121
-	s.Increment(v)
122
-	s.Increment(v)
123
-	s.Decrement(v)
124
-	if c := s.Count(v); c != 1 {
125
-		t.Fatalf("Expected 1 volume, got %v", c)
134
+	if _, err := s.Create("fake1", "fake", nil); err != nil {
135
+		t.Fatal(err)
126 136
 	}
127
-
128
-	s.Decrement(v)
129
-	if c := s.Count(v); c != 0 {
130
-		t.Fatalf("Expected 0 volumes, got %v", c)
137
+	if _, err := s.Create("fake2", "fake", nil); err != nil {
138
+		t.Fatal(err)
131 139
 	}
132
-
133
-	// Test counter cannot be negative.
134
-	s.Decrement(v)
135
-	if c := s.Count(v); c != 0 {
136
-		t.Fatalf("Expected 0 volumes, got %v", c)
140
+	if _, err := s.Create("fake3", "noop", nil); err != nil {
141
+		t.Fatal(err)
137 142
 	}
138
-}
139
-
140
-func TestFilterByDriver(t *testing.T) {
141
-	s := New()
142
-
143
-	s.Increment(vt.NewFakeVolume("fake1"))
144
-	s.Increment(vt.NewFakeVolume("fake2"))
145
-	s.Increment(vt.NoopVolume{})
146 143
 
147
-	if l := s.FilterByDriver("fake"); len(l) != 2 {
144
+	if l, _ := s.FilterByDriver("fake"); len(l) != 2 {
148 145
 		t.Fatalf("Expected 2 volumes, got %v, %v", len(l), l)
149 146
 	}
150 147
 
151
-	if l := s.FilterByDriver("noop"); len(l) != 1 {
148
+	if l, _ := s.FilterByDriver("noop"); len(l) != 1 {
152 149
 		t.Fatalf("Expected 1 volume, got %v, %v", len(l), l)
153 150
 	}
154 151
 }
... ...
@@ -50,19 +50,55 @@ func (FakeVolume) Mount() (string, error) { return "fake", nil }
50 50
 func (FakeVolume) Unmount() error { return nil }
51 51
 
52 52
 // FakeDriver is a driver that generates fake volumes
53
-type FakeDriver struct{}
53
+type FakeDriver struct {
54
+	name string
55
+	vols map[string]volume.Volume
56
+}
57
+
58
+// NewFakeDriver creates a new FakeDriver with the specified name
59
+func NewFakeDriver(name string) volume.Driver {
60
+	return &FakeDriver{
61
+		name: name,
62
+		vols: make(map[string]volume.Volume),
63
+	}
64
+}
54 65
 
55 66
 // Name is the name of the driver
56
-func (FakeDriver) Name() string { return "fake" }
67
+func (d *FakeDriver) Name() string { return d.name }
57 68
 
58 69
 // Create initializes a fake volume.
59 70
 // It returns an error if the options include an "error" key with a message
60
-func (FakeDriver) Create(name string, opts map[string]string) (volume.Volume, error) {
71
+func (d *FakeDriver) Create(name string, opts map[string]string) (volume.Volume, error) {
61 72
 	if opts != nil && opts["error"] != "" {
62 73
 		return nil, fmt.Errorf(opts["error"])
63 74
 	}
64
-	return NewFakeVolume(name), nil
75
+	v := NewFakeVolume(name)
76
+	d.vols[name] = v
77
+	return v, nil
65 78
 }
66 79
 
67 80
 // Remove deletes a volume.
68
-func (FakeDriver) Remove(v volume.Volume) error { return nil }
81
+func (d *FakeDriver) Remove(v volume.Volume) error {
82
+	if _, exists := d.vols[v.Name()]; !exists {
83
+		return fmt.Errorf("no such volume")
84
+	}
85
+	delete(d.vols, v.Name())
86
+	return nil
87
+}
88
+
89
+// List lists the volumes
90
+func (d *FakeDriver) List() ([]volume.Volume, error) {
91
+	var vols []volume.Volume
92
+	for _, v := range d.vols {
93
+		vols = append(vols, v)
94
+	}
95
+	return vols, nil
96
+}
97
+
98
+// Get gets the volume
99
+func (d *FakeDriver) Get(name string) (volume.Volume, error) {
100
+	if v, exists := d.vols[name]; exists {
101
+		return v, nil
102
+	}
103
+	return nil, fmt.Errorf("no such volume")
104
+}
... ...
@@ -21,7 +21,11 @@ type Driver interface {
21 21
 	// Create makes a new volume with the given id.
22 22
 	Create(name string, opts map[string]string) (Volume, error)
23 23
 	// Remove deletes the volume.
24
-	Remove(Volume) error
24
+	Remove(vol Volume) (err error)
25
+	// List lists all the volumes the driver has
26
+	List() ([]Volume, error)
27
+	// Get retreives the volume with the requested name
28
+	Get(name string) (Volume, error)
25 29
 }
26 30
 
27 31
 // Volume is a place to store data. It is backed by a specific driver, and can be mounted.