Merge pull request #36637 from cpuguy83/no_global_driver_store
No global volume driver store
This commit is contained in:
commit
6cd806aa53
19 changed files with 236 additions and 582 deletions
|
@ -179,11 +179,6 @@ func (daemon *Daemon) restore() error {
|
|||
delete(containers, id)
|
||||
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 {
|
||||
logrus.Errorf("Failed to register container %s: %s", c.ID, err)
|
||||
delete(containers, id)
|
||||
|
@ -1150,17 +1145,15 @@ func setDefaultMtu(conf *config.Config) {
|
|||
}
|
||||
|
||||
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 {
|
||||
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 store.New(daemon.configStore.Root)
|
||||
return store.New(daemon.configStore.Root, drivers)
|
||||
}
|
||||
|
||||
// IsShuttingDown tells whether the daemon is shutting down or not
|
||||
|
|
|
@ -13,7 +13,6 @@ import (
|
|||
_ "github.com/docker/docker/pkg/discovery/memory"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/truncindex"
|
||||
"github.com/docker/docker/volume"
|
||||
volumedrivers "github.com/docker/docker/volume/drivers"
|
||||
"github.com/docker/docker/volume/local"
|
||||
"github.com/docker/docker/volume/store"
|
||||
|
@ -121,7 +120,8 @@ func initDaemonWithVolumeStore(tmp string) (*Daemon, error) {
|
|||
repository: tmp,
|
||||
root: tmp,
|
||||
}
|
||||
daemon.volumes, err = store.New(tmp)
|
||||
drivers := volumedrivers.NewStore(nil)
|
||||
daemon.volumes, err = store.New(tmp, drivers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ func initDaemonWithVolumeStore(tmp string) (*Daemon, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
volumedrivers.Register(volumesDriver, volumesDriver.Name())
|
||||
drivers.Register(volumesDriver, volumesDriver.Name())
|
||||
|
||||
return daemon, nil
|
||||
}
|
||||
|
@ -208,7 +208,6 @@ func TestContainerInitDNS(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer volumedrivers.Unregister(volume.DefaultDriverName)
|
||||
|
||||
c, err := daemon.load(containerID)
|
||||
if err != nil {
|
||||
|
|
|
@ -6,18 +6,11 @@ import (
|
|||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/container"
|
||||
"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 {
|
||||
|
@ -273,85 +266,3 @@ func TestNetworkOptions(t *testing.T) {
|
|||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -632,13 +632,6 @@ func setupDaemonProcess(config *config.Config) error {
|
|||
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 {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -35,41 +35,39 @@ func (daemon *Daemon) SystemDiskUsage(ctx context.Context) (*types.DiskUsage, er
|
|||
return nil, fmt.Errorf("failed to retrieve image list: %v", err)
|
||||
}
|
||||
|
||||
// Get all local volumes
|
||||
allVolumes := []*types.Volume{}
|
||||
getLocalVols := func(v volume.Volume) error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
if d, ok := v.(volume.DetailedVolume); ok {
|
||||
// skip local volumes with mount options since these could have external
|
||||
// mounted filesystems that will be slow to enumerate.
|
||||
if len(d.Options()) > 0 {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
err = daemon.traverseLocalVolumes(getLocalVols)
|
||||
volumes, err := daemon.volumes.FilterByDriver(volume.DefaultDriverName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var allVolumes []*types.Volume
|
||||
for _, v := range volumes {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
}
|
||||
if d, ok := v.(volume.DetailedVolume); ok {
|
||||
if len(d.Options()) > 0 {
|
||||
// skip local volumes with mount options since these could have external
|
||||
// mounted filesystems that will be slow to enumerate.
|
||||
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)
|
||||
}
|
||||
|
||||
allLayersSize, err := daemon.imageService.LayerDiskUsage(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -19,7 +19,6 @@ import (
|
|||
"github.com/docker/docker/pkg/sysinfo"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/docker/docker/volume/drivers"
|
||||
"github.com/docker/go-connections/sockets"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
@ -196,7 +195,7 @@ func (daemon *Daemon) SystemVersion() types.Version {
|
|||
func (daemon *Daemon) showPluginsInfo() types.PluginsInfo {
|
||||
var pluginsInfo types.PluginsInfo
|
||||
|
||||
pluginsInfo.Volume = volumedrivers.GetDriverList()
|
||||
pluginsInfo.Volume = daemon.volumes.GetDriverList()
|
||||
pluginsInfo.Network = daemon.GetNetworkDriverList()
|
||||
// The authorization plugins are returned in the order they are
|
||||
// used as they constitute a request/response modification chain.
|
||||
|
|
|
@ -107,11 +107,20 @@ func (daemon *Daemon) VolumesPrune(ctx context.Context, pruneFilters filters.Arg
|
|||
|
||||
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 {
|
||||
case <-ctx.Done():
|
||||
logrus.Debugf("VolumesPrune operation cancelled: %#v", *rep)
|
||||
return ctx.Err()
|
||||
err := ctx.Err()
|
||||
if err == context.Canceled {
|
||||
return rep, nil
|
||||
}
|
||||
return rep, err
|
||||
default:
|
||||
}
|
||||
|
||||
|
@ -122,9 +131,10 @@ func (daemon *Daemon) VolumesPrune(ctx context.Context, pruneFilters filters.Arg
|
|||
detailedVolume, ok := v.(volume.DetailedVolume)
|
||||
if ok {
|
||||
if !matchLabels(pruneFilters, detailedVolume.Labels()) {
|
||||
return nil
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
vSize, err := directory.Size(ctx, v.Path())
|
||||
if err != nil {
|
||||
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)
|
||||
if err != nil {
|
||||
logrus.Warnf("could not remove volume %s: %v", name, err)
|
||||
return nil
|
||||
continue
|
||||
}
|
||||
rep.SpaceReclaimed += uint64(vSize)
|
||||
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
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package daemon // import "github.com/docker/docker/daemon"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
|
@ -15,7 +14,6 @@ import (
|
|||
"github.com/docker/docker/container"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/volume"
|
||||
"github.com/docker/docker/volume/drivers"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
@ -385,32 +383,3 @@ func (daemon *Daemon) backportMountSpec(container *container.Container) {
|
|||
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
|
||||
}
|
||||
|
|
|
@ -3,10 +3,8 @@
|
|||
package daemon // import "github.com/docker/docker/daemon"
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -15,9 +13,6 @@ import (
|
|||
"github.com/docker/docker/pkg/fileutils"
|
||||
"github.com/docker/docker/pkg/mount"
|
||||
"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
|
||||
|
@ -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 {
|
||||
mounts, err := daemon.setupMounts(container)
|
||||
if err != nil {
|
||||
|
|
|
@ -35,7 +35,6 @@ import (
|
|||
testdaemon "github.com/docker/docker/internal/test/daemon"
|
||||
"github.com/docker/docker/opts"
|
||||
"github.com/docker/docker/pkg/mount"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
units "github.com/docker/go-units"
|
||||
"github.com/docker/libnetwork/iptables"
|
||||
"github.com/docker/libtrust"
|
||||
|
@ -2668,84 +2667,6 @@ func (s *DockerDaemonSuite) TestDaemonRestartSaveContainerExitCode(c *check.C) {
|
|||
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) {
|
||||
testRequires(c, SameHostDaemon, DaemonIsLinux)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package volumedrivers // import "github.com/docker/docker/volume/drivers"
|
||||
package drivers // import "github.com/docker/docker/volume/drivers"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
//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 (
|
||||
"fmt"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/pkg/locker"
|
||||
getter "github.com/docker/docker/pkg/plugingetter"
|
||||
"github.com/docker/docker/volume"
|
||||
|
@ -14,14 +15,6 @@ import (
|
|||
"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"
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
// 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,
|
||||
}
|
||||
|
||||
drivers.Lock()
|
||||
defer drivers.Unlock()
|
||||
|
||||
_, exists := drivers.extensions[name]
|
||||
if exists {
|
||||
return false
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -113,18 +74,21 @@ func (driverNotFoundError) NotFound() {}
|
|||
// lookup returns the driver associated with the given name. If a
|
||||
// driver with the given name has not been registered it checks if
|
||||
// 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 {
|
||||
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 {
|
||||
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 mode > 0 {
|
||||
// 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")
|
||||
}
|
||||
}
|
||||
|
@ -141,9 +105,9 @@ func lookup(name string, mode int) (volume.Driver, error) {
|
|||
}
|
||||
|
||||
if p.IsV1() {
|
||||
drivers.Lock()
|
||||
drivers.extensions[name] = d
|
||||
drivers.Unlock()
|
||||
s.mu.Lock()
|
||||
s.extensions[name] = d
|
||||
s.mu.Unlock()
|
||||
}
|
||||
return d, nil
|
||||
}
|
||||
|
@ -158,75 +122,88 @@ func validateDriver(vd volume.Driver) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// 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 == "" {
|
||||
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
|
||||
}
|
||||
|
||||
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 GetDriver(name string) (volume.Driver, error) {
|
||||
if name == "" {
|
||||
name = volume.DefaultDriverName
|
||||
}
|
||||
return lookup(name, getter.Lookup)
|
||||
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.
|
||||
// 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..
|
||||
// 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.
|
||||
// If no driver is registered, empty string list will be returned.
|
||||
func GetDriverList() []string {
|
||||
func (s *Store) GetDriverList() []string {
|
||||
var driverList []string
|
||||
drivers.Lock()
|
||||
for driverName := range drivers.extensions {
|
||||
s.mu.Lock()
|
||||
for driverName := range s.extensions {
|
||||
driverList = append(driverList, driverName)
|
||||
}
|
||||
drivers.Unlock()
|
||||
s.mu.Unlock()
|
||||
sort.Strings(driverList)
|
||||
return driverList
|
||||
}
|
||||
|
||||
// GetAllDrivers lists all the registered drivers
|
||||
func GetAllDrivers() ([]volume.Driver, error) {
|
||||
func (s *Store) GetAllDrivers() ([]volume.Driver, error) {
|
||||
var plugins []getter.CompatPlugin
|
||||
if drivers.plugingetter != nil {
|
||||
if s.pluginGetter != nil {
|
||||
var err error
|
||||
plugins, err = drivers.plugingetter.GetAllByCap(extName)
|
||||
plugins, err = s.pluginGetter.GetAllByCap(extName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error listing plugins: %v", err)
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
for _, p := range plugins {
|
||||
name := p.Name()
|
||||
|
||||
if _, ok := drivers.extensions[name]; ok {
|
||||
if _, ok := s.extensions[name]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
ext := NewVolumeDriver(name, p.ScopedPath, p.Client())
|
||||
if p.IsV1() {
|
||||
drivers.extensions[name] = ext
|
||||
s.extensions[name] = ext
|
||||
}
|
||||
ds = append(ds, ext)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package volumedrivers // import "github.com/docker/docker/volume/drivers"
|
||||
package drivers // import "github.com/docker/docker/volume/drivers"
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
@ -7,13 +7,14 @@ import (
|
|||
)
|
||||
|
||||
func TestGetDriver(t *testing.T) {
|
||||
_, err := GetDriver("missing")
|
||||
s := NewStore(nil)
|
||||
_, err := s.GetDriver("missing")
|
||||
if err == 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 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// generated code - DO NOT EDIT
|
||||
|
||||
package volumedrivers // import "github.com/docker/docker/volume/drivers"
|
||||
package drivers // import "github.com/docker/docker/volume/drivers"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package volumedrivers // import "github.com/docker/docker/volume/drivers"
|
||||
package drivers // import "github.com/docker/docker/volume/drivers"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
|
||||
"github.com/boltdb/bolt"
|
||||
"github.com/docker/docker/volume"
|
||||
"github.com/docker/docker/volume/drivers"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
|
@ -33,7 +32,7 @@ func (s *VolumeStore) restore() {
|
|||
var v volume.Volume
|
||||
var err error
|
||||
if meta.Driver != "" {
|
||||
v, err = lookupVolume(meta.Driver, meta.Name)
|
||||
v, err = lookupVolume(s.drivers, meta.Driver, meta.Name)
|
||||
if err != nil && err != errNoSuchVolume {
|
||||
logrus.WithError(err).WithField("driver", meta.Driver).WithField("volume", meta.Name).Warn("Error restoring volume")
|
||||
return
|
||||
|
@ -59,7 +58,7 @@ func (s *VolumeStore) restore() {
|
|||
}
|
||||
|
||||
// increment driver refcount
|
||||
volumedrivers.CreateDriver(meta.Driver)
|
||||
s.drivers.CreateDriver(meta.Driver)
|
||||
|
||||
// cache the volume
|
||||
s.globalLock.Lock()
|
||||
|
|
|
@ -18,11 +18,11 @@ func TestRestore(t *testing.T) {
|
|||
assert.NilError(t, err)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
drivers := volumedrivers.NewStore(nil)
|
||||
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)
|
||||
defer s.Shutdown()
|
||||
|
||||
|
@ -36,7 +36,7 @@ func TestRestore(t *testing.T) {
|
|||
|
||||
s.Shutdown()
|
||||
|
||||
s, err = New(dir)
|
||||
s, err = New(dir, drivers)
|
||||
assert.NilError(t, err)
|
||||
|
||||
v, err := s.Get("test1")
|
||||
|
|
|
@ -66,13 +66,14 @@ func (v volumeWrapper) CachedPath() string {
|
|||
|
||||
// New initializes a VolumeStore to keep
|
||||
// reference counting of volumes in the system.
|
||||
func New(rootPath string) (*VolumeStore, error) {
|
||||
func New(rootPath string, drivers *drivers.Store) (*VolumeStore, error) {
|
||||
vs := &VolumeStore{
|
||||
locks: &locker.Locker{},
|
||||
names: make(map[string]volume.Volume),
|
||||
refs: make(map[string]map[string]struct{}),
|
||||
labels: make(map[string]map[string]string),
|
||||
options: make(map[string]map[string]string),
|
||||
drivers: drivers,
|
||||
}
|
||||
|
||||
if rootPath != "" {
|
||||
|
@ -157,7 +158,7 @@ func (s *VolumeStore) Purge(name string) {
|
|||
v, exists := s.names[name]
|
||||
if exists {
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
@ -175,7 +176,8 @@ func (s *VolumeStore) Purge(name string) {
|
|||
type VolumeStore struct {
|
||||
// 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.
|
||||
locks *locker.Locker
|
||||
locks *locker.Locker
|
||||
drivers *drivers.Store
|
||||
// globalLock is used to protect access to mutable structures used by the store object
|
||||
globalLock sync.RWMutex
|
||||
// names stores the volume name -> volume relationship.
|
||||
|
@ -226,7 +228,7 @@ func (s *VolumeStore) list() ([]volume.Volume, []string, error) {
|
|||
warnings []string
|
||||
)
|
||||
|
||||
drivers, err := volumedrivers.GetAllDrivers()
|
||||
drivers, err := s.drivers.GetAllDrivers()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
@ -329,7 +331,7 @@ func (s *VolumeStore) checkConflict(name, driverName string) (volume.Volume, err
|
|||
if driverName != "" {
|
||||
// Retrieve canonical driver name to avoid inconsistencies (for example
|
||||
// "plugin" vs. "plugin:latest")
|
||||
vd, err := volumedrivers.GetDriver(driverName)
|
||||
vd, err := s.drivers.GetDriver(driverName)
|
||||
if err != nil {
|
||||
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
|
||||
// is stale by checking with the driver if it still exists
|
||||
exists, err := volumeExists(v)
|
||||
exists, err := volumeExists(s.drivers, v)
|
||||
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)
|
||||
}
|
||||
|
@ -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.
|
||||
// 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 {
|
||||
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 {
|
||||
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 {
|
||||
v, err = vd.Create(name, opts)
|
||||
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")
|
||||
}
|
||||
return nil, err
|
||||
|
@ -455,7 +460,10 @@ func (s *VolumeStore) GetWithRef(name, driverName, ref string) (volume.Volume, e
|
|||
s.locks.Lock(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 {
|
||||
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 != "" {
|
||||
vol, err := lookupVolume(meta.Driver, name)
|
||||
vol, err := lookupVolume(s.drivers, meta.Driver, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -520,7 +528,7 @@ func (s *VolumeStore) getVolume(name string) (volume.Volume, error) {
|
|||
}
|
||||
|
||||
var scope string
|
||||
vd, err := volumedrivers.GetDriver(meta.Driver)
|
||||
vd, err := s.drivers.GetDriver(meta.Driver)
|
||||
if err == nil {
|
||||
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)
|
||||
drivers, err := volumedrivers.GetAllDrivers()
|
||||
drivers, err := s.drivers.GetAllDrivers()
|
||||
if err != nil {
|
||||
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
|
||||
// error is logged but not returned.
|
||||
// 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 {
|
||||
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)}
|
||||
}
|
||||
|
||||
vd, err := volumedrivers.GetDriver(v.DriverName())
|
||||
vd, err := s.drivers.GetDriver(v.DriverName())
|
||||
if err != nil {
|
||||
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
|
||||
func (s *VolumeStore) FilterByDriver(name string) ([]volume.Volume, error) {
|
||||
vd, err := volumedrivers.GetDriver(name)
|
||||
vd, err := s.drivers.GetDriver(name)
|
||||
if err != nil {
|
||||
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 {
|
||||
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()
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"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"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/gotestyourself/gotestyourself/assert"
|
||||
|
@ -18,18 +18,12 @@ import (
|
|||
)
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -53,19 +47,13 @@ func TestCreate(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
|
||||
expected := "no such volume"
|
||||
|
@ -91,20 +79,19 @@ func TestRemove(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")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.NilError(t, err)
|
||||
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 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -124,7 +111,7 @@ func TestList(t *testing.T) {
|
|||
}
|
||||
|
||||
// and again with a new store
|
||||
s, err = New(dir)
|
||||
s, err = New(dir, drivers)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -138,18 +125,12 @@ func TestList(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 {
|
||||
t.Fatal(err)
|
||||
|
@ -171,17 +152,12 @@ func TestFilterByDriver(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 {
|
||||
t.Fatal(err)
|
||||
|
@ -213,16 +189,10 @@ func TestFilterByUsed(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)
|
||||
if err != nil {
|
||||
|
@ -240,17 +210,12 @@ func TestDerefMultipleOfSameRef(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestCreateKeepOptsLabelsWhenExistsRemotely(t *testing.T) {
|
||||
t.Parallel()
|
||||
s, cleanup := setupTest(t)
|
||||
defer cleanup()
|
||||
|
||||
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
|
||||
if _, err := vd.Create("foo", nil); err != nil {
|
||||
|
@ -273,6 +238,8 @@ func TestCreateKeepOptsLabelsWhenExistsRemotely(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestDefererencePluginOnCreateError(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var (
|
||||
l net.Listener
|
||||
err error
|
||||
|
@ -286,6 +253,9 @@ func TestDefererencePluginOnCreateError(t *testing.T) {
|
|||
}
|
||||
defer l.Close()
|
||||
|
||||
s, cleanup := setupTest(t)
|
||||
defer cleanup()
|
||||
|
||||
d := volumetestutils.NewFakeDriver("TestDefererencePluginOnCreateError")
|
||||
p, err := volumetestutils.MakeFakePlugin(d, l)
|
||||
if err != nil {
|
||||
|
@ -293,19 +263,7 @@ func TestDefererencePluginOnCreateError(t *testing.T) {
|
|||
}
|
||||
|
||||
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
|
||||
_, err = s.Create("fake1", d.Name(), nil, nil)
|
||||
|
@ -329,8 +287,9 @@ func TestRefDerefRemove(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
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)
|
||||
assert.NilError(t, err)
|
||||
|
@ -348,8 +307,9 @@ func TestGet(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
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")
|
||||
assert.Assert(t, is.ErrorContains(err, ""))
|
||||
|
@ -373,8 +333,9 @@ func TestGetWithRef(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
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")
|
||||
assert.Assert(t, is.ErrorContains(err, ""))
|
||||
|
@ -397,32 +358,22 @@ func TestGetWithRef(t *testing.T) {
|
|||
|
||||
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()
|
||||
|
||||
dir, err := ioutil.TempDir("", "store-root")
|
||||
dirName := strings.Replace(t.Name(), string(os.PathSeparator), "_", -1)
|
||||
dir, err := ioutil.TempDir("", dirName)
|
||||
assert.NilError(t, err)
|
||||
|
||||
cleanup := func(t *testing.T) {
|
||||
cleanup := func() {
|
||||
err := os.RemoveAll(dir)
|
||||
assert.Check(t, err)
|
||||
}
|
||||
|
||||
s, err := New(dir)
|
||||
s, err := New(dir, volumedrivers.NewStore(nil))
|
||||
assert.Check(t, err)
|
||||
return s, func(t *testing.T) {
|
||||
return s, func() {
|
||||
s.Shutdown()
|
||||
cleanup(t)
|
||||
cleanup()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue