|
@@ -1,257 +1,26 @@
|
|
|
-// +build experimental
|
|
|
+// +build !experimental
|
|
|
|
|
|
package store
|
|
|
|
|
|
import (
|
|
|
- "encoding/json"
|
|
|
- "fmt"
|
|
|
- "path/filepath"
|
|
|
- "strings"
|
|
|
- "sync"
|
|
|
-
|
|
|
- "github.com/Sirupsen/logrus"
|
|
|
- "github.com/docker/docker/pkg/ioutils"
|
|
|
"github.com/docker/docker/pkg/plugins"
|
|
|
- "github.com/docker/docker/plugin/v2"
|
|
|
- "github.com/docker/docker/reference"
|
|
|
-)
|
|
|
-
|
|
|
-var (
|
|
|
- store *PluginStore
|
|
|
- /* allowV1PluginsFallback determines daemon's support for V1 plugins.
|
|
|
- * When the time comes to remove support for V1 plugins, flipping
|
|
|
- * this bool is all that will be needed.
|
|
|
- */
|
|
|
- allowV1PluginsFallback = true
|
|
|
+ "github.com/docker/docker/plugin/getter"
|
|
|
)
|
|
|
|
|
|
-// ErrNotFound indicates that a plugin was not found locally.
|
|
|
-type ErrNotFound string
|
|
|
-
|
|
|
-func (name ErrNotFound) Error() string { return fmt.Sprintf("plugin %q not found", string(name)) }
|
|
|
-
|
|
|
-// PluginStore manages the plugin inventory in memory and on-disk
|
|
|
-type PluginStore struct {
|
|
|
- sync.RWMutex
|
|
|
- plugins map[string]*v2.Plugin
|
|
|
- /* handlers are necessary for transition path of legacy plugins
|
|
|
- * to the new model. Legacy plugins use Handle() for registering an
|
|
|
- * activation callback.*/
|
|
|
- handlers map[string]func(string, *plugins.Client)
|
|
|
- nameToID map[string]string
|
|
|
- plugindb string
|
|
|
-}
|
|
|
-
|
|
|
-// NewPluginStore creates a PluginStore.
|
|
|
-func NewPluginStore(libRoot string) *PluginStore {
|
|
|
- store = &PluginStore{
|
|
|
- plugins: make(map[string]*v2.Plugin),
|
|
|
- handlers: make(map[string]func(string, *plugins.Client)),
|
|
|
- nameToID: make(map[string]string),
|
|
|
- plugindb: filepath.Join(libRoot, "plugins.json"),
|
|
|
- }
|
|
|
- return store
|
|
|
-}
|
|
|
-
|
|
|
-// GetByName retreives a plugin by name.
|
|
|
-func (ps *PluginStore) GetByName(name string) (*v2.Plugin, error) {
|
|
|
- ps.RLock()
|
|
|
- defer ps.RUnlock()
|
|
|
-
|
|
|
- id, nameOk := ps.nameToID[name]
|
|
|
- if !nameOk {
|
|
|
- return nil, ErrNotFound(name)
|
|
|
- }
|
|
|
-
|
|
|
- p, idOk := ps.plugins[id]
|
|
|
- if !idOk {
|
|
|
- return nil, ErrNotFound(id)
|
|
|
- }
|
|
|
- return p, nil
|
|
|
-}
|
|
|
-
|
|
|
-// GetByID retreives a plugin by ID.
|
|
|
-func (ps *PluginStore) GetByID(id string) (*v2.Plugin, error) {
|
|
|
- ps.RLock()
|
|
|
- defer ps.RUnlock()
|
|
|
-
|
|
|
- p, idOk := ps.plugins[id]
|
|
|
- if !idOk {
|
|
|
- return nil, ErrNotFound(id)
|
|
|
- }
|
|
|
- return p, nil
|
|
|
-}
|
|
|
-
|
|
|
-// GetAll retreives all plugins.
|
|
|
-func (ps *PluginStore) GetAll() map[string]*v2.Plugin {
|
|
|
- ps.RLock()
|
|
|
- defer ps.RUnlock()
|
|
|
- return ps.plugins
|
|
|
-}
|
|
|
-
|
|
|
-// SetAll initialized plugins during daemon restore.
|
|
|
-func (ps *PluginStore) SetAll(plugins map[string]*v2.Plugin) {
|
|
|
- ps.Lock()
|
|
|
- defer ps.Unlock()
|
|
|
- ps.plugins = plugins
|
|
|
-}
|
|
|
-
|
|
|
-func (ps *PluginStore) getByCap(name string, capability string) (*v2.Plugin, error) {
|
|
|
- ps.RLock()
|
|
|
- defer ps.RUnlock()
|
|
|
-
|
|
|
- p, err := ps.GetByName(name)
|
|
|
+// GetAllByCap returns a list of plugins matching the given capability.
|
|
|
+func (ps Store) GetAllByCap(capability string) ([]getter.CompatPlugin, error) {
|
|
|
+ pl, err := plugins.GetAll(capability)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
- return p.FilterByCap(capability)
|
|
|
-}
|
|
|
-
|
|
|
-func (ps *PluginStore) getAllByCap(capability string) []CompatPlugin {
|
|
|
- ps.RLock()
|
|
|
- defer ps.RUnlock()
|
|
|
-
|
|
|
- result := make([]CompatPlugin, 0, 1)
|
|
|
- for _, p := range ps.plugins {
|
|
|
- if _, err := p.FilterByCap(capability); err == nil {
|
|
|
- result = append(result, p)
|
|
|
- }
|
|
|
- }
|
|
|
- return result
|
|
|
-}
|
|
|
-
|
|
|
-// SetState sets the active state of the plugin and updates plugindb.
|
|
|
-func (ps *PluginStore) SetState(p *v2.Plugin, state bool) {
|
|
|
- ps.Lock()
|
|
|
- defer ps.Unlock()
|
|
|
-
|
|
|
- p.PluginObj.Enabled = state
|
|
|
- ps.updatePluginDB()
|
|
|
-}
|
|
|
-
|
|
|
-// Add adds a plugin to memory and plugindb.
|
|
|
-func (ps *PluginStore) Add(p *v2.Plugin) {
|
|
|
- ps.Lock()
|
|
|
- ps.plugins[p.GetID()] = p
|
|
|
- ps.nameToID[p.Name()] = p.GetID()
|
|
|
- ps.updatePluginDB()
|
|
|
- ps.Unlock()
|
|
|
-}
|
|
|
-
|
|
|
-// Remove removes a plugin from memory, plugindb and disk.
|
|
|
-func (ps *PluginStore) Remove(p *v2.Plugin) {
|
|
|
- ps.Lock()
|
|
|
- delete(ps.plugins, p.GetID())
|
|
|
- delete(ps.nameToID, p.Name())
|
|
|
- ps.updatePluginDB()
|
|
|
- p.RemoveFromDisk()
|
|
|
- ps.Unlock()
|
|
|
-}
|
|
|
-
|
|
|
-// Callers are expected to hold the store lock.
|
|
|
-func (ps *PluginStore) updatePluginDB() error {
|
|
|
- jsonData, err := json.Marshal(ps.plugins)
|
|
|
- if err != nil {
|
|
|
- logrus.Debugf("Error in json.Marshal: %v", err)
|
|
|
- return err
|
|
|
- }
|
|
|
- ioutils.AtomicWriteFile(ps.plugindb, jsonData, 0600)
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-// LookupWithCapability returns a plugin matching the given name and capability.
|
|
|
-func LookupWithCapability(name, capability string, mode int) (CompatPlugin, error) {
|
|
|
- var (
|
|
|
- p *v2.Plugin
|
|
|
- err error
|
|
|
- )
|
|
|
-
|
|
|
- // Lookup using new model.
|
|
|
- if store != nil {
|
|
|
- fullName := name
|
|
|
- if named, err := reference.ParseNamed(fullName); err == nil { // FIXME: validate
|
|
|
- if reference.IsNameOnly(named) {
|
|
|
- named = reference.WithDefaultTag(named)
|
|
|
- }
|
|
|
- ref, ok := named.(reference.NamedTagged)
|
|
|
- if !ok {
|
|
|
- return nil, fmt.Errorf("invalid name: %s", named.String())
|
|
|
- }
|
|
|
- fullName = ref.String()
|
|
|
- }
|
|
|
- p, err = store.GetByName(fullName)
|
|
|
- if err == nil {
|
|
|
- p.Lock()
|
|
|
- p.RefCount += mode
|
|
|
- p.Unlock()
|
|
|
- return p.FilterByCap(capability)
|
|
|
- }
|
|
|
- if _, ok := err.(ErrNotFound); !ok {
|
|
|
- return nil, err
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Lookup using legacy model.
|
|
|
- if allowV1PluginsFallback {
|
|
|
- p, err := plugins.Get(name, capability)
|
|
|
- if err != nil {
|
|
|
- return nil, fmt.Errorf("legacy plugin: %v", err)
|
|
|
- }
|
|
|
- return p, nil
|
|
|
- }
|
|
|
-
|
|
|
- return nil, err
|
|
|
-}
|
|
|
-
|
|
|
-// FindWithCapability returns a list of plugins matching the given capability.
|
|
|
-func FindWithCapability(capability string) ([]CompatPlugin, error) {
|
|
|
- result := make([]CompatPlugin, 0, 1)
|
|
|
-
|
|
|
- /* Daemon start always calls plugin.Init thereby initializing a store.
|
|
|
- * So store on experimental builds can never be nil, even while
|
|
|
- * handling legacy plugins. However, there are legacy plugin unit
|
|
|
- * tests where the volume subsystem directly talks with the plugin,
|
|
|
- * bypassing the daemon. For such tests, this check is necessary.
|
|
|
- */
|
|
|
- if store != nil {
|
|
|
- store.RLock()
|
|
|
- result = store.getAllByCap(capability)
|
|
|
- store.RUnlock()
|
|
|
- }
|
|
|
-
|
|
|
- // Lookup with legacy model
|
|
|
- if allowV1PluginsFallback {
|
|
|
- pl, err := plugins.GetAll(capability)
|
|
|
- if err != nil {
|
|
|
- return nil, fmt.Errorf("legacy plugin: %v", err)
|
|
|
- }
|
|
|
- for _, p := range pl {
|
|
|
- result = append(result, p)
|
|
|
- }
|
|
|
+ result := make([]getter.CompatPlugin, len(pl))
|
|
|
+ for i, p := range pl {
|
|
|
+ result[i] = p
|
|
|
}
|
|
|
return result, nil
|
|
|
}
|
|
|
|
|
|
-// Handle sets a callback for a given capability. It is only used by network
|
|
|
-// and ipam drivers during plugin registration. The callback registers the
|
|
|
-// driver with the subsystem (network, ipam).
|
|
|
-func Handle(capability string, callback func(string, *plugins.Client)) {
|
|
|
- pluginType := fmt.Sprintf("docker.%s/1", strings.ToLower(capability))
|
|
|
-
|
|
|
- // Register callback with new plugin model.
|
|
|
- store.handlers[pluginType] = callback
|
|
|
-
|
|
|
- // Register callback with legacy plugin model.
|
|
|
- if allowV1PluginsFallback {
|
|
|
- plugins.Handle(capability, callback)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// CallHandler calls the registered callback. It is invoked during plugin enable.
|
|
|
-func (ps *PluginStore) CallHandler(p *v2.Plugin) {
|
|
|
- for _, typ := range p.GetTypes() {
|
|
|
- if handler := ps.handlers[typ.String()]; handler != nil {
|
|
|
- handler(p.Name(), p.Client())
|
|
|
- }
|
|
|
- }
|
|
|
+// Get returns a plugin matching the given name and capability.
|
|
|
+func (ps Store) Get(name, capability string, _ int) (getter.CompatPlugin, error) {
|
|
|
+ return plugins.Get(name, capability)
|
|
|
}
|