فهرست منبع

Merge pull request #36637 from cpuguy83/no_global_driver_store

No global volume driver store
Brian Goff 7 سال پیش
والد
کامیت
6cd806aa53

+ 4 - 11
daemon/daemon.go

@@ -179,11 +179,6 @@ func (daemon *Daemon) restore() error {
 			delete(containers, id)
 			delete(containers, id)
 			continue
 			continue
 		}
 		}
-		// verify that all volumes valid and have been migrated from the pre-1.7 layout
-		if err := daemon.verifyVolumesInfo(c); err != nil {
-			// don't skip the container due to error
-			logrus.Errorf("Failed to verify volumes for container '%s': %v", c.ID, err)
-		}
 		if err := daemon.Register(c); err != nil {
 		if err := daemon.Register(c); err != nil {
 			logrus.Errorf("Failed to register container %s: %s", c.ID, err)
 			logrus.Errorf("Failed to register container %s: %s", c.ID, err)
 			delete(containers, id)
 			delete(containers, id)
@@ -1150,17 +1145,15 @@ func setDefaultMtu(conf *config.Config) {
 }
 }
 
 
 func (daemon *Daemon) configureVolumes(rootIDs idtools.IDPair) (*store.VolumeStore, error) {
 func (daemon *Daemon) configureVolumes(rootIDs idtools.IDPair) (*store.VolumeStore, error) {
-	volumesDriver, err := local.New(daemon.configStore.Root, rootIDs)
+	volumeDriver, err := local.New(daemon.configStore.Root, rootIDs)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-
-	volumedrivers.RegisterPluginGetter(daemon.PluginStore)
-
-	if !volumedrivers.Register(volumesDriver, volumesDriver.Name()) {
+	drivers := volumedrivers.NewStore(daemon.PluginStore)
+	if !drivers.Register(volumeDriver, volumeDriver.Name()) {
 		return nil, errors.New("local volume driver could not be registered")
 		return nil, errors.New("local volume driver could not be registered")
 	}
 	}
-	return store.New(daemon.configStore.Root)
+	return store.New(daemon.configStore.Root, drivers)
 }
 }
 
 
 // IsShuttingDown tells whether the daemon is shutting down or not
 // IsShuttingDown tells whether the daemon is shutting down or not

+ 3 - 4
daemon/daemon_test.go

@@ -13,7 +13,6 @@ import (
 	_ "github.com/docker/docker/pkg/discovery/memory"
 	_ "github.com/docker/docker/pkg/discovery/memory"
 	"github.com/docker/docker/pkg/idtools"
 	"github.com/docker/docker/pkg/idtools"
 	"github.com/docker/docker/pkg/truncindex"
 	"github.com/docker/docker/pkg/truncindex"
-	"github.com/docker/docker/volume"
 	volumedrivers "github.com/docker/docker/volume/drivers"
 	volumedrivers "github.com/docker/docker/volume/drivers"
 	"github.com/docker/docker/volume/local"
 	"github.com/docker/docker/volume/local"
 	"github.com/docker/docker/volume/store"
 	"github.com/docker/docker/volume/store"
@@ -121,7 +120,8 @@ func initDaemonWithVolumeStore(tmp string) (*Daemon, error) {
 		repository: tmp,
 		repository: tmp,
 		root:       tmp,
 		root:       tmp,
 	}
 	}
-	daemon.volumes, err = store.New(tmp)
+	drivers := volumedrivers.NewStore(nil)
+	daemon.volumes, err = store.New(tmp, drivers)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -130,7 +130,7 @@ func initDaemonWithVolumeStore(tmp string) (*Daemon, error) {
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-	volumedrivers.Register(volumesDriver, volumesDriver.Name())
+	drivers.Register(volumesDriver, volumesDriver.Name())
 
 
 	return daemon, nil
 	return daemon, nil
 }
 }
@@ -208,7 +208,6 @@ func TestContainerInitDNS(t *testing.T) {
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
-	defer volumedrivers.Unregister(volume.DefaultDriverName)
 
 
 	c, err := daemon.load(containerID)
 	c, err := daemon.load(containerID)
 	if err != nil {
 	if err != nil {

+ 0 - 89
daemon/daemon_unix_test.go

@@ -6,18 +6,11 @@ import (
 	"errors"
 	"errors"
 	"io/ioutil"
 	"io/ioutil"
 	"os"
 	"os"
-	"path/filepath"
 	"testing"
 	"testing"
 
 
 	containertypes "github.com/docker/docker/api/types/container"
 	containertypes "github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/container"
 	"github.com/docker/docker/container"
 	"github.com/docker/docker/daemon/config"
 	"github.com/docker/docker/daemon/config"
-	"github.com/docker/docker/pkg/idtools"
-	"github.com/docker/docker/volume"
-	"github.com/docker/docker/volume/drivers"
-	"github.com/docker/docker/volume/local"
-	"github.com/docker/docker/volume/store"
-	"github.com/gotestyourself/gotestyourself/assert"
 )
 )
 
 
 type fakeContainerGetter struct {
 type fakeContainerGetter struct {
@@ -273,85 +266,3 @@ func TestNetworkOptions(t *testing.T) {
 		t.Fatal("Expected networkOptions error, got nil")
 		t.Fatal("Expected networkOptions error, got nil")
 	}
 	}
 }
 }
-
-func TestMigratePre17Volumes(t *testing.T) {
-	rootDir, err := ioutil.TempDir("", "test-daemon-volumes")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(rootDir)
-
-	volumeRoot := filepath.Join(rootDir, "volumes")
-	err = os.MkdirAll(volumeRoot, 0755)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	containerRoot := filepath.Join(rootDir, "containers")
-	cid := "1234"
-	err = os.MkdirAll(filepath.Join(containerRoot, cid), 0755)
-	assert.NilError(t, err)
-
-	vid := "5678"
-	vfsPath := filepath.Join(rootDir, "vfs", "dir", vid)
-	err = os.MkdirAll(vfsPath, 0755)
-	assert.NilError(t, err)
-
-	config := []byte(`
-		{
-			"ID": "` + cid + `",
-			"Volumes": {
-				"/foo": "` + vfsPath + `",
-				"/bar": "/foo",
-				"/quux": "/quux"
-			},
-			"VolumesRW": {
-				"/foo": true,
-				"/bar": true,
-				"/quux": false
-			}
-		}
-	`)
-
-	volStore, err := store.New(volumeRoot)
-	if err != nil {
-		t.Fatal(err)
-	}
-	drv, err := local.New(volumeRoot, idtools.IDPair{UID: 0, GID: 0})
-	if err != nil {
-		t.Fatal(err)
-	}
-	volumedrivers.Register(drv, volume.DefaultDriverName)
-
-	daemon := &Daemon{
-		root:       rootDir,
-		repository: containerRoot,
-		volumes:    volStore,
-	}
-	err = ioutil.WriteFile(filepath.Join(containerRoot, cid, "config.v2.json"), config, 600)
-	if err != nil {
-		t.Fatal(err)
-	}
-	c, err := daemon.load(cid)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if err := daemon.verifyVolumesInfo(c); err != nil {
-		t.Fatal(err)
-	}
-
-	expected := map[string]volume.MountPoint{
-		"/foo":  {Destination: "/foo", RW: true, Name: vid},
-		"/bar":  {Source: "/foo", Destination: "/bar", RW: true},
-		"/quux": {Source: "/quux", Destination: "/quux", RW: false},
-	}
-	for id, mp := range c.MountPoints {
-		x, exists := expected[id]
-		if !exists {
-			t.Fatal("volume not migrated")
-		}
-		if mp.Source != x.Source || mp.Destination != x.Destination || mp.RW != x.RW || mp.Name != x.Name {
-			t.Fatalf("got unexpected mountpoint, expected: %+v, got: %+v", x, mp)
-		}
-	}
-}

+ 0 - 7
daemon/daemon_windows.go

@@ -632,13 +632,6 @@ func setupDaemonProcess(config *config.Config) error {
 	return nil
 	return nil
 }
 }
 
 
-// verifyVolumesInfo is a no-op on windows.
-// This is called during daemon initialization to migrate volumes from pre-1.7.
-// volumes were not supported on windows pre-1.7
-func (daemon *Daemon) verifyVolumesInfo(container *container.Container) error {
-	return nil
-}
-
 func (daemon *Daemon) setupSeccompProfile() error {
 func (daemon *Daemon) setupSeccompProfile() error {
 	return nil
 	return nil
 }
 }

+ 22 - 24
daemon/disk_usage.go

@@ -35,39 +35,37 @@ func (daemon *Daemon) SystemDiskUsage(ctx context.Context) (*types.DiskUsage, er
 		return nil, fmt.Errorf("failed to retrieve image list: %v", err)
 		return nil, fmt.Errorf("failed to retrieve image list: %v", err)
 	}
 	}
 
 
-	// Get all local volumes
-	allVolumes := []*types.Volume{}
-	getLocalVols := func(v volume.Volume) error {
+	volumes, err := daemon.volumes.FilterByDriver(volume.DefaultDriverName)
+	if err != nil {
+		return nil, err
+	}
+
+	var allVolumes []*types.Volume
+	for _, v := range volumes {
 		select {
 		select {
 		case <-ctx.Done():
 		case <-ctx.Done():
-			return ctx.Err()
+			return nil, ctx.Err()
 		default:
 		default:
-			if d, ok := v.(volume.DetailedVolume); ok {
+		}
+		if d, ok := v.(volume.DetailedVolume); ok {
+			if len(d.Options()) > 0 {
 				// skip local volumes with mount options since these could have external
 				// skip local volumes with mount options since these could have external
 				// mounted filesystems that will be slow to enumerate.
 				// mounted filesystems that will be slow to enumerate.
-				if len(d.Options()) > 0 {
-					return nil
-				}
+				continue
 			}
 			}
-			name := v.Name()
-			refs := daemon.volumes.Refs(v)
-
-			tv := volumeToAPIType(v)
-			sz, err := directory.Size(ctx, v.Path())
-			if err != nil {
-				logrus.Warnf("failed to determine size of volume %v", name)
-				sz = -1
-			}
-			tv.UsageData = &types.VolumeUsageData{Size: sz, RefCount: int64(len(refs))}
-			allVolumes = append(allVolumes, tv)
 		}
 		}
 
 
-		return nil
-	}
+		name := v.Name()
+		refs := daemon.volumes.Refs(v)
 
 
-	err = daemon.traverseLocalVolumes(getLocalVols)
-	if err != nil {
-		return nil, err
+		tv := volumeToAPIType(v)
+		sz, err := directory.Size(ctx, v.Path())
+		if err != nil {
+			logrus.Warnf("failed to determine size of volume %v", name)
+			sz = -1
+		}
+		tv.UsageData = &types.VolumeUsageData{Size: sz, RefCount: int64(len(refs))}
+		allVolumes = append(allVolumes, tv)
 	}
 	}
 
 
 	allLayersSize, err := daemon.imageService.LayerDiskUsage(ctx)
 	allLayersSize, err := daemon.imageService.LayerDiskUsage(ctx)

+ 1 - 2
daemon/info.go

@@ -19,7 +19,6 @@ import (
 	"github.com/docker/docker/pkg/sysinfo"
 	"github.com/docker/docker/pkg/sysinfo"
 	"github.com/docker/docker/pkg/system"
 	"github.com/docker/docker/pkg/system"
 	"github.com/docker/docker/registry"
 	"github.com/docker/docker/registry"
-	"github.com/docker/docker/volume/drivers"
 	"github.com/docker/go-connections/sockets"
 	"github.com/docker/go-connections/sockets"
 	"github.com/sirupsen/logrus"
 	"github.com/sirupsen/logrus"
 )
 )
@@ -196,7 +195,7 @@ func (daemon *Daemon) SystemVersion() types.Version {
 func (daemon *Daemon) showPluginsInfo() types.PluginsInfo {
 func (daemon *Daemon) showPluginsInfo() types.PluginsInfo {
 	var pluginsInfo types.PluginsInfo
 	var pluginsInfo types.PluginsInfo
 
 
-	pluginsInfo.Volume = volumedrivers.GetDriverList()
+	pluginsInfo.Volume = daemon.volumes.GetDriverList()
 	pluginsInfo.Network = daemon.GetNetworkDriverList()
 	pluginsInfo.Network = daemon.GetNetworkDriverList()
 	// The authorization plugins are returned in the order they are
 	// The authorization plugins are returned in the order they are
 	// used as they constitute a request/response modification chain.
 	// used as they constitute a request/response modification chain.

+ 15 - 11
daemon/prune.go

@@ -107,11 +107,20 @@ func (daemon *Daemon) VolumesPrune(ctx context.Context, pruneFilters filters.Arg
 
 
 	rep := &types.VolumesPruneReport{}
 	rep := &types.VolumesPruneReport{}
 
 
-	pruneVols := func(v volume.Volume) error {
+	volumes, err := daemon.volumes.FilterByDriver(volume.DefaultDriverName)
+	if err != nil {
+		return nil, err
+	}
+
+	for _, v := range volumes {
 		select {
 		select {
 		case <-ctx.Done():
 		case <-ctx.Done():
 			logrus.Debugf("VolumesPrune operation cancelled: %#v", *rep)
 			logrus.Debugf("VolumesPrune operation cancelled: %#v", *rep)
-			return ctx.Err()
+			err := ctx.Err()
+			if err == context.Canceled {
+				return rep, nil
+			}
+			return rep, err
 		default:
 		default:
 		}
 		}
 
 
@@ -122,9 +131,10 @@ func (daemon *Daemon) VolumesPrune(ctx context.Context, pruneFilters filters.Arg
 			detailedVolume, ok := v.(volume.DetailedVolume)
 			detailedVolume, ok := v.(volume.DetailedVolume)
 			if ok {
 			if ok {
 				if !matchLabels(pruneFilters, detailedVolume.Labels()) {
 				if !matchLabels(pruneFilters, detailedVolume.Labels()) {
-					return nil
+					continue
 				}
 				}
 			}
 			}
+
 			vSize, err := directory.Size(ctx, v.Path())
 			vSize, err := directory.Size(ctx, v.Path())
 			if err != nil {
 			if err != nil {
 				logrus.Warnf("could not determine size of volume %s: %v", name, err)
 				logrus.Warnf("could not determine size of volume %s: %v", name, err)
@@ -132,21 +142,15 @@ func (daemon *Daemon) VolumesPrune(ctx context.Context, pruneFilters filters.Arg
 			err = daemon.volumeRm(v)
 			err = daemon.volumeRm(v)
 			if err != nil {
 			if err != nil {
 				logrus.Warnf("could not remove volume %s: %v", name, err)
 				logrus.Warnf("could not remove volume %s: %v", name, err)
-				return nil
+				continue
 			}
 			}
 			rep.SpaceReclaimed += uint64(vSize)
 			rep.SpaceReclaimed += uint64(vSize)
 			rep.VolumesDeleted = append(rep.VolumesDeleted, name)
 			rep.VolumesDeleted = append(rep.VolumesDeleted, name)
 		}
 		}
 
 
-		return nil
 	}
 	}
 
 
-	err = daemon.traverseLocalVolumes(pruneVols)
-	if err == context.Canceled {
-		return rep, nil
-	}
-
-	return rep, err
+	return rep, nil
 }
 }
 
 
 // localNetworksPrune removes unused local networks
 // localNetworksPrune removes unused local networks

+ 0 - 31
daemon/volumes.go

@@ -1,7 +1,6 @@
 package daemon // import "github.com/docker/docker/daemon"
 package daemon // import "github.com/docker/docker/daemon"
 
 
 import (
 import (
-	"fmt"
 	"os"
 	"os"
 	"path/filepath"
 	"path/filepath"
 	"reflect"
 	"reflect"
@@ -15,7 +14,6 @@ import (
 	"github.com/docker/docker/container"
 	"github.com/docker/docker/container"
 	"github.com/docker/docker/errdefs"
 	"github.com/docker/docker/errdefs"
 	"github.com/docker/docker/volume"
 	"github.com/docker/docker/volume"
-	"github.com/docker/docker/volume/drivers"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 	"github.com/sirupsen/logrus"
 )
 )
@@ -385,32 +383,3 @@ func (daemon *Daemon) backportMountSpec(container *container.Container) {
 		cm.Spec.ReadOnly = !cm.RW
 		cm.Spec.ReadOnly = !cm.RW
 	}
 	}
 }
 }
-
-func (daemon *Daemon) traverseLocalVolumes(fn func(volume.Volume) error) error {
-	localVolumeDriver, err := volumedrivers.GetDriver(volume.DefaultDriverName)
-	if err != nil {
-		return fmt.Errorf("can't retrieve local volume driver: %v", err)
-	}
-	vols, err := localVolumeDriver.List()
-	if err != nil {
-		return fmt.Errorf("can't retrieve local volumes: %v", err)
-	}
-
-	for _, v := range vols {
-		name := v.Name()
-		vol, err := daemon.volumes.Get(name)
-		if err != nil {
-			logrus.Warnf("failed to retrieve volume %s from store: %v", name, err)
-		} else {
-			// daemon.volumes.Get will return DetailedVolume
-			v = vol
-		}
-
-		err = fn(v)
-		if err != nil {
-			return err
-		}
-	}
-
-	return nil
-}

+ 0 - 79
daemon/volumes_unix.go

@@ -3,10 +3,8 @@
 package daemon // import "github.com/docker/docker/daemon"
 package daemon // import "github.com/docker/docker/daemon"
 
 
 import (
 import (
-	"encoding/json"
 	"fmt"
 	"fmt"
 	"os"
 	"os"
-	"path/filepath"
 	"sort"
 	"sort"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
@@ -15,9 +13,6 @@ import (
 	"github.com/docker/docker/pkg/fileutils"
 	"github.com/docker/docker/pkg/fileutils"
 	"github.com/docker/docker/pkg/mount"
 	"github.com/docker/docker/pkg/mount"
 	"github.com/docker/docker/volume"
 	"github.com/docker/docker/volume"
-	"github.com/docker/docker/volume/drivers"
-	"github.com/docker/docker/volume/local"
-	"github.com/pkg/errors"
 )
 )
 
 
 // setupMounts iterates through each of the mount points for a container and
 // setupMounts iterates through each of the mount points for a container and
@@ -113,80 +108,6 @@ func setBindModeIfNull(bind *volume.MountPoint) {
 	}
 	}
 }
 }
 
 
-// migrateVolume links the contents of a volume created pre Docker 1.7
-// into the location expected by the local driver.
-// It creates a symlink from DOCKER_ROOT/vfs/dir/VOLUME_ID to DOCKER_ROOT/volumes/VOLUME_ID/_container_data.
-// It preserves the volume json configuration generated pre Docker 1.7 to be able to
-// downgrade from Docker 1.7 to Docker 1.6 without losing volume compatibility.
-func migrateVolume(id, vfs string) error {
-	l, err := volumedrivers.GetDriver(volume.DefaultDriverName)
-	if err != nil {
-		return err
-	}
-
-	newDataPath := l.(*local.Root).DataPath(id)
-	fi, err := os.Stat(newDataPath)
-	if err != nil && !os.IsNotExist(err) {
-		return err
-	}
-
-	if fi != nil && fi.IsDir() {
-		return nil
-	}
-
-	return os.Symlink(vfs, newDataPath)
-}
-
-// verifyVolumesInfo ports volumes configured for the containers pre docker 1.7.
-// It reads the container configuration and creates valid mount points for the old volumes.
-func (daemon *Daemon) verifyVolumesInfo(container *container.Container) error {
-	container.Lock()
-	defer container.Unlock()
-
-	// Inspect old structures only when we're upgrading from old versions
-	// to versions >= 1.7 and the MountPoints has not been populated with volumes data.
-	type volumes struct {
-		Volumes   map[string]string
-		VolumesRW map[string]bool
-	}
-	cfgPath, err := container.ConfigPath()
-	if err != nil {
-		return err
-	}
-	f, err := os.Open(cfgPath)
-	if err != nil {
-		return errors.Wrap(err, "could not open container config")
-	}
-	defer f.Close()
-	var cv volumes
-	if err := json.NewDecoder(f).Decode(&cv); err != nil {
-		return errors.Wrap(err, "could not decode container config")
-	}
-
-	if len(container.MountPoints) == 0 && len(cv.Volumes) > 0 {
-		for destination, hostPath := range cv.Volumes {
-			vfsPath := filepath.Join(daemon.root, "vfs", "dir")
-			rw := cv.VolumesRW != nil && cv.VolumesRW[destination]
-
-			if strings.HasPrefix(hostPath, vfsPath) {
-				id := filepath.Base(hostPath)
-				v, err := daemon.volumes.CreateWithRef(id, volume.DefaultDriverName, container.ID, nil, nil)
-				if err != nil {
-					return err
-				}
-				if err := migrateVolume(id, hostPath); err != nil {
-					return err
-				}
-				container.AddMountPointWithVolume(destination, v, true)
-			} else { // Bind mount
-				m := volume.MountPoint{Source: hostPath, Destination: destination, RW: rw}
-				container.MountPoints[destination] = &m
-			}
-		}
-	}
-	return nil
-}
-
 func (daemon *Daemon) mountVolumes(container *container.Container) error {
 func (daemon *Daemon) mountVolumes(container *container.Container) error {
 	mounts, err := daemon.setupMounts(container)
 	mounts, err := daemon.setupMounts(container)
 	if err != nil {
 	if err != nil {

+ 0 - 79
integration-cli/docker_cli_daemon_test.go

@@ -35,7 +35,6 @@ import (
 	testdaemon "github.com/docker/docker/internal/test/daemon"
 	testdaemon "github.com/docker/docker/internal/test/daemon"
 	"github.com/docker/docker/opts"
 	"github.com/docker/docker/opts"
 	"github.com/docker/docker/pkg/mount"
 	"github.com/docker/docker/pkg/mount"
-	"github.com/docker/docker/pkg/stringid"
 	units "github.com/docker/go-units"
 	units "github.com/docker/go-units"
 	"github.com/docker/libnetwork/iptables"
 	"github.com/docker/libnetwork/iptables"
 	"github.com/docker/libtrust"
 	"github.com/docker/libtrust"
@@ -2668,84 +2667,6 @@ func (s *DockerDaemonSuite) TestDaemonRestartSaveContainerExitCode(c *check.C) {
 	c.Assert(out, checker.Equals, errMsg1)
 	c.Assert(out, checker.Equals, errMsg1)
 }
 }
 
 
-func (s *DockerDaemonSuite) TestDaemonBackcompatPre17Volumes(c *check.C) {
-	testRequires(c, SameHostDaemon)
-	d := s.d
-	d.StartWithBusybox(c)
-
-	// hack to be able to side-load a container config
-	out, err := d.Cmd("create", "busybox:latest")
-	c.Assert(err, checker.IsNil, check.Commentf(out))
-	id := strings.TrimSpace(out)
-
-	out, err = d.Cmd("inspect", "--type=image", "--format={{.ID}}", "busybox:latest")
-	c.Assert(err, checker.IsNil, check.Commentf(out))
-	d.Stop(c)
-	<-d.Wait
-
-	imageID := strings.TrimSpace(out)
-	volumeID := stringid.GenerateNonCryptoID()
-	vfsPath := filepath.Join(d.Root, "vfs", "dir", volumeID)
-	c.Assert(os.MkdirAll(vfsPath, 0755), checker.IsNil)
-
-	config := []byte(`
-		{
-			"ID": "` + id + `",
-			"Name": "hello",
-			"Driver": "` + d.StorageDriver() + `",
-			"Image": "` + imageID + `",
-			"Config": {"Image": "busybox:latest"},
-			"NetworkSettings": {},
-			"Volumes": {
-				"/bar":"/foo",
-				"/foo": "` + vfsPath + `",
-				"/quux":"/quux"
-			},
-			"VolumesRW": {
-				"/bar": true,
-				"/foo": true,
-				"/quux": false
-			}
-		}
-	`)
-
-	configPath := filepath.Join(d.Root, "containers", id, "config.v2.json")
-	c.Assert(ioutil.WriteFile(configPath, config, 600), checker.IsNil)
-	d.Start(c)
-
-	out, err = d.Cmd("inspect", "--type=container", "--format={{ json .Mounts }}", id)
-	c.Assert(err, checker.IsNil, check.Commentf(out))
-	type mount struct {
-		Name        string
-		Source      string
-		Destination string
-		Driver      string
-		RW          bool
-	}
-
-	ls := []mount{}
-	err = json.NewDecoder(strings.NewReader(out)).Decode(&ls)
-	c.Assert(err, checker.IsNil)
-
-	expected := []mount{
-		{Source: "/foo", Destination: "/bar", RW: true},
-		{Name: volumeID, Destination: "/foo", RW: true},
-		{Source: "/quux", Destination: "/quux", RW: false},
-	}
-	c.Assert(ls, checker.HasLen, len(expected))
-
-	for _, m := range ls {
-		var matched bool
-		for _, x := range expected {
-			if m.Source == x.Source && m.Destination == x.Destination && m.RW == x.RW || m.Name != x.Name {
-				matched = true
-				break
-			}
-		}
-		c.Assert(matched, checker.True, check.Commentf("did find match for %+v", m))
-	}
-}
-
 func (s *DockerDaemonSuite) TestDaemonWithUserlandProxyPath(c *check.C) {
 func (s *DockerDaemonSuite) TestDaemonWithUserlandProxyPath(c *check.C) {
 	testRequires(c, SameHostDaemon, DaemonIsLinux)
 	testRequires(c, SameHostDaemon, DaemonIsLinux)
 
 

+ 1 - 1
volume/drivers/adapter.go

@@ -1,4 +1,4 @@
-package volumedrivers // import "github.com/docker/docker/volume/drivers"
+package drivers // import "github.com/docker/docker/volume/drivers"
 
 
 import (
 import (
 	"errors"
 	"errors"

+ 68 - 91
volume/drivers/extpoint.go

@@ -1,12 +1,13 @@
 //go:generate pluginrpc-gen -i $GOFILE -o proxy.go -type volumeDriver -name VolumeDriver
 //go:generate pluginrpc-gen -i $GOFILE -o proxy.go -type volumeDriver -name VolumeDriver
 
 
-package volumedrivers // import "github.com/docker/docker/volume/drivers"
+package drivers // import "github.com/docker/docker/volume/drivers"
 
 
 import (
 import (
 	"fmt"
 	"fmt"
 	"sort"
 	"sort"
 	"sync"
 	"sync"
 
 
+	"github.com/docker/docker/errdefs"
 	"github.com/docker/docker/pkg/locker"
 	"github.com/docker/docker/pkg/locker"
 	getter "github.com/docker/docker/pkg/plugingetter"
 	getter "github.com/docker/docker/pkg/plugingetter"
 	"github.com/docker/docker/volume"
 	"github.com/docker/docker/volume"
@@ -14,14 +15,6 @@ import (
 	"github.com/sirupsen/logrus"
 	"github.com/sirupsen/logrus"
 )
 )
 
 
-// currently created by hand. generation tool would generate this like:
-// $ extpoint-gen Driver > volume/extpoint.go
-
-var drivers = &driverExtpoint{
-	extensions: make(map[string]volume.Driver),
-	driverLock: &locker.Locker{},
-}
-
 const extName = "VolumeDriver"
 const extName = "VolumeDriver"
 
 
 // NewVolumeDriver returns a driver has the given name mapped on the given client.
 // NewVolumeDriver returns a driver has the given name mapped on the given client.
@@ -53,53 +46,21 @@ type volumeDriver interface {
 	Capabilities() (capabilities volume.Capability, err error)
 	Capabilities() (capabilities volume.Capability, err error)
 }
 }
 
 
-type driverExtpoint struct {
-	extensions map[string]volume.Driver
-	sync.Mutex
+// Store is an in-memory store for volume drivers
+type Store struct {
+	extensions   map[string]volume.Driver
+	mu           sync.Mutex
 	driverLock   *locker.Locker
 	driverLock   *locker.Locker
-	plugingetter getter.PluginGetter
+	pluginGetter getter.PluginGetter
 }
 }
 
 
-// RegisterPluginGetter sets the plugingetter
-func RegisterPluginGetter(plugingetter getter.PluginGetter) {
-	drivers.plugingetter = plugingetter
-}
-
-// Register associates the given driver to the given name, checking if
-// the name is already associated
-func Register(extension volume.Driver, name string) bool {
-	if name == "" {
-		return false
-	}
-
-	drivers.Lock()
-	defer drivers.Unlock()
-
-	_, exists := drivers.extensions[name]
-	if exists {
-		return false
+// NewStore creates a new volume driver store
+func NewStore(pg getter.PluginGetter) *Store {
+	return &Store{
+		extensions:   make(map[string]volume.Driver),
+		driverLock:   locker.New(),
+		pluginGetter: pg,
 	}
 	}
-
-	if err := validateDriver(extension); err != nil {
-		return false
-	}
-
-	drivers.extensions[name] = extension
-
-	return true
-}
-
-// Unregister dissociates the name from its driver, if the association exists.
-func Unregister(name string) bool {
-	drivers.Lock()
-	defer drivers.Unlock()
-
-	_, exists := drivers.extensions[name]
-	if !exists {
-		return false
-	}
-	delete(drivers.extensions, name)
-	return true
 }
 }
 
 
 type driverNotFoundError string
 type driverNotFoundError string
@@ -113,18 +74,21 @@ func (driverNotFoundError) NotFound() {}
 // lookup returns the driver associated with the given name. If a
 // lookup returns the driver associated with the given name. If a
 // driver with the given name has not been registered it checks if
 // driver with the given name has not been registered it checks if
 // there is a VolumeDriver plugin available with the given name.
 // there is a VolumeDriver plugin available with the given name.
-func lookup(name string, mode int) (volume.Driver, error) {
-	drivers.driverLock.Lock(name)
-	defer drivers.driverLock.Unlock(name)
+func (s *Store) lookup(name string, mode int) (volume.Driver, error) {
+	if name == "" {
+		return nil, errdefs.InvalidParameter(errors.New("driver name cannot be empty"))
+	}
+	s.driverLock.Lock(name)
+	defer s.driverLock.Unlock(name)
 
 
-	drivers.Lock()
-	ext, ok := drivers.extensions[name]
-	drivers.Unlock()
+	s.mu.Lock()
+	ext, ok := s.extensions[name]
+	s.mu.Unlock()
 	if ok {
 	if ok {
 		return ext, nil
 		return ext, nil
 	}
 	}
-	if drivers.plugingetter != nil {
-		p, err := drivers.plugingetter.Get(name, extName, mode)
+	if s.pluginGetter != nil {
+		p, err := s.pluginGetter.Get(name, extName, mode)
 		if err != nil {
 		if err != nil {
 			return nil, errors.Wrap(err, "error looking up volume plugin "+name)
 			return nil, errors.Wrap(err, "error looking up volume plugin "+name)
 		}
 		}
@@ -133,7 +97,7 @@ func lookup(name string, mode int) (volume.Driver, error) {
 		if err := validateDriver(d); err != nil {
 		if err := validateDriver(d); err != nil {
 			if mode > 0 {
 			if mode > 0 {
 				// Undo any reference count changes from the initial `Get`
 				// Undo any reference count changes from the initial `Get`
-				if _, err := drivers.plugingetter.Get(name, extName, mode*-1); err != nil {
+				if _, err := s.pluginGetter.Get(name, extName, mode*-1); err != nil {
 					logrus.WithError(err).WithField("action", "validate-driver").WithField("plugin", name).Error("error releasing reference to plugin")
 					logrus.WithError(err).WithField("action", "validate-driver").WithField("plugin", name).Error("error releasing reference to plugin")
 				}
 				}
 			}
 			}
@@ -141,9 +105,9 @@ func lookup(name string, mode int) (volume.Driver, error) {
 		}
 		}
 
 
 		if p.IsV1() {
 		if p.IsV1() {
-			drivers.Lock()
-			drivers.extensions[name] = d
-			drivers.Unlock()
+			s.mu.Lock()
+			s.extensions[name] = d
+			s.mu.Unlock()
 		}
 		}
 		return d, nil
 		return d, nil
 	}
 	}
@@ -158,75 +122,88 @@ func validateDriver(vd volume.Driver) error {
 	return nil
 	return nil
 }
 }
 
 
-// GetDriver returns a volume driver by its name.
-// If the driver is empty, it looks for the local driver.
-func GetDriver(name string) (volume.Driver, error) {
+// Register associates the given driver to the given name, checking if
+// the name is already associated
+func (s *Store) Register(d volume.Driver, name string) bool {
 	if name == "" {
 	if name == "" {
-		name = volume.DefaultDriverName
+		return false
+	}
+
+	s.mu.Lock()
+	defer s.mu.Unlock()
+
+	if _, exists := s.extensions[name]; exists {
+		return false
+	}
+
+	if err := validateDriver(d); err != nil {
+		return false
 	}
 	}
-	return lookup(name, getter.Lookup)
+
+	s.extensions[name] = d
+	return true
+}
+
+// GetDriver returns a volume driver by its name.
+// If the driver is empty, it looks for the local driver.
+func (s *Store) GetDriver(name string) (volume.Driver, error) {
+	return s.lookup(name, getter.Lookup)
 }
 }
 
 
 // CreateDriver returns a volume driver by its name and increments RefCount.
 // CreateDriver returns a volume driver by its name and increments RefCount.
 // If the driver is empty, it looks for the local driver.
 // If the driver is empty, it looks for the local driver.
-func CreateDriver(name string) (volume.Driver, error) {
-	if name == "" {
-		name = volume.DefaultDriverName
-	}
-	return lookup(name, getter.Acquire)
+func (s *Store) CreateDriver(name string) (volume.Driver, error) {
+	return s.lookup(name, getter.Acquire)
 }
 }
 
 
 // ReleaseDriver returns a volume driver by its name and decrements RefCount..
 // ReleaseDriver returns a volume driver by its name and decrements RefCount..
 // If the driver is empty, it looks for the local driver.
 // If the driver is empty, it looks for the local driver.
-func ReleaseDriver(name string) (volume.Driver, error) {
-	if name == "" {
-		name = volume.DefaultDriverName
-	}
-	return lookup(name, getter.Release)
+func (s *Store) ReleaseDriver(name string) (volume.Driver, error) {
+	return s.lookup(name, getter.Release)
 }
 }
 
 
 // GetDriverList returns list of volume drivers registered.
 // GetDriverList returns list of volume drivers registered.
 // If no driver is registered, empty string list will be returned.
 // If no driver is registered, empty string list will be returned.
-func GetDriverList() []string {
+func (s *Store) GetDriverList() []string {
 	var driverList []string
 	var driverList []string
-	drivers.Lock()
-	for driverName := range drivers.extensions {
+	s.mu.Lock()
+	for driverName := range s.extensions {
 		driverList = append(driverList, driverName)
 		driverList = append(driverList, driverName)
 	}
 	}
-	drivers.Unlock()
+	s.mu.Unlock()
 	sort.Strings(driverList)
 	sort.Strings(driverList)
 	return driverList
 	return driverList
 }
 }
 
 
 // GetAllDrivers lists all the registered drivers
 // GetAllDrivers lists all the registered drivers
-func GetAllDrivers() ([]volume.Driver, error) {
+func (s *Store) GetAllDrivers() ([]volume.Driver, error) {
 	var plugins []getter.CompatPlugin
 	var plugins []getter.CompatPlugin
-	if drivers.plugingetter != nil {
+	if s.pluginGetter != nil {
 		var err error
 		var err error
-		plugins, err = drivers.plugingetter.GetAllByCap(extName)
+		plugins, err = s.pluginGetter.GetAllByCap(extName)
 		if err != nil {
 		if err != nil {
 			return nil, fmt.Errorf("error listing plugins: %v", err)
 			return nil, fmt.Errorf("error listing plugins: %v", err)
 		}
 		}
 	}
 	}
 	var ds []volume.Driver
 	var ds []volume.Driver
 
 
-	drivers.Lock()
-	defer drivers.Unlock()
+	s.mu.Lock()
+	defer s.mu.Unlock()
 
 
-	for _, d := range drivers.extensions {
+	for _, d := range s.extensions {
 		ds = append(ds, d)
 		ds = append(ds, d)
 	}
 	}
 
 
 	for _, p := range plugins {
 	for _, p := range plugins {
 		name := p.Name()
 		name := p.Name()
 
 
-		if _, ok := drivers.extensions[name]; ok {
+		if _, ok := s.extensions[name]; ok {
 			continue
 			continue
 		}
 		}
 
 
 		ext := NewVolumeDriver(name, p.ScopedPath, p.Client())
 		ext := NewVolumeDriver(name, p.ScopedPath, p.Client())
 		if p.IsV1() {
 		if p.IsV1() {
-			drivers.extensions[name] = ext
+			s.extensions[name] = ext
 		}
 		}
 		ds = append(ds, ext)
 		ds = append(ds, ext)
 	}
 	}

+ 5 - 4
volume/drivers/extpoint_test.go

@@ -1,4 +1,4 @@
-package volumedrivers // import "github.com/docker/docker/volume/drivers"
+package drivers // import "github.com/docker/docker/volume/drivers"
 
 
 import (
 import (
 	"testing"
 	"testing"
@@ -7,13 +7,14 @@ import (
 )
 )
 
 
 func TestGetDriver(t *testing.T) {
 func TestGetDriver(t *testing.T) {
-	_, err := GetDriver("missing")
+	s := NewStore(nil)
+	_, err := s.GetDriver("missing")
 	if err == nil {
 	if err == nil {
 		t.Fatal("Expected error, was nil")
 		t.Fatal("Expected error, was nil")
 	}
 	}
-	Register(volumetestutils.NewFakeDriver("fake"), "fake")
+	s.Register(volumetestutils.NewFakeDriver("fake"), "fake")
 
 
-	d, err := GetDriver("fake")
+	d, err := s.GetDriver("fake")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}

+ 1 - 1
volume/drivers/proxy.go

@@ -1,6 +1,6 @@
 // generated code - DO NOT EDIT
 // generated code - DO NOT EDIT
 
 
-package volumedrivers // import "github.com/docker/docker/volume/drivers"
+package drivers // import "github.com/docker/docker/volume/drivers"
 
 
 import (
 import (
 	"errors"
 	"errors"

+ 1 - 1
volume/drivers/proxy_test.go

@@ -1,4 +1,4 @@
-package volumedrivers // import "github.com/docker/docker/volume/drivers"
+package drivers // import "github.com/docker/docker/volume/drivers"
 
 
 import (
 import (
 	"fmt"
 	"fmt"

+ 2 - 3
volume/store/restore.go

@@ -5,7 +5,6 @@ import (
 
 
 	"github.com/boltdb/bolt"
 	"github.com/boltdb/bolt"
 	"github.com/docker/docker/volume"
 	"github.com/docker/docker/volume"
-	"github.com/docker/docker/volume/drivers"
 	"github.com/sirupsen/logrus"
 	"github.com/sirupsen/logrus"
 )
 )
 
 
@@ -33,7 +32,7 @@ func (s *VolumeStore) restore() {
 			var v volume.Volume
 			var v volume.Volume
 			var err error
 			var err error
 			if meta.Driver != "" {
 			if meta.Driver != "" {
-				v, err = lookupVolume(meta.Driver, meta.Name)
+				v, err = lookupVolume(s.drivers, meta.Driver, meta.Name)
 				if err != nil && err != errNoSuchVolume {
 				if err != nil && err != errNoSuchVolume {
 					logrus.WithError(err).WithField("driver", meta.Driver).WithField("volume", meta.Name).Warn("Error restoring volume")
 					logrus.WithError(err).WithField("driver", meta.Driver).WithField("volume", meta.Name).Warn("Error restoring volume")
 					return
 					return
@@ -59,7 +58,7 @@ func (s *VolumeStore) restore() {
 			}
 			}
 
 
 			// increment driver refcount
 			// increment driver refcount
-			volumedrivers.CreateDriver(meta.Driver)
+			s.drivers.CreateDriver(meta.Driver)
 
 
 			// cache the volume
 			// cache the volume
 			s.globalLock.Lock()
 			s.globalLock.Lock()

+ 4 - 4
volume/store/restore_test.go

@@ -18,11 +18,11 @@ func TestRestore(t *testing.T) {
 	assert.NilError(t, err)
 	assert.NilError(t, err)
 	defer os.RemoveAll(dir)
 	defer os.RemoveAll(dir)
 
 
+	drivers := volumedrivers.NewStore(nil)
 	driverName := "test-restore"
 	driverName := "test-restore"
-	volumedrivers.Register(volumetestutils.NewFakeDriver(driverName), driverName)
-	defer volumedrivers.Unregister("test-restore")
+	drivers.Register(volumetestutils.NewFakeDriver(driverName), driverName)
 
 
-	s, err := New(dir)
+	s, err := New(dir, drivers)
 	assert.NilError(t, err)
 	assert.NilError(t, err)
 	defer s.Shutdown()
 	defer s.Shutdown()
 
 
@@ -36,7 +36,7 @@ func TestRestore(t *testing.T) {
 
 
 	s.Shutdown()
 	s.Shutdown()
 
 
-	s, err = New(dir)
+	s, err = New(dir, drivers)
 	assert.NilError(t, err)
 	assert.NilError(t, err)
 
 
 	v, err := s.Get("test1")
 	v, err := s.Get("test1")

+ 36 - 18
volume/store/store.go

@@ -66,13 +66,14 @@ func (v volumeWrapper) CachedPath() string {
 
 
 // New initializes a VolumeStore to keep
 // New initializes a VolumeStore to keep
 // reference counting of volumes in the system.
 // reference counting of volumes in the system.
-func New(rootPath string) (*VolumeStore, error) {
+func New(rootPath string, drivers *drivers.Store) (*VolumeStore, error) {
 	vs := &VolumeStore{
 	vs := &VolumeStore{
 		locks:   &locker.Locker{},
 		locks:   &locker.Locker{},
 		names:   make(map[string]volume.Volume),
 		names:   make(map[string]volume.Volume),
 		refs:    make(map[string]map[string]struct{}),
 		refs:    make(map[string]map[string]struct{}),
 		labels:  make(map[string]map[string]string),
 		labels:  make(map[string]map[string]string),
 		options: make(map[string]map[string]string),
 		options: make(map[string]map[string]string),
+		drivers: drivers,
 	}
 	}
 
 
 	if rootPath != "" {
 	if rootPath != "" {
@@ -157,7 +158,7 @@ func (s *VolumeStore) Purge(name string) {
 	v, exists := s.names[name]
 	v, exists := s.names[name]
 	if exists {
 	if exists {
 		driverName := v.DriverName()
 		driverName := v.DriverName()
-		if _, err := volumedrivers.ReleaseDriver(driverName); err != nil {
+		if _, err := s.drivers.ReleaseDriver(driverName); err != nil {
 			logrus.WithError(err).WithField("driver", driverName).Error("Error releasing reference to volume driver")
 			logrus.WithError(err).WithField("driver", driverName).Error("Error releasing reference to volume driver")
 		}
 		}
 	}
 	}
@@ -175,7 +176,8 @@ func (s *VolumeStore) Purge(name string) {
 type VolumeStore struct {
 type VolumeStore struct {
 	// locks ensures that only one action is being performed on a particular volume at a time without locking the entire store
 	// locks ensures that only one action is being performed on a particular volume at a time without locking the entire store
 	// since actions on volumes can be quite slow, this ensures the store is free to handle requests for other volumes.
 	// since actions on volumes can be quite slow, this ensures the store is free to handle requests for other volumes.
-	locks *locker.Locker
+	locks   *locker.Locker
+	drivers *drivers.Store
 	// globalLock is used to protect access to mutable structures used by the store object
 	// globalLock is used to protect access to mutable structures used by the store object
 	globalLock sync.RWMutex
 	globalLock sync.RWMutex
 	// names stores the volume name -> volume relationship.
 	// names stores the volume name -> volume relationship.
@@ -226,7 +228,7 @@ func (s *VolumeStore) list() ([]volume.Volume, []string, error) {
 		warnings []string
 		warnings []string
 	)
 	)
 
 
-	drivers, err := volumedrivers.GetAllDrivers()
+	drivers, err := s.drivers.GetAllDrivers()
 	if err != nil {
 	if err != nil {
 		return nil, nil, err
 		return nil, nil, err
 	}
 	}
@@ -329,7 +331,7 @@ func (s *VolumeStore) checkConflict(name, driverName string) (volume.Volume, err
 	if driverName != "" {
 	if driverName != "" {
 		// Retrieve canonical driver name to avoid inconsistencies (for example
 		// Retrieve canonical driver name to avoid inconsistencies (for example
 		// "plugin" vs. "plugin:latest")
 		// "plugin" vs. "plugin:latest")
-		vd, err := volumedrivers.GetDriver(driverName)
+		vd, err := s.drivers.GetDriver(driverName)
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
@@ -341,7 +343,7 @@ func (s *VolumeStore) checkConflict(name, driverName string) (volume.Volume, err
 
 
 	// let's check if the found volume ref
 	// let's check if the found volume ref
 	// is stale by checking with the driver if it still exists
 	// is stale by checking with the driver if it still exists
-	exists, err := volumeExists(v)
+	exists, err := volumeExists(s.drivers, v)
 	if err != nil {
 	if err != nil {
 		return nil, errors.Wrapf(errNameConflict, "found reference to volume '%s' in driver '%s', but got an error while checking the driver: %v", name, vDriverName, err)
 		return nil, errors.Wrapf(errNameConflict, "found reference to volume '%s' in driver '%s', but got an error while checking the driver: %v", name, vDriverName, err)
 	}
 	}
@@ -366,8 +368,8 @@ func (s *VolumeStore) checkConflict(name, driverName string) (volume.Volume, err
 
 
 // volumeExists returns if the volume is still present in the driver.
 // volumeExists returns if the volume is still present in the driver.
 // An error is returned if there was an issue communicating with the driver.
 // An error is returned if there was an issue communicating with the driver.
-func volumeExists(v volume.Volume) (bool, error) {
-	exists, err := lookupVolume(v.DriverName(), v.Name())
+func volumeExists(store *drivers.Store, v volume.Volume) (bool, error) {
+	exists, err := lookupVolume(store, v.DriverName(), v.Name())
 	if err != nil {
 	if err != nil {
 		return false, err
 		return false, err
 	}
 	}
@@ -412,7 +414,10 @@ func (s *VolumeStore) create(name, driverName string, opts, labels map[string]st
 		}
 		}
 	}
 	}
 
 
-	vd, err := volumedrivers.CreateDriver(driverName)
+	if driverName == "" {
+		driverName = volume.DefaultDriverName
+	}
+	vd, err := s.drivers.CreateDriver(driverName)
 	if err != nil {
 	if err != nil {
 		return nil, &OpErr{Op: "create", Name: name, Err: err}
 		return nil, &OpErr{Op: "create", Name: name, Err: err}
 	}
 	}
@@ -421,7 +426,7 @@ func (s *VolumeStore) create(name, driverName string, opts, labels map[string]st
 	if v, _ = vd.Get(name); v == nil {
 	if v, _ = vd.Get(name); v == nil {
 		v, err = vd.Create(name, opts)
 		v, err = vd.Create(name, opts)
 		if err != nil {
 		if err != nil {
-			if _, err := volumedrivers.ReleaseDriver(driverName); err != nil {
+			if _, err := s.drivers.ReleaseDriver(driverName); err != nil {
 				logrus.WithError(err).WithField("driver", driverName).Error("Error releasing reference to volume driver")
 				logrus.WithError(err).WithField("driver", driverName).Error("Error releasing reference to volume driver")
 			}
 			}
 			return nil, err
 			return nil, err
@@ -455,7 +460,10 @@ func (s *VolumeStore) GetWithRef(name, driverName, ref string) (volume.Volume, e
 	s.locks.Lock(name)
 	s.locks.Lock(name)
 	defer s.locks.Unlock(name)
 	defer s.locks.Unlock(name)
 
 
-	vd, err := volumedrivers.GetDriver(driverName)
+	if driverName == "" {
+		driverName = volume.DefaultDriverName
+	}
+	vd, err := s.drivers.GetDriver(driverName)
 	if err != nil {
 	if err != nil {
 		return nil, &OpErr{Err: err, Name: name, Op: "get"}
 		return nil, &OpErr{Err: err, Name: name, Op: "get"}
 	}
 	}
@@ -510,7 +518,7 @@ func (s *VolumeStore) getVolume(name string) (volume.Volume, error) {
 	}
 	}
 
 
 	if meta.Driver != "" {
 	if meta.Driver != "" {
-		vol, err := lookupVolume(meta.Driver, name)
+		vol, err := lookupVolume(s.drivers, meta.Driver, name)
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
@@ -520,7 +528,7 @@ func (s *VolumeStore) getVolume(name string) (volume.Volume, error) {
 		}
 		}
 
 
 		var scope string
 		var scope string
-		vd, err := volumedrivers.GetDriver(meta.Driver)
+		vd, err := s.drivers.GetDriver(meta.Driver)
 		if err == nil {
 		if err == nil {
 			scope = vd.Scope()
 			scope = vd.Scope()
 		}
 		}
@@ -528,7 +536,7 @@ func (s *VolumeStore) getVolume(name string) (volume.Volume, error) {
 	}
 	}
 
 
 	logrus.Debugf("Probing all drivers for volume with name: %s", name)
 	logrus.Debugf("Probing all drivers for volume with name: %s", name)
-	drivers, err := volumedrivers.GetAllDrivers()
+	drivers, err := s.drivers.GetAllDrivers()
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -552,8 +560,11 @@ func (s *VolumeStore) getVolume(name string) (volume.Volume, error) {
 // If the driver returns an error that is not communication related the
 // If the driver returns an error that is not communication related the
 //   error is logged but not returned.
 //   error is logged but not returned.
 // If the volume is not found it will return `nil, nil``
 // If the volume is not found it will return `nil, nil``
-func lookupVolume(driverName, volumeName string) (volume.Volume, error) {
-	vd, err := volumedrivers.GetDriver(driverName)
+func lookupVolume(store *drivers.Store, driverName, volumeName string) (volume.Volume, error) {
+	if driverName == "" {
+		driverName = volume.DefaultDriverName
+	}
+	vd, err := store.GetDriver(driverName)
 	if err != nil {
 	if err != nil {
 		return nil, errors.Wrapf(err, "error while checking if volume %q exists in driver %q", volumeName, driverName)
 		return nil, errors.Wrapf(err, "error while checking if volume %q exists in driver %q", volumeName, driverName)
 	}
 	}
@@ -585,7 +596,7 @@ func (s *VolumeStore) Remove(v volume.Volume) error {
 		return &OpErr{Err: errVolumeInUse, Name: v.Name(), Op: "remove", Refs: s.getRefs(name)}
 		return &OpErr{Err: errVolumeInUse, Name: v.Name(), Op: "remove", Refs: s.getRefs(name)}
 	}
 	}
 
 
-	vd, err := volumedrivers.GetDriver(v.DriverName())
+	vd, err := s.drivers.GetDriver(v.DriverName())
 	if err != nil {
 	if err != nil {
 		return &OpErr{Err: err, Name: v.DriverName(), Op: "remove"}
 		return &OpErr{Err: err, Name: v.DriverName(), Op: "remove"}
 	}
 	}
@@ -627,7 +638,7 @@ func (s *VolumeStore) Refs(v volume.Volume) []string {
 
 
 // FilterByDriver returns the available volumes filtered by driver name
 // FilterByDriver returns the available volumes filtered by driver name
 func (s *VolumeStore) FilterByDriver(name string) ([]volume.Volume, error) {
 func (s *VolumeStore) FilterByDriver(name string) ([]volume.Volume, error) {
-	vd, err := volumedrivers.GetDriver(name)
+	vd, err := s.drivers.GetDriver(name)
 	if err != nil {
 	if err != nil {
 		return nil, &OpErr{Err: err, Name: name, Op: "list"}
 		return nil, &OpErr{Err: err, Name: name, Op: "list"}
 	}
 	}
@@ -686,3 +697,10 @@ func unwrapVolume(v volume.Volume) volume.Volume {
 func (s *VolumeStore) Shutdown() error {
 func (s *VolumeStore) Shutdown() error {
 	return s.db.Close()
 	return s.db.Close()
 }
 }
+
+// GetDriverList gets the list of volume drivers from the configured volume driver
+// store.
+// TODO(@cpuguy83): This should be factored out into a separate service.
+func (s *VolumeStore) GetDriverList() []string {
+	return s.drivers.GetDriverList()
+}

+ 66 - 115
volume/store/store_test.go

@@ -10,7 +10,7 @@ import (
 	"testing"
 	"testing"
 
 
 	"github.com/docker/docker/volume"
 	"github.com/docker/docker/volume"
-	"github.com/docker/docker/volume/drivers"
+	volumedrivers "github.com/docker/docker/volume/drivers"
 	volumetestutils "github.com/docker/docker/volume/testutils"
 	volumetestutils "github.com/docker/docker/volume/testutils"
 	"github.com/google/go-cmp/cmp"
 	"github.com/google/go-cmp/cmp"
 	"github.com/gotestyourself/gotestyourself/assert"
 	"github.com/gotestyourself/gotestyourself/assert"
@@ -18,18 +18,12 @@ import (
 )
 )
 
 
 func TestCreate(t *testing.T) {
 func TestCreate(t *testing.T) {
-	volumedrivers.Register(volumetestutils.NewFakeDriver("fake"), "fake")
-	defer volumedrivers.Unregister("fake")
-	dir, err := ioutil.TempDir("", "test-create")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(dir)
+	t.Parallel()
+
+	s, cleanup := setupTest(t)
+	defer cleanup()
+	s.drivers.Register(volumetestutils.NewFakeDriver("fake"), "fake")
 
 
-	s, err := New(dir)
-	if err != nil {
-		t.Fatal(err)
-	}
 	v, err := s.Create("fake1", "fake", nil, nil)
 	v, err := s.Create("fake1", "fake", nil, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -53,19 +47,13 @@ func TestCreate(t *testing.T) {
 }
 }
 
 
 func TestRemove(t *testing.T) {
 func TestRemove(t *testing.T) {
-	volumedrivers.Register(volumetestutils.NewFakeDriver("fake"), "fake")
-	volumedrivers.Register(volumetestutils.NewFakeDriver("noop"), "noop")
-	defer volumedrivers.Unregister("fake")
-	defer volumedrivers.Unregister("noop")
-	dir, err := ioutil.TempDir("", "test-remove")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(dir)
-	s, err := New(dir)
-	if err != nil {
-		t.Fatal(err)
-	}
+	t.Parallel()
+
+	s, cleanup := setupTest(t)
+	defer cleanup()
+
+	s.drivers.Register(volumetestutils.NewFakeDriver("fake"), "fake")
+	s.drivers.Register(volumetestutils.NewFakeDriver("noop"), "noop")
 
 
 	// doing string compare here since this error comes directly from the driver
 	// doing string compare here since this error comes directly from the driver
 	expected := "no such volume"
 	expected := "no such volume"
@@ -91,20 +79,19 @@ func TestRemove(t *testing.T) {
 }
 }
 
 
 func TestList(t *testing.T) {
 func TestList(t *testing.T) {
-	volumedrivers.Register(volumetestutils.NewFakeDriver("fake"), "fake")
-	volumedrivers.Register(volumetestutils.NewFakeDriver("fake2"), "fake2")
-	defer volumedrivers.Unregister("fake")
-	defer volumedrivers.Unregister("fake2")
+	t.Parallel()
+
 	dir, err := ioutil.TempDir("", "test-list")
 	dir, err := ioutil.TempDir("", "test-list")
-	if err != nil {
-		t.Fatal(err)
-	}
+	assert.NilError(t, err)
 	defer os.RemoveAll(dir)
 	defer os.RemoveAll(dir)
 
 
-	s, err := New(dir)
-	if err != nil {
-		t.Fatal(err)
-	}
+	drivers := volumedrivers.NewStore(nil)
+	drivers.Register(volumetestutils.NewFakeDriver("fake"), "fake")
+	drivers.Register(volumetestutils.NewFakeDriver("fake2"), "fake2")
+
+	s, err := New(dir, drivers)
+	assert.NilError(t, err)
+
 	if _, err := s.Create("test", "fake", nil, nil); err != nil {
 	if _, err := s.Create("test", "fake", nil, nil); err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -124,7 +111,7 @@ func TestList(t *testing.T) {
 	}
 	}
 
 
 	// and again with a new store
 	// and again with a new store
-	s, err = New(dir)
+	s, err = New(dir, drivers)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -138,18 +125,12 @@ func TestList(t *testing.T) {
 }
 }
 
 
 func TestFilterByDriver(t *testing.T) {
 func TestFilterByDriver(t *testing.T) {
-	volumedrivers.Register(volumetestutils.NewFakeDriver("fake"), "fake")
-	volumedrivers.Register(volumetestutils.NewFakeDriver("noop"), "noop")
-	defer volumedrivers.Unregister("fake")
-	defer volumedrivers.Unregister("noop")
-	dir, err := ioutil.TempDir("", "test-filter-driver")
-	if err != nil {
-		t.Fatal(err)
-	}
-	s, err := New(dir)
-	if err != nil {
-		t.Fatal(err)
-	}
+	t.Parallel()
+	s, cleanup := setupTest(t)
+	defer cleanup()
+
+	s.drivers.Register(volumetestutils.NewFakeDriver("fake"), "fake")
+	s.drivers.Register(volumetestutils.NewFakeDriver("noop"), "noop")
 
 
 	if _, err := s.Create("fake1", "fake", nil, nil); err != nil {
 	if _, err := s.Create("fake1", "fake", nil, nil); err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -171,17 +152,12 @@ func TestFilterByDriver(t *testing.T) {
 }
 }
 
 
 func TestFilterByUsed(t *testing.T) {
 func TestFilterByUsed(t *testing.T) {
-	volumedrivers.Register(volumetestutils.NewFakeDriver("fake"), "fake")
-	volumedrivers.Register(volumetestutils.NewFakeDriver("noop"), "noop")
-	dir, err := ioutil.TempDir("", "test-filter-used")
-	if err != nil {
-		t.Fatal(err)
-	}
+	t.Parallel()
+	s, cleanup := setupTest(t)
+	defer cleanup()
 
 
-	s, err := New(dir)
-	if err != nil {
-		t.Fatal(err)
-	}
+	s.drivers.Register(volumetestutils.NewFakeDriver("fake"), "fake")
+	s.drivers.Register(volumetestutils.NewFakeDriver("noop"), "noop")
 
 
 	if _, err := s.CreateWithRef("fake1", "fake", "volReference", nil, nil); err != nil {
 	if _, err := s.CreateWithRef("fake1", "fake", "volReference", nil, nil); err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -213,16 +189,10 @@ func TestFilterByUsed(t *testing.T) {
 }
 }
 
 
 func TestDerefMultipleOfSameRef(t *testing.T) {
 func TestDerefMultipleOfSameRef(t *testing.T) {
-	volumedrivers.Register(volumetestutils.NewFakeDriver("fake"), "fake")
-	dir, err := ioutil.TempDir("", "test-same-deref")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(dir)
-	s, err := New(dir)
-	if err != nil {
-		t.Fatal(err)
-	}
+	t.Parallel()
+	s, cleanup := setupTest(t)
+	defer cleanup()
+	s.drivers.Register(volumetestutils.NewFakeDriver("fake"), "fake")
 
 
 	v, err := s.CreateWithRef("fake1", "fake", "volReference", nil, nil)
 	v, err := s.CreateWithRef("fake1", "fake", "volReference", nil, nil)
 	if err != nil {
 	if err != nil {
@@ -240,17 +210,12 @@ func TestDerefMultipleOfSameRef(t *testing.T) {
 }
 }
 
 
 func TestCreateKeepOptsLabelsWhenExistsRemotely(t *testing.T) {
 func TestCreateKeepOptsLabelsWhenExistsRemotely(t *testing.T) {
+	t.Parallel()
+	s, cleanup := setupTest(t)
+	defer cleanup()
+
 	vd := volumetestutils.NewFakeDriver("fake")
 	vd := volumetestutils.NewFakeDriver("fake")
-	volumedrivers.Register(vd, "fake")
-	dir, err := ioutil.TempDir("", "test-same-deref")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(dir)
-	s, err := New(dir)
-	if err != nil {
-		t.Fatal(err)
-	}
+	s.drivers.Register(vd, "fake")
 
 
 	// Create a volume in the driver directly
 	// Create a volume in the driver directly
 	if _, err := vd.Create("foo", nil); err != nil {
 	if _, err := vd.Create("foo", nil); err != nil {
@@ -273,6 +238,8 @@ func TestCreateKeepOptsLabelsWhenExistsRemotely(t *testing.T) {
 }
 }
 
 
 func TestDefererencePluginOnCreateError(t *testing.T) {
 func TestDefererencePluginOnCreateError(t *testing.T) {
+	t.Parallel()
+
 	var (
 	var (
 		l   net.Listener
 		l   net.Listener
 		err error
 		err error
@@ -286,6 +253,9 @@ func TestDefererencePluginOnCreateError(t *testing.T) {
 	}
 	}
 	defer l.Close()
 	defer l.Close()
 
 
+	s, cleanup := setupTest(t)
+	defer cleanup()
+
 	d := volumetestutils.NewFakeDriver("TestDefererencePluginOnCreateError")
 	d := volumetestutils.NewFakeDriver("TestDefererencePluginOnCreateError")
 	p, err := volumetestutils.MakeFakePlugin(d, l)
 	p, err := volumetestutils.MakeFakePlugin(d, l)
 	if err != nil {
 	if err != nil {
@@ -293,19 +263,7 @@ func TestDefererencePluginOnCreateError(t *testing.T) {
 	}
 	}
 
 
 	pg := volumetestutils.NewFakePluginGetter(p)
 	pg := volumetestutils.NewFakePluginGetter(p)
-	volumedrivers.RegisterPluginGetter(pg)
-	defer volumedrivers.RegisterPluginGetter(nil)
-
-	dir, err := ioutil.TempDir("", "test-plugin-deref-err")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(dir)
-
-	s, err := New(dir)
-	if err != nil {
-		t.Fatal(err)
-	}
+	s.drivers = volumedrivers.NewStore(pg)
 
 
 	// create a good volume so we have a plugin reference
 	// create a good volume so we have a plugin reference
 	_, err = s.Create("fake1", d.Name(), nil, nil)
 	_, err = s.Create("fake1", d.Name(), nil, nil)
@@ -329,8 +287,9 @@ func TestRefDerefRemove(t *testing.T) {
 	t.Parallel()
 	t.Parallel()
 
 
 	driverName := "test-ref-deref-remove"
 	driverName := "test-ref-deref-remove"
-	s, cleanup := setupTest(t, driverName)
-	defer cleanup(t)
+	s, cleanup := setupTest(t)
+	defer cleanup()
+	s.drivers.Register(volumetestutils.NewFakeDriver(driverName), driverName)
 
 
 	v, err := s.CreateWithRef("test", driverName, "test-ref", nil, nil)
 	v, err := s.CreateWithRef("test", driverName, "test-ref", nil, nil)
 	assert.NilError(t, err)
 	assert.NilError(t, err)
@@ -348,8 +307,9 @@ func TestGet(t *testing.T) {
 	t.Parallel()
 	t.Parallel()
 
 
 	driverName := "test-get"
 	driverName := "test-get"
-	s, cleanup := setupTest(t, driverName)
-	defer cleanup(t)
+	s, cleanup := setupTest(t)
+	defer cleanup()
+	s.drivers.Register(volumetestutils.NewFakeDriver(driverName), driverName)
 
 
 	_, err := s.Get("not-exist")
 	_, err := s.Get("not-exist")
 	assert.Assert(t, is.ErrorContains(err, ""))
 	assert.Assert(t, is.ErrorContains(err, ""))
@@ -373,8 +333,9 @@ func TestGetWithRef(t *testing.T) {
 	t.Parallel()
 	t.Parallel()
 
 
 	driverName := "test-get-with-ref"
 	driverName := "test-get-with-ref"
-	s, cleanup := setupTest(t, driverName)
-	defer cleanup(t)
+	s, cleanup := setupTest(t)
+	defer cleanup()
+	s.drivers.Register(volumetestutils.NewFakeDriver(driverName), driverName)
 
 
 	_, err := s.GetWithRef("not-exist", driverName, "test-ref")
 	_, err := s.GetWithRef("not-exist", driverName, "test-ref")
 	assert.Assert(t, is.ErrorContains(err, ""))
 	assert.Assert(t, is.ErrorContains(err, ""))
@@ -397,32 +358,22 @@ func TestGetWithRef(t *testing.T) {
 
 
 var cmpVolume = cmp.AllowUnexported(volumetestutils.FakeVolume{}, volumeWrapper{})
 var cmpVolume = cmp.AllowUnexported(volumetestutils.FakeVolume{}, volumeWrapper{})
 
 
-func setupTest(t *testing.T, name string) (*VolumeStore, func(*testing.T)) {
-	t.Helper()
-	s, cleanup := newTestStore(t)
-
-	volumedrivers.Register(volumetestutils.NewFakeDriver(name), name)
-	return s, func(t *testing.T) {
-		cleanup(t)
-		volumedrivers.Unregister(name)
-	}
-}
-
-func newTestStore(t *testing.T) (*VolumeStore, func(*testing.T)) {
+func setupTest(t *testing.T) (*VolumeStore, func()) {
 	t.Helper()
 	t.Helper()
 
 
-	dir, err := ioutil.TempDir("", "store-root")
+	dirName := strings.Replace(t.Name(), string(os.PathSeparator), "_", -1)
+	dir, err := ioutil.TempDir("", dirName)
 	assert.NilError(t, err)
 	assert.NilError(t, err)
 
 
-	cleanup := func(t *testing.T) {
+	cleanup := func() {
 		err := os.RemoveAll(dir)
 		err := os.RemoveAll(dir)
 		assert.Check(t, err)
 		assert.Check(t, err)
 	}
 	}
 
 
-	s, err := New(dir)
+	s, err := New(dir, volumedrivers.NewStore(nil))
 	assert.Check(t, err)
 	assert.Check(t, err)
-	return s, func(t *testing.T) {
+	return s, func() {
 		s.Shutdown()
 		s.Shutdown()
-		cleanup(t)
+		cleanup()
 	}
 	}
 }
 }