From 390876ba18d89e152ba79823c00d9defc3011c59 Mon Sep 17 00:00:00 2001 From: Brian Goff Date: Wed, 23 Sep 2015 16:29:14 -0400 Subject: [PATCH] Move responsibility of ls/inspect to volume driver Makes `docker volume ls` and `docker volume inspect` ask the volume drivers rather than only using what is cached locally. Previously in order to use a volume from an external driver, one would either have to use `docker volume create` or have a container that is already using that volume for it to be visible to the other volume API's. For keeping uniqueness of volume names in the daemon, names are bound to a driver on a first come first serve basis. If two drivers have a volume with the same name, the first one is chosen, and a warning is logged about the second one. Adds 2 new methods to the plugin API, `List` and `Get`. If a plugin does not implement these endpoints, a user will not be able to find the specified volumes as well requests go through the drivers. Signed-off-by: Brian Goff --- plugins/discovery.go | 32 +++++++++++++++++++++++++++ plugins/plugins.go | 51 +++++++++++++++++++++++++++++++++++++++----- 2 files changed, 78 insertions(+), 5 deletions(-) diff --git a/plugins/discovery.go b/plugins/discovery.go index 5ea8db5..3f79661 100644 --- a/plugins/discovery.go +++ b/plugins/discovery.go @@ -25,6 +25,38 @@ func newLocalRegistry() localRegistry { return localRegistry{} } +// Scan scans all the plugin paths and returns all the names it found +func Scan() ([]string, error) { + var names []string + if err := filepath.Walk(socketsPath, func(path string, fi os.FileInfo, err error) error { + if err != nil { + return nil + } + + if fi.Mode()&os.ModeSocket != 0 { + name := strings.TrimSuffix(fi.Name(), filepath.Ext(fi.Name())) + names = append(names, name) + } + return nil + }); err != nil { + return nil, err + } + + for _, path := range specsPaths { + if err := filepath.Walk(path, func(p string, fi os.FileInfo, err error) error { + if err != nil || fi.IsDir() { + return nil + } + name := strings.TrimSuffix(fi.Name(), filepath.Ext(fi.Name())) + names = append(names, name) + return nil + }); err != nil { + return nil, err + } + } + return names, nil +} + // Plugin returns the plugin registered with the given name (or returns an error). func (l *localRegistry) Plugin(name string) (*Plugin, error) { socketpaths := pluginPaths(socketsPath, name, ".sock") diff --git a/plugins/plugins.go b/plugins/plugins.go index 6317e4f..7157107 100644 --- a/plugins/plugins.go +++ b/plugins/plugins.go @@ -108,6 +108,15 @@ func (p *Plugin) activateWithLock() error { return nil } +func (p *Plugin) implements(kind string) bool { + for _, driver := range p.Manifest.Implements { + if driver == kind { + return true + } + } + return false +} + func load(name string) (*Plugin, error) { return loadWithRetry(name, true) } @@ -166,11 +175,9 @@ func Get(name, imp string) (*Plugin, error) { if err != nil { return nil, err } - for _, driver := range pl.Manifest.Implements { - logrus.Debugf("%s implements: %s", name, driver) - if driver == imp { - return pl, nil - } + if pl.implements(imp) { + logrus.Debugf("%s implements: %s", name, imp) + return pl, nil } return nil, ErrNotImplements } @@ -179,3 +186,37 @@ func Get(name, imp string) (*Plugin, error) { func Handle(iface string, fn func(string, *Client)) { extpointHandlers[iface] = fn } + +// GetAll returns all the plugins for the specified implementation +func GetAll(imp string) ([]*Plugin, error) { + pluginNames, err := Scan() + if err != nil { + return nil, err + } + + type plLoad struct { + pl *Plugin + err error + } + + chPl := make(chan plLoad, len(pluginNames)) + for _, name := range pluginNames { + go func(name string) { + pl, err := loadWithRetry(name, false) + chPl <- plLoad{pl, err} + }(name) + } + + var out []*Plugin + for i := 0; i < len(pluginNames); i++ { + pl := <-chPl + if pl.err != nil { + logrus.Error(err) + continue + } + if pl.pl.implements(imp) { + out = append(out, pl.pl) + } + } + return out, nil +}