Browse code

Merge pull request #26645 from anusha-ragunathan/use-pluginv2-graph

Make graphdrivers work with pluginv2.

Anusha Ragunathan authored on 2016/09/21 02:59:33
Showing 24 changed files
... ...
@@ -1,5 +1,3 @@
1
-// +build experimental
2
-
3 1
 package types
4 2
 
5 3
 import (
6 4
old mode 100755
7 5
new mode 100644
... ...
@@ -47,6 +47,7 @@ import (
47 47
 	"github.com/docker/docker/pkg/sysinfo"
48 48
 	"github.com/docker/docker/pkg/system"
49 49
 	"github.com/docker/docker/pkg/truncindex"
50
+	pluginstore "github.com/docker/docker/plugin/store"
50 51
 	"github.com/docker/docker/reference"
51 52
 	"github.com/docker/docker/registry"
52 53
 	"github.com/docker/docker/runconfig"
... ...
@@ -94,6 +95,7 @@ type Daemon struct {
94 94
 	gidMaps                   []idtools.IDMap
95 95
 	layerStore                layer.Store
96 96
 	imageStore                image.Store
97
+	pluginStore               *pluginstore.Store
97 98
 	nameIndex                 *registrar.Registrar
98 99
 	linkIndex                 *linkIndex
99 100
 	containerd                libcontainerd.Client
... ...
@@ -548,6 +550,9 @@ func NewDaemon(config *Config, registryService registry.Service, containerdRemot
548 548
 	if driverName == "" {
549 549
 		driverName = config.GraphDriver
550 550
 	}
551
+
552
+	d.pluginStore = pluginstore.NewStore(config.Root)
553
+
551 554
 	d.layerStore, err = layer.NewStoreFromOptions(layer.StoreOptions{
552 555
 		StorePath:                 config.Root,
553 556
 		MetadataStorePathTemplate: filepath.Join(config.Root, "image", "%s", "layerdb"),
... ...
@@ -555,6 +560,7 @@ func NewDaemon(config *Config, registryService registry.Service, containerdRemot
555 555
 		GraphDriverOptions:        config.GraphOptions,
556 556
 		UIDMaps:                   uidMaps,
557 557
 		GIDMaps:                   gidMaps,
558
+		PluginGetter:              d.pluginStore,
558 559
 	})
559 560
 	if err != nil {
560 561
 		return nil, err
... ...
@@ -911,6 +917,8 @@ func (daemon *Daemon) configureVolumes(rootUID, rootGID int) (*store.VolumeStore
911 911
 		return nil, err
912 912
 	}
913 913
 
914
+	volumedrivers.RegisterPluginGetter(daemon.pluginStore)
915
+
914 916
 	if !volumedrivers.Register(volumesDriver, volumesDriver.Name()) {
915 917
 		return nil, fmt.Errorf("local volume driver could not be registered")
916 918
 	}
... ...
@@ -13,7 +13,7 @@ func (daemon *Daemon) verifyExperimentalContainerSettings(hostConfig *container.
13 13
 }
14 14
 
15 15
 func pluginInit(d *Daemon, cfg *Config, remote libcontainerd.Remote) error {
16
-	return plugin.Init(cfg.Root, remote, d.RegistryService, cfg.LiveRestoreEnabled, d.LogPluginEvent)
16
+	return plugin.Init(cfg.Root, d.pluginStore, remote, d.RegistryService, cfg.LiveRestoreEnabled, d.LogPluginEvent)
17 17
 }
18 18
 
19 19
 func pluginShutdown() {
... ...
@@ -12,6 +12,7 @@ import (
12 12
 
13 13
 	"github.com/docker/docker/pkg/archive"
14 14
 	"github.com/docker/docker/pkg/idtools"
15
+	"github.com/docker/docker/plugin/getter"
15 16
 )
16 17
 
17 18
 // FsMagic unsigned id of the filesystem in use.
... ...
@@ -134,11 +135,11 @@ func Register(name string, initFunc InitFunc) error {
134 134
 }
135 135
 
136 136
 // GetDriver initializes and returns the registered driver
137
-func GetDriver(name, home string, options []string, uidMaps, gidMaps []idtools.IDMap) (Driver, error) {
137
+func GetDriver(name, home string, options []string, uidMaps, gidMaps []idtools.IDMap, plugingetter getter.PluginGetter) (Driver, error) {
138 138
 	if initFunc, exists := drivers[name]; exists {
139 139
 		return initFunc(filepath.Join(home, name), options, uidMaps, gidMaps)
140 140
 	}
141
-	if pluginDriver, err := lookupPlugin(name, home, options); err == nil {
141
+	if pluginDriver, err := lookupPlugin(name, home, options, plugingetter); err == nil {
142 142
 		return pluginDriver, nil
143 143
 	}
144 144
 	logrus.Errorf("Failed to GetDriver graph %s %s", name, home)
... ...
@@ -155,10 +156,10 @@ func getBuiltinDriver(name, home string, options []string, uidMaps, gidMaps []id
155 155
 }
156 156
 
157 157
 // New creates the driver and initializes it at the specified root.
158
-func New(root string, name string, options []string, uidMaps, gidMaps []idtools.IDMap) (Driver, error) {
158
+func New(root string, name string, options []string, uidMaps, gidMaps []idtools.IDMap, plugingetter getter.PluginGetter) (Driver, error) {
159 159
 	if name != "" {
160 160
 		logrus.Debugf("[graphdriver] trying provided driver: %s", name) // so the logs show specified driver
161
-		return GetDriver(name, root, options, uidMaps, gidMaps)
161
+		return GetDriver(name, root, options, uidMaps, gidMaps, plugingetter)
162 162
 	}
163 163
 
164 164
 	// Guess for prior driver
... ...
@@ -41,7 +41,7 @@ func newDriver(t testing.TB, name string, options []string) *Driver {
41 41
 		t.Fatal(err)
42 42
 	}
43 43
 
44
-	d, err := graphdriver.GetDriver(name, root, options, nil, nil)
44
+	d, err := graphdriver.GetDriver(name, root, options, nil, nil, nil)
45 45
 	if err != nil {
46 46
 		t.Logf("graphdriver: %v\n", err)
47 47
 		if err == graphdriver.ErrNotSupported || err == graphdriver.ErrPrerequisites || err == graphdriver.ErrIncompatibleFS {
... ...
@@ -6,7 +6,7 @@ import (
6 6
 	"fmt"
7 7
 	"io"
8 8
 
9
-	"github.com/docker/docker/pkg/plugins"
9
+	"github.com/docker/docker/plugin/getter"
10 10
 )
11 11
 
12 12
 type pluginClient interface {
... ...
@@ -18,8 +18,8 @@ type pluginClient interface {
18 18
 	SendFile(string, io.Reader, interface{}) error
19 19
 }
20 20
 
21
-func lookupPlugin(name, home string, opts []string) (Driver, error) {
22
-	pl, err := plugins.Get(name, "GraphDriver")
21
+func lookupPlugin(name, home string, opts []string, pluginGetter getter.PluginGetter) (Driver, error) {
22
+	pl, err := pluginGetter.Get(name, "GraphDriver", getter.LOOKUP)
23 23
 	if err != nil {
24 24
 		return nil, fmt.Errorf("Error looking up graphdriver plugin %s: %v", name, err)
25 25
 	}
... ...
@@ -2,6 +2,8 @@
2 2
 
3 3
 package graphdriver
4 4
 
5
-func lookupPlugin(name, home string, opts []string) (Driver, error) {
5
+import "github.com/docker/docker/plugin/getter"
6
+
7
+func lookupPlugin(name, home string, opts []string, plugingetter getter.PluginGetter) (Driver, error) {
6 8
 	return nil, ErrNotSupported
7 9
 }
... ...
@@ -14,6 +14,7 @@ import (
14 14
 	"github.com/docker/docker/pkg/archive"
15 15
 	"github.com/docker/docker/pkg/idtools"
16 16
 	"github.com/docker/docker/pkg/stringid"
17
+	"github.com/docker/docker/plugin/getter"
17 18
 	"github.com/vbatts/tar-split/tar/asm"
18 19
 	"github.com/vbatts/tar-split/tar/storage"
19 20
 )
... ...
@@ -44,6 +45,7 @@ type StoreOptions struct {
44 44
 	GraphDriverOptions        []string
45 45
 	UIDMaps                   []idtools.IDMap
46 46
 	GIDMaps                   []idtools.IDMap
47
+	PluginGetter              getter.PluginGetter
47 48
 }
48 49
 
49 50
 // NewStoreFromOptions creates a new Store instance
... ...
@@ -53,7 +55,8 @@ func NewStoreFromOptions(options StoreOptions) (Store, error) {
53 53
 		options.GraphDriver,
54 54
 		options.GraphDriverOptions,
55 55
 		options.UIDMaps,
56
-		options.GIDMaps)
56
+		options.GIDMaps,
57
+		options.PluginGetter)
57 58
 	if err != nil {
58 59
 		return nil, fmt.Errorf("error initializing graphdriver: %v", err)
59 60
 	}
... ...
@@ -39,7 +39,7 @@ func newVFSGraphDriver(td string) (graphdriver.Driver, error) {
39 39
 		},
40 40
 	}
41 41
 
42
-	return graphdriver.GetDriver("vfs", td, nil, uidMap, gidMap)
42
+	return graphdriver.GetDriver("vfs", td, nil, uidMap, gidMap, nil)
43 43
 }
44 44
 
45 45
 func newTestGraphDriver(t *testing.T) (graphdriver.Driver, func()) {
... ...
@@ -83,8 +83,8 @@ func (p *Plugin) Client() *Client {
83 83
 	return p.client
84 84
 }
85 85
 
86
-// IsLegacy returns true for legacy plugins and false otherwise.
87
-func (p *Plugin) IsLegacy() bool {
86
+// IsV1 returns true for V1 plugins and false otherwise.
87
+func (p *Plugin) IsV1() bool {
88 88
 	return true
89 89
 }
90 90
 
... ...
@@ -17,7 +17,6 @@ import (
17 17
 	"github.com/docker/docker/pkg/stringid"
18 18
 	"github.com/docker/docker/plugin/distribution"
19 19
 	"github.com/docker/docker/plugin/v2"
20
-	"github.com/docker/docker/reference"
21 20
 )
22 21
 
23 22
 // Disable deactivates a plugin, which implies that they cannot be used by containers.
... ...
@@ -57,9 +56,9 @@ func (pm *Manager) Inspect(name string) (tp types.Plugin, err error) {
57 57
 
58 58
 // Pull pulls a plugin and computes the privileges required to install it.
59 59
 func (pm *Manager) Pull(name string, metaHeader http.Header, authConfig *types.AuthConfig) (types.PluginPrivileges, error) {
60
-	ref, err := reference.ParseNamed(name)
60
+	ref, err := distribution.GetRef(name)
61 61
 	if err != nil {
62
-		logrus.Debugf("error in reference.ParseNamed: %v", err)
62
+		logrus.Debugf("error in distribution.GetRef: %v", err)
63 63
 		return nil, err
64 64
 	}
65 65
 	name = ref.String()
... ...
@@ -76,7 +75,7 @@ func (pm *Manager) Pull(name string, metaHeader http.Header, authConfig *types.A
76 76
 		return nil, err
77 77
 	}
78 78
 
79
-	pd, err := distribution.Pull(name, pm.registryService, metaHeader, authConfig)
79
+	pd, err := distribution.Pull(ref, pm.registryService, metaHeader, authConfig)
80 80
 	if err != nil {
81 81
 		logrus.Debugf("error in distribution.Pull(): %v", err)
82 82
 		return nil, err
... ...
@@ -87,10 +86,7 @@ func (pm *Manager) Pull(name string, metaHeader http.Header, authConfig *types.A
87 87
 		return nil, err
88 88
 	}
89 89
 
90
-	var tag string
91
-	if ref, ok := ref.(reference.NamedTagged); ok {
92
-		tag = ref.Tag()
93
-	}
90
+	tag := distribution.GetTag(ref)
94 91
 	p := v2.NewPlugin(ref.Name(), pluginID, pm.runRoot, tag)
95 92
 	if err := p.InitPlugin(pm.libRoot); err != nil {
96 93
 		return nil, err
... ...
@@ -62,14 +62,26 @@ func (pd *pullData) Layer() (io.ReadCloser, error) {
62 62
 	return rsc, nil
63 63
 }
64 64
 
65
-// Pull downloads the plugin from Store
66
-func Pull(name string, rs registry.Service, metaheader http.Header, authConfig *types.AuthConfig) (PullData, error) {
65
+// GetRef returns the distribution reference for a given name.
66
+func GetRef(name string) (reference.Named, error) {
67 67
 	ref, err := reference.ParseNamed(name)
68 68
 	if err != nil {
69
-		logrus.Debugf("pull.go: error in ParseNamed: %v", err)
70 69
 		return nil, err
71 70
 	}
71
+	return ref, nil
72
+}
72 73
 
74
+// GetTag returns the tag associated with the given reference name.
75
+func GetTag(ref reference.Named) string {
76
+	tag := DefaultTag
77
+	if ref, ok := ref.(reference.NamedTagged); ok {
78
+		tag = ref.Tag()
79
+	}
80
+	return tag
81
+}
82
+
83
+// Pull downloads the plugin from Store
84
+func Pull(ref reference.Named, rs registry.Service, metaheader http.Header, authConfig *types.AuthConfig) (PullData, error) {
73 85
 	repoInfo, err := rs.ResolveRepository(ref)
74 86
 	if err != nil {
75 87
 		logrus.Debugf("pull.go: error in ResolveRepository: %v", err)
76 88
new file mode 100644
... ...
@@ -0,0 +1,25 @@
0
+package getter
1
+
2
+import "github.com/docker/docker/pkg/plugins"
3
+
4
+const (
5
+	// LOOKUP doesn't update RefCount
6
+	LOOKUP = 0
7
+	// CREATE increments RefCount
8
+	CREATE = 1
9
+	// REMOVE decrements RefCount
10
+	REMOVE = -1
11
+)
12
+
13
+// CompatPlugin is a abstraction to handle both v2(new) and v1(legacy) plugins.
14
+type CompatPlugin interface {
15
+	Client() *plugins.Client
16
+	Name() string
17
+	IsV1() bool
18
+}
19
+
20
+// PluginGetter is the interface implemented by Store
21
+type PluginGetter interface {
22
+	Get(name, capability string, mode int) (CompatPlugin, error)
23
+	GetAllByCap(capability string) ([]CompatPlugin, error)
24
+}
... ...
@@ -35,7 +35,7 @@ type Manager struct {
35 35
 	sync.RWMutex
36 36
 	libRoot           string
37 37
 	runRoot           string
38
-	pluginStore       *store.PluginStore
38
+	pluginStore       *store.Store
39 39
 	containerdClient  libcontainerd.Client
40 40
 	registryService   registry.Service
41 41
 	liveRestore       bool
... ...
@@ -50,7 +50,7 @@ func GetManager() *Manager {
50 50
 
51 51
 // Init (was NewManager) instantiates the singleton Manager.
52 52
 // TODO: revert this to NewManager once we get rid of all the singletons.
53
-func Init(root string, remote libcontainerd.Remote, rs registry.Service, liveRestore bool, evL eventLogger) (err error) {
53
+func Init(root string, ps *store.Store, remote libcontainerd.Remote, rs registry.Service, liveRestore bool, evL eventLogger) (err error) {
54 54
 	if manager != nil {
55 55
 		return nil
56 56
 	}
... ...
@@ -59,7 +59,7 @@ func Init(root string, remote libcontainerd.Remote, rs registry.Service, liveRes
59 59
 	manager = &Manager{
60 60
 		libRoot:           root,
61 61
 		runRoot:           "/run/docker",
62
-		pluginStore:       store.NewPluginStore(root),
62
+		pluginStore:       ps,
63 63
 		registryService:   rs,
64 64
 		liveRestore:       liveRestore,
65 65
 		pluginEventLogger: evL,
66 66
new file mode 100644
... ...
@@ -0,0 +1,31 @@
0
+package store
1
+
2
+import (
3
+	"path/filepath"
4
+	"sync"
5
+
6
+	"github.com/docker/docker/pkg/plugins"
7
+	"github.com/docker/docker/plugin/v2"
8
+)
9
+
10
+// Store manages the plugin inventory in memory and on-disk
11
+type Store struct {
12
+	sync.RWMutex
13
+	plugins map[string]*v2.Plugin
14
+	/* handlers are necessary for transition path of legacy plugins
15
+	 * to the new model. Legacy plugins use Handle() for registering an
16
+	 * activation callback.*/
17
+	handlers map[string]func(string, *plugins.Client)
18
+	nameToID map[string]string
19
+	plugindb string
20
+}
21
+
22
+// NewStore creates a Store.
23
+func NewStore(libRoot string) *Store {
24
+	return &Store{
25
+		plugins:  make(map[string]*v2.Plugin),
26
+		handlers: make(map[string]func(string, *plugins.Client)),
27
+		nameToID: make(map[string]string),
28
+		plugindb: filepath.Join(libRoot, "plugins", "plugins.json"),
29
+	}
30
+}
0 31
deleted file mode 100644
... ...
@@ -1,19 +0,0 @@
1
-package store
2
-
3
-import "github.com/docker/docker/pkg/plugins"
4
-
5
-const (
6
-	// LOOKUP doesn't update RefCount
7
-	LOOKUP = 0
8
-	// CREATE increments RefCount
9
-	CREATE = 1
10
-	// REMOVE decrements RefCount
11
-	REMOVE = -1
12
-)
13
-
14
-// CompatPlugin is an abstraction to handle both new and legacy (v1) plugins.
15
-type CompatPlugin interface {
16
-	Client() *plugins.Client
17
-	Name() string
18
-	IsLegacy() bool
19
-}
20 1
deleted file mode 100644
... ...
@@ -1,25 +0,0 @@
1
-// +build !experimental
2
-
3
-package store
4
-
5
-import (
6
-	"github.com/docker/docker/pkg/plugins"
7
-)
8
-
9
-// FindWithCapability returns a list of plugins matching the given capability.
10
-func FindWithCapability(capability string) ([]CompatPlugin, error) {
11
-	pl, err := plugins.GetAll(capability)
12
-	if err != nil {
13
-		return nil, err
14
-	}
15
-	result := make([]CompatPlugin, len(pl))
16
-	for i, p := range pl {
17
-		result[i] = p
18
-	}
19
-	return result, nil
20
-}
21
-
22
-// LookupWithCapability returns a plugin matching the given name and capability.
23
-func LookupWithCapability(name, capability string, _ int) (CompatPlugin, error) {
24
-	return plugins.Get(name, capability)
25
-}
... ...
@@ -1,257 +1,26 @@
1
-// +build experimental
1
+// +build !experimental
2 2
 
3 3
 package store
4 4
 
5 5
 import (
6
-	"encoding/json"
7
-	"fmt"
8
-	"path/filepath"
9
-	"strings"
10
-	"sync"
11
-
12
-	"github.com/Sirupsen/logrus"
13
-	"github.com/docker/docker/pkg/ioutils"
14 6
 	"github.com/docker/docker/pkg/plugins"
15
-	"github.com/docker/docker/plugin/v2"
16
-	"github.com/docker/docker/reference"
17
-)
18
-
19
-var (
20
-	store *PluginStore
21
-	/* allowV1PluginsFallback determines daemon's support for V1 plugins.
22
-	 * When the time comes to remove support for V1 plugins, flipping
23
-	 * this bool is all that will be needed.
24
-	 */
25
-	allowV1PluginsFallback = true
7
+	"github.com/docker/docker/plugin/getter"
26 8
 )
27 9
 
28
-// ErrNotFound indicates that a plugin was not found locally.
29
-type ErrNotFound string
30
-
31
-func (name ErrNotFound) Error() string { return fmt.Sprintf("plugin %q not found", string(name)) }
32
-
33
-// PluginStore manages the plugin inventory in memory and on-disk
34
-type PluginStore struct {
35
-	sync.RWMutex
36
-	plugins map[string]*v2.Plugin
37
-	/* handlers are necessary for transition path of legacy plugins
38
-	 * to the new model. Legacy plugins use Handle() for registering an
39
-	 * activation callback.*/
40
-	handlers map[string]func(string, *plugins.Client)
41
-	nameToID map[string]string
42
-	plugindb string
43
-}
44
-
45
-// NewPluginStore creates a PluginStore.
46
-func NewPluginStore(libRoot string) *PluginStore {
47
-	store = &PluginStore{
48
-		plugins:  make(map[string]*v2.Plugin),
49
-		handlers: make(map[string]func(string, *plugins.Client)),
50
-		nameToID: make(map[string]string),
51
-		plugindb: filepath.Join(libRoot, "plugins.json"),
52
-	}
53
-	return store
54
-}
55
-
56
-// GetByName retreives a plugin by name.
57
-func (ps *PluginStore) GetByName(name string) (*v2.Plugin, error) {
58
-	ps.RLock()
59
-	defer ps.RUnlock()
60
-
61
-	id, nameOk := ps.nameToID[name]
62
-	if !nameOk {
63
-		return nil, ErrNotFound(name)
64
-	}
65
-
66
-	p, idOk := ps.plugins[id]
67
-	if !idOk {
68
-		return nil, ErrNotFound(id)
69
-	}
70
-	return p, nil
71
-}
72
-
73
-// GetByID retreives a plugin by ID.
74
-func (ps *PluginStore) GetByID(id string) (*v2.Plugin, error) {
75
-	ps.RLock()
76
-	defer ps.RUnlock()
77
-
78
-	p, idOk := ps.plugins[id]
79
-	if !idOk {
80
-		return nil, ErrNotFound(id)
81
-	}
82
-	return p, nil
83
-}
84
-
85
-// GetAll retreives all plugins.
86
-func (ps *PluginStore) GetAll() map[string]*v2.Plugin {
87
-	ps.RLock()
88
-	defer ps.RUnlock()
89
-	return ps.plugins
90
-}
91
-
92
-// SetAll initialized plugins during daemon restore.
93
-func (ps *PluginStore) SetAll(plugins map[string]*v2.Plugin) {
94
-	ps.Lock()
95
-	defer ps.Unlock()
96
-	ps.plugins = plugins
97
-}
98
-
99
-func (ps *PluginStore) getByCap(name string, capability string) (*v2.Plugin, error) {
100
-	ps.RLock()
101
-	defer ps.RUnlock()
102
-
103
-	p, err := ps.GetByName(name)
10
+// GetAllByCap returns a list of plugins matching the given capability.
11
+func (ps Store) GetAllByCap(capability string) ([]getter.CompatPlugin, error) {
12
+	pl, err := plugins.GetAll(capability)
104 13
 	if err != nil {
105 14
 		return nil, err
106 15
 	}
107
-	return p.FilterByCap(capability)
108
-}
109
-
110
-func (ps *PluginStore) getAllByCap(capability string) []CompatPlugin {
111
-	ps.RLock()
112
-	defer ps.RUnlock()
113
-
114
-	result := make([]CompatPlugin, 0, 1)
115
-	for _, p := range ps.plugins {
116
-		if _, err := p.FilterByCap(capability); err == nil {
117
-			result = append(result, p)
118
-		}
119
-	}
120
-	return result
121
-}
122
-
123
-// SetState sets the active state of the plugin and updates plugindb.
124
-func (ps *PluginStore) SetState(p *v2.Plugin, state bool) {
125
-	ps.Lock()
126
-	defer ps.Unlock()
127
-
128
-	p.PluginObj.Enabled = state
129
-	ps.updatePluginDB()
130
-}
131
-
132
-// Add adds a plugin to memory and plugindb.
133
-func (ps *PluginStore) Add(p *v2.Plugin) {
134
-	ps.Lock()
135
-	ps.plugins[p.GetID()] = p
136
-	ps.nameToID[p.Name()] = p.GetID()
137
-	ps.updatePluginDB()
138
-	ps.Unlock()
139
-}
140
-
141
-// Remove removes a plugin from memory, plugindb and disk.
142
-func (ps *PluginStore) Remove(p *v2.Plugin) {
143
-	ps.Lock()
144
-	delete(ps.plugins, p.GetID())
145
-	delete(ps.nameToID, p.Name())
146
-	ps.updatePluginDB()
147
-	p.RemoveFromDisk()
148
-	ps.Unlock()
149
-}
150
-
151
-// Callers are expected to hold the store lock.
152
-func (ps *PluginStore) updatePluginDB() error {
153
-	jsonData, err := json.Marshal(ps.plugins)
154
-	if err != nil {
155
-		logrus.Debugf("Error in json.Marshal: %v", err)
156
-		return err
157
-	}
158
-	ioutils.AtomicWriteFile(ps.plugindb, jsonData, 0600)
159
-	return nil
160
-}
161
-
162
-// LookupWithCapability returns a plugin matching the given name and capability.
163
-func LookupWithCapability(name, capability string, mode int) (CompatPlugin, error) {
164
-	var (
165
-		p   *v2.Plugin
166
-		err error
167
-	)
168
-
169
-	// Lookup using new model.
170
-	if store != nil {
171
-		fullName := name
172
-		if named, err := reference.ParseNamed(fullName); err == nil { // FIXME: validate
173
-			if reference.IsNameOnly(named) {
174
-				named = reference.WithDefaultTag(named)
175
-			}
176
-			ref, ok := named.(reference.NamedTagged)
177
-			if !ok {
178
-				return nil, fmt.Errorf("invalid name: %s", named.String())
179
-			}
180
-			fullName = ref.String()
181
-		}
182
-		p, err = store.GetByName(fullName)
183
-		if err == nil {
184
-			p.Lock()
185
-			p.RefCount += mode
186
-			p.Unlock()
187
-			return p.FilterByCap(capability)
188
-		}
189
-		if _, ok := err.(ErrNotFound); !ok {
190
-			return nil, err
191
-		}
192
-	}
193
-
194
-	// Lookup using legacy model.
195
-	if allowV1PluginsFallback {
196
-		p, err := plugins.Get(name, capability)
197
-		if err != nil {
198
-			return nil, fmt.Errorf("legacy plugin: %v", err)
199
-		}
200
-		return p, nil
201
-	}
202
-
203
-	return nil, err
204
-}
205
-
206
-// FindWithCapability returns a list of plugins matching the given capability.
207
-func FindWithCapability(capability string) ([]CompatPlugin, error) {
208
-	result := make([]CompatPlugin, 0, 1)
209
-
210
-	/* Daemon start always calls plugin.Init thereby initializing a store.
211
-	 * So store on experimental builds can never be nil, even while
212
-	 * handling legacy plugins. However, there are legacy plugin unit
213
-	 * tests where the volume subsystem directly talks with the plugin,
214
-	 * bypassing the daemon. For such tests, this check is necessary.
215
-	 */
216
-	if store != nil {
217
-		store.RLock()
218
-		result = store.getAllByCap(capability)
219
-		store.RUnlock()
220
-	}
221
-
222
-	// Lookup with legacy model
223
-	if allowV1PluginsFallback {
224
-		pl, err := plugins.GetAll(capability)
225
-		if err != nil {
226
-			return nil, fmt.Errorf("legacy plugin: %v", err)
227
-		}
228
-		for _, p := range pl {
229
-			result = append(result, p)
230
-		}
16
+	result := make([]getter.CompatPlugin, len(pl))
17
+	for i, p := range pl {
18
+		result[i] = p
231 19
 	}
232 20
 	return result, nil
233 21
 }
234 22
 
235
-// Handle sets a callback for a given capability. It is only used by network
236
-// and ipam drivers during plugin registration. The callback registers the
237
-// driver with the subsystem (network, ipam).
238
-func Handle(capability string, callback func(string, *plugins.Client)) {
239
-	pluginType := fmt.Sprintf("docker.%s/1", strings.ToLower(capability))
240
-
241
-	// Register callback with new plugin model.
242
-	store.handlers[pluginType] = callback
243
-
244
-	// Register callback with legacy plugin model.
245
-	if allowV1PluginsFallback {
246
-		plugins.Handle(capability, callback)
247
-	}
248
-}
249
-
250
-// CallHandler calls the registered callback. It is invoked during plugin enable.
251
-func (ps *PluginStore) CallHandler(p *v2.Plugin) {
252
-	for _, typ := range p.GetTypes() {
253
-		if handler := ps.handlers[typ.String()]; handler != nil {
254
-			handler(p.Name(), p.Client())
255
-		}
256
-	}
23
+// Get returns a plugin matching the given name and capability.
24
+func (ps Store) Get(name, capability string, _ int) (getter.CompatPlugin, error) {
25
+	return plugins.Get(name, capability)
257 26
 }
258 27
new file mode 100644
... ...
@@ -0,0 +1,234 @@
0
+// +build experimental
1
+
2
+package store
3
+
4
+import (
5
+	"encoding/json"
6
+	"fmt"
7
+	"strings"
8
+
9
+	"github.com/Sirupsen/logrus"
10
+	"github.com/docker/docker/pkg/ioutils"
11
+	"github.com/docker/docker/pkg/plugins"
12
+	"github.com/docker/docker/plugin/getter"
13
+	"github.com/docker/docker/plugin/v2"
14
+	"github.com/docker/docker/reference"
15
+)
16
+
17
+/* allowV1PluginsFallback determines daemon's support for V1 plugins.
18
+ * When the time comes to remove support for V1 plugins, flipping
19
+ * this bool is all that will be needed.
20
+ */
21
+var allowV1PluginsFallback = true
22
+
23
+// ErrNotFound indicates that a plugin was not found locally.
24
+type ErrNotFound string
25
+
26
+func (name ErrNotFound) Error() string { return fmt.Sprintf("plugin %q not found", string(name)) }
27
+
28
+// GetByName retreives a plugin by name.
29
+func (ps *Store) GetByName(name string) (*v2.Plugin, error) {
30
+	ps.RLock()
31
+	defer ps.RUnlock()
32
+
33
+	id, nameOk := ps.nameToID[name]
34
+	if !nameOk {
35
+		return nil, ErrNotFound(name)
36
+	}
37
+
38
+	p, idOk := ps.plugins[id]
39
+	if !idOk {
40
+		return nil, ErrNotFound(id)
41
+	}
42
+	return p, nil
43
+}
44
+
45
+// GetByID retreives a plugin by ID.
46
+func (ps *Store) GetByID(id string) (*v2.Plugin, error) {
47
+	ps.RLock()
48
+	defer ps.RUnlock()
49
+
50
+	p, idOk := ps.plugins[id]
51
+	if !idOk {
52
+		return nil, ErrNotFound(id)
53
+	}
54
+	return p, nil
55
+}
56
+
57
+// GetAll retreives all plugins.
58
+func (ps *Store) GetAll() map[string]*v2.Plugin {
59
+	ps.RLock()
60
+	defer ps.RUnlock()
61
+	return ps.plugins
62
+}
63
+
64
+// SetAll initialized plugins during daemon restore.
65
+func (ps *Store) SetAll(plugins map[string]*v2.Plugin) {
66
+	ps.Lock()
67
+	defer ps.Unlock()
68
+	ps.plugins = plugins
69
+}
70
+
71
+func (ps *Store) getByCap(name string, capability string) (*v2.Plugin, error) {
72
+	ps.RLock()
73
+	defer ps.RUnlock()
74
+
75
+	p, err := ps.GetByName(name)
76
+	if err != nil {
77
+		return nil, err
78
+	}
79
+	return p.FilterByCap(capability)
80
+}
81
+
82
+func (ps *Store) getAllByCap(capability string) []getter.CompatPlugin {
83
+	ps.RLock()
84
+	defer ps.RUnlock()
85
+
86
+	result := make([]getter.CompatPlugin, 0, 1)
87
+	for _, p := range ps.plugins {
88
+		if _, err := p.FilterByCap(capability); err == nil {
89
+			result = append(result, p)
90
+		}
91
+	}
92
+	return result
93
+}
94
+
95
+// SetState sets the active state of the plugin and updates plugindb.
96
+func (ps *Store) SetState(p *v2.Plugin, state bool) {
97
+	ps.Lock()
98
+	defer ps.Unlock()
99
+
100
+	p.PluginObj.Enabled = state
101
+	ps.updatePluginDB()
102
+}
103
+
104
+// Add adds a plugin to memory and plugindb.
105
+func (ps *Store) Add(p *v2.Plugin) {
106
+	ps.Lock()
107
+	ps.plugins[p.GetID()] = p
108
+	ps.nameToID[p.Name()] = p.GetID()
109
+	ps.updatePluginDB()
110
+	ps.Unlock()
111
+}
112
+
113
+// Remove removes a plugin from memory, plugindb and disk.
114
+func (ps *Store) Remove(p *v2.Plugin) {
115
+	ps.Lock()
116
+	delete(ps.plugins, p.GetID())
117
+	delete(ps.nameToID, p.Name())
118
+	ps.updatePluginDB()
119
+	p.RemoveFromDisk()
120
+	ps.Unlock()
121
+}
122
+
123
+// Callers are expected to hold the store lock.
124
+func (ps *Store) updatePluginDB() error {
125
+	jsonData, err := json.Marshal(ps.plugins)
126
+	if err != nil {
127
+		logrus.Debugf("Error in json.Marshal: %v", err)
128
+		return err
129
+	}
130
+	ioutils.AtomicWriteFile(ps.plugindb, jsonData, 0600)
131
+	return nil
132
+}
133
+
134
+// Get returns a plugin matching the given name and capability.
135
+func (ps *Store) Get(name, capability string, mode int) (getter.CompatPlugin, error) {
136
+	var (
137
+		p   *v2.Plugin
138
+		err error
139
+	)
140
+
141
+	// Lookup using new model.
142
+	if ps != nil {
143
+		fullName := name
144
+		if named, err := reference.ParseNamed(fullName); err == nil { // FIXME: validate
145
+			if reference.IsNameOnly(named) {
146
+				named = reference.WithDefaultTag(named)
147
+			}
148
+			ref, ok := named.(reference.NamedTagged)
149
+			if !ok {
150
+				return nil, fmt.Errorf("invalid name: %s", named.String())
151
+			}
152
+			fullName = ref.String()
153
+		}
154
+		p, err = ps.GetByName(fullName)
155
+		if err == nil {
156
+			p.Lock()
157
+			p.RefCount += mode
158
+			p.Unlock()
159
+			return p.FilterByCap(capability)
160
+		}
161
+		if _, ok := err.(ErrNotFound); !ok {
162
+			return nil, err
163
+		}
164
+	}
165
+
166
+	// Lookup using legacy model.
167
+	if allowV1PluginsFallback {
168
+		p, err := plugins.Get(name, capability)
169
+		if err != nil {
170
+			return nil, fmt.Errorf("legacy plugin: %v", err)
171
+		}
172
+		return p, nil
173
+	}
174
+
175
+	return nil, err
176
+}
177
+
178
+// GetAllByCap returns a list of plugins matching the given capability.
179
+func (ps *Store) GetAllByCap(capability string) ([]getter.CompatPlugin, error) {
180
+	result := make([]getter.CompatPlugin, 0, 1)
181
+
182
+	/* Daemon start always calls plugin.Init thereby initializing a store.
183
+	 * So store on experimental builds can never be nil, even while
184
+	 * handling legacy plugins. However, there are legacy plugin unit
185
+	 * tests where the volume subsystem directly talks with the plugin,
186
+	 * bypassing the daemon. For such tests, this check is necessary.
187
+	 */
188
+	if ps != nil {
189
+		ps.RLock()
190
+		result = ps.getAllByCap(capability)
191
+		ps.RUnlock()
192
+	}
193
+
194
+	// Lookup with legacy model
195
+	if allowV1PluginsFallback {
196
+		pl, err := plugins.GetAll(capability)
197
+		if err != nil {
198
+			return nil, fmt.Errorf("legacy plugin: %v", err)
199
+		}
200
+		for _, p := range pl {
201
+			result = append(result, p)
202
+		}
203
+	}
204
+	return result, nil
205
+}
206
+
207
+// Handle sets a callback for a given capability. It is only used by network
208
+// and ipam drivers during plugin registration. The callback registers the
209
+// driver with the subsystem (network, ipam).
210
+func (ps Store) Handle(capability string, callback func(string, *plugins.Client)) {
211
+	pluginType := fmt.Sprintf("docker.%s/1", strings.ToLower(capability))
212
+
213
+	store := &ps
214
+
215
+	// Register callback with new plugin model.
216
+	store.Lock()
217
+	store.handlers[pluginType] = callback
218
+	store.Unlock()
219
+
220
+	// Register callback with legacy plugin model.
221
+	if allowV1PluginsFallback {
222
+		plugins.Handle(capability, callback)
223
+	}
224
+}
225
+
226
+// CallHandler calls the registered callback. It is invoked during plugin enable.
227
+func (ps *Store) CallHandler(p *v2.Plugin) {
228
+	for _, typ := range p.GetTypes() {
229
+		if handler := ps.handlers[typ.String()]; handler != nil {
230
+			handler(p.Name(), p.Client())
231
+		}
232
+	}
233
+}
... ...
@@ -1,32 +1,13 @@
1
-// +build experimental
2
-
3 1
 package v2
4 2
 
5 3
 import (
6
-	"encoding/json"
7
-	"errors"
8
-	"fmt"
9
-	"os"
10
-	"path/filepath"
11
-	"strings"
12 4
 	"sync"
13 5
 
14 6
 	"github.com/docker/docker/api/types"
15 7
 	"github.com/docker/docker/pkg/plugins"
16
-	"github.com/docker/docker/pkg/system"
17 8
 	"github.com/docker/docker/restartmanager"
18
-	"github.com/opencontainers/runtime-spec/specs-go"
19 9
 )
20 10
 
21
-const defaultPluginRuntimeDestination = "/run/docker/plugins"
22
-
23
-// ErrInadequateCapability indicates that the plugin did not have the requested capability.
24
-type ErrInadequateCapability string
25
-
26
-func (cap ErrInadequateCapability) Error() string {
27
-	return fmt.Sprintf("plugin does not provide %q capability", cap)
28
-}
29
-
30 11
 // Plugin represents an individual plugin.
31 12
 type Plugin struct {
32 13
 	sync.RWMutex
... ...
@@ -37,226 +18,3 @@ type Plugin struct {
37 37
 	ExitChan          chan bool                     `json:"-"`
38 38
 	RefCount          int                           `json:"-"`
39 39
 }
40
-
41
-func newPluginObj(name, id, tag string) types.Plugin {
42
-	return types.Plugin{Name: name, ID: id, Tag: tag}
43
-}
44
-
45
-// NewPlugin creates a plugin.
46
-func NewPlugin(name, id, runRoot, tag string) *Plugin {
47
-	return &Plugin{
48
-		PluginObj:         newPluginObj(name, id, tag),
49
-		RuntimeSourcePath: filepath.Join(runRoot, id),
50
-	}
51
-}
52
-
53
-// Client returns the plugin client.
54
-func (p *Plugin) Client() *plugins.Client {
55
-	return p.PClient
56
-}
57
-
58
-// IsLegacy returns true for legacy plugins and false otherwise.
59
-func (p *Plugin) IsLegacy() bool {
60
-	return false
61
-}
62
-
63
-// Name returns the plugin name.
64
-func (p *Plugin) Name() string {
65
-	name := p.PluginObj.Name
66
-	if len(p.PluginObj.Tag) > 0 {
67
-		// TODO: this feels hacky, maybe we should be storing the distribution reference rather than splitting these
68
-		name += ":" + p.PluginObj.Tag
69
-	}
70
-	return name
71
-}
72
-
73
-// FilterByCap query the plugin for a given capability.
74
-func (p *Plugin) FilterByCap(capability string) (*Plugin, error) {
75
-	capability = strings.ToLower(capability)
76
-	for _, typ := range p.PluginObj.Manifest.Interface.Types {
77
-		if typ.Capability == capability && typ.Prefix == "docker" {
78
-			return p, nil
79
-		}
80
-	}
81
-	return nil, ErrInadequateCapability(capability)
82
-}
83
-
84
-// RemoveFromDisk deletes the plugin's runtime files from disk.
85
-func (p *Plugin) RemoveFromDisk() error {
86
-	return os.RemoveAll(p.RuntimeSourcePath)
87
-}
88
-
89
-// InitPlugin populates the plugin object from the plugin manifest file.
90
-func (p *Plugin) InitPlugin(libRoot string) error {
91
-	dt, err := os.Open(filepath.Join(libRoot, p.PluginObj.ID, "manifest.json"))
92
-	if err != nil {
93
-		return err
94
-	}
95
-	err = json.NewDecoder(dt).Decode(&p.PluginObj.Manifest)
96
-	dt.Close()
97
-	if err != nil {
98
-		return err
99
-	}
100
-
101
-	p.PluginObj.Config.Mounts = make([]types.PluginMount, len(p.PluginObj.Manifest.Mounts))
102
-	for i, mount := range p.PluginObj.Manifest.Mounts {
103
-		p.PluginObj.Config.Mounts[i] = mount
104
-	}
105
-	p.PluginObj.Config.Env = make([]string, 0, len(p.PluginObj.Manifest.Env))
106
-	for _, env := range p.PluginObj.Manifest.Env {
107
-		if env.Value != nil {
108
-			p.PluginObj.Config.Env = append(p.PluginObj.Config.Env, fmt.Sprintf("%s=%s", env.Name, *env.Value))
109
-		}
110
-	}
111
-	copy(p.PluginObj.Config.Args, p.PluginObj.Manifest.Args.Value)
112
-
113
-	f, err := os.Create(filepath.Join(libRoot, p.PluginObj.ID, "plugin-config.json"))
114
-	if err != nil {
115
-		return err
116
-	}
117
-	err = json.NewEncoder(f).Encode(&p.PluginObj.Config)
118
-	f.Close()
119
-	return err
120
-}
121
-
122
-// Set is used to pass arguments to the plugin.
123
-func (p *Plugin) Set(args []string) error {
124
-	m := make(map[string]string, len(args))
125
-	for _, arg := range args {
126
-		i := strings.Index(arg, "=")
127
-		if i < 0 {
128
-			return fmt.Errorf("No equal sign '=' found in %s", arg)
129
-		}
130
-		m[arg[:i]] = arg[i+1:]
131
-	}
132
-	return errors.New("not implemented")
133
-}
134
-
135
-// ComputePrivileges takes the manifest file and computes the list of access necessary
136
-// for the plugin on the host.
137
-func (p *Plugin) ComputePrivileges() types.PluginPrivileges {
138
-	m := p.PluginObj.Manifest
139
-	var privileges types.PluginPrivileges
140
-	if m.Network.Type != "null" && m.Network.Type != "bridge" {
141
-		privileges = append(privileges, types.PluginPrivilege{
142
-			Name:        "network",
143
-			Description: "",
144
-			Value:       []string{m.Network.Type},
145
-		})
146
-	}
147
-	for _, mount := range m.Mounts {
148
-		if mount.Source != nil {
149
-			privileges = append(privileges, types.PluginPrivilege{
150
-				Name:        "mount",
151
-				Description: "",
152
-				Value:       []string{*mount.Source},
153
-			})
154
-		}
155
-	}
156
-	for _, device := range m.Devices {
157
-		if device.Path != nil {
158
-			privileges = append(privileges, types.PluginPrivilege{
159
-				Name:        "device",
160
-				Description: "",
161
-				Value:       []string{*device.Path},
162
-			})
163
-		}
164
-	}
165
-	if len(m.Capabilities) > 0 {
166
-		privileges = append(privileges, types.PluginPrivilege{
167
-			Name:        "capabilities",
168
-			Description: "",
169
-			Value:       m.Capabilities,
170
-		})
171
-	}
172
-	return privileges
173
-}
174
-
175
-// IsEnabled returns the active state of the plugin.
176
-func (p *Plugin) IsEnabled() bool {
177
-	p.RLock()
178
-	defer p.RUnlock()
179
-
180
-	return p.PluginObj.Enabled
181
-}
182
-
183
-// GetID returns the plugin's ID.
184
-func (p *Plugin) GetID() string {
185
-	p.RLock()
186
-	defer p.RUnlock()
187
-
188
-	return p.PluginObj.ID
189
-}
190
-
191
-// GetSocket returns the plugin socket.
192
-func (p *Plugin) GetSocket() string {
193
-	p.RLock()
194
-	defer p.RUnlock()
195
-
196
-	return p.PluginObj.Manifest.Interface.Socket
197
-}
198
-
199
-// GetTypes returns the interface types of a plugin.
200
-func (p *Plugin) GetTypes() []types.PluginInterfaceType {
201
-	p.RLock()
202
-	defer p.RUnlock()
203
-
204
-	return p.PluginObj.Manifest.Interface.Types
205
-}
206
-
207
-// InitSpec creates an OCI spec from the plugin's config.
208
-func (p *Plugin) InitSpec(s specs.Spec, libRoot string) (*specs.Spec, error) {
209
-	rootfs := filepath.Join(libRoot, p.PluginObj.ID, "rootfs")
210
-	s.Root = specs.Root{
211
-		Path:     rootfs,
212
-		Readonly: false, // TODO: all plugins should be readonly? settable in manifest?
213
-	}
214
-
215
-	mounts := append(p.PluginObj.Config.Mounts, types.PluginMount{
216
-		Source:      &p.RuntimeSourcePath,
217
-		Destination: defaultPluginRuntimeDestination,
218
-		Type:        "bind",
219
-		Options:     []string{"rbind", "rshared"},
220
-	})
221
-	for _, mount := range mounts {
222
-		m := specs.Mount{
223
-			Destination: mount.Destination,
224
-			Type:        mount.Type,
225
-			Options:     mount.Options,
226
-		}
227
-		// TODO: if nil, then it's required and user didn't set it
228
-		if mount.Source != nil {
229
-			m.Source = *mount.Source
230
-		}
231
-		if m.Source != "" && m.Type == "bind" {
232
-			fi, err := os.Lstat(filepath.Join(rootfs, string(os.PathSeparator), m.Destination)) // TODO: followsymlinks
233
-			if err != nil {
234
-				return nil, err
235
-			}
236
-			if fi.IsDir() {
237
-				if err := os.MkdirAll(m.Source, 0700); err != nil {
238
-					return nil, err
239
-				}
240
-			}
241
-		}
242
-		s.Mounts = append(s.Mounts, m)
243
-	}
244
-
245
-	envs := make([]string, 1, len(p.PluginObj.Config.Env)+1)
246
-	envs[0] = "PATH=" + system.DefaultPathEnv
247
-	envs = append(envs, p.PluginObj.Config.Env...)
248
-
249
-	args := append(p.PluginObj.Manifest.Entrypoint, p.PluginObj.Config.Args...)
250
-	cwd := p.PluginObj.Manifest.Workdir
251
-	if len(cwd) == 0 {
252
-		cwd = "/"
253
-	}
254
-	s.Process = specs.Process{
255
-		Terminal: false,
256
-		Args:     args,
257
-		Cwd:      cwd,
258
-		Env:      envs,
259
-	}
260
-
261
-	return &s, nil
262
-}
263 40
new file mode 100644
... ...
@@ -0,0 +1,249 @@
0
+// +build experimental
1
+
2
+package v2
3
+
4
+import (
5
+	"encoding/json"
6
+	"errors"
7
+	"fmt"
8
+	"os"
9
+	"path/filepath"
10
+	"strings"
11
+
12
+	"github.com/docker/docker/api/types"
13
+	"github.com/docker/docker/pkg/plugins"
14
+	"github.com/docker/docker/pkg/system"
15
+	"github.com/opencontainers/runtime-spec/specs-go"
16
+)
17
+
18
+const defaultPluginRuntimeDestination = "/run/docker/plugins"
19
+
20
+// ErrInadequateCapability indicates that the plugin did not have the requested capability.
21
+type ErrInadequateCapability string
22
+
23
+func (cap ErrInadequateCapability) Error() string {
24
+	return fmt.Sprintf("plugin does not provide %q capability", cap)
25
+}
26
+
27
+func newPluginObj(name, id, tag string) types.Plugin {
28
+	return types.Plugin{Name: name, ID: id, Tag: tag}
29
+}
30
+
31
+// NewPlugin creates a plugin.
32
+func NewPlugin(name, id, runRoot, tag string) *Plugin {
33
+	return &Plugin{
34
+		PluginObj:         newPluginObj(name, id, tag),
35
+		RuntimeSourcePath: filepath.Join(runRoot, id),
36
+	}
37
+}
38
+
39
+// Client returns the plugin client.
40
+func (p *Plugin) Client() *plugins.Client {
41
+	return p.PClient
42
+}
43
+
44
+// IsV1 returns true for V1 plugins and false otherwise.
45
+func (p *Plugin) IsV1() bool {
46
+	return false
47
+}
48
+
49
+// Name returns the plugin name.
50
+func (p *Plugin) Name() string {
51
+	name := p.PluginObj.Name
52
+	if len(p.PluginObj.Tag) > 0 {
53
+		// TODO: this feels hacky, maybe we should be storing the distribution reference rather than splitting these
54
+		name += ":" + p.PluginObj.Tag
55
+	}
56
+	return name
57
+}
58
+
59
+// FilterByCap query the plugin for a given capability.
60
+func (p *Plugin) FilterByCap(capability string) (*Plugin, error) {
61
+	capability = strings.ToLower(capability)
62
+	for _, typ := range p.PluginObj.Manifest.Interface.Types {
63
+		if typ.Capability == capability && typ.Prefix == "docker" {
64
+			return p, nil
65
+		}
66
+	}
67
+	return nil, ErrInadequateCapability(capability)
68
+}
69
+
70
+// RemoveFromDisk deletes the plugin's runtime files from disk.
71
+func (p *Plugin) RemoveFromDisk() error {
72
+	return os.RemoveAll(p.RuntimeSourcePath)
73
+}
74
+
75
+// InitPlugin populates the plugin object from the plugin manifest file.
76
+func (p *Plugin) InitPlugin(libRoot string) error {
77
+	dt, err := os.Open(filepath.Join(libRoot, p.PluginObj.ID, "manifest.json"))
78
+	if err != nil {
79
+		return err
80
+	}
81
+	err = json.NewDecoder(dt).Decode(&p.PluginObj.Manifest)
82
+	dt.Close()
83
+	if err != nil {
84
+		return err
85
+	}
86
+
87
+	p.PluginObj.Config.Mounts = make([]types.PluginMount, len(p.PluginObj.Manifest.Mounts))
88
+	for i, mount := range p.PluginObj.Manifest.Mounts {
89
+		p.PluginObj.Config.Mounts[i] = mount
90
+	}
91
+	p.PluginObj.Config.Env = make([]string, 0, len(p.PluginObj.Manifest.Env))
92
+	for _, env := range p.PluginObj.Manifest.Env {
93
+		if env.Value != nil {
94
+			p.PluginObj.Config.Env = append(p.PluginObj.Config.Env, fmt.Sprintf("%s=%s", env.Name, *env.Value))
95
+		}
96
+	}
97
+	copy(p.PluginObj.Config.Args, p.PluginObj.Manifest.Args.Value)
98
+
99
+	f, err := os.Create(filepath.Join(libRoot, p.PluginObj.ID, "plugin-config.json"))
100
+	if err != nil {
101
+		return err
102
+	}
103
+	err = json.NewEncoder(f).Encode(&p.PluginObj.Config)
104
+	f.Close()
105
+	return err
106
+}
107
+
108
+// Set is used to pass arguments to the plugin.
109
+func (p *Plugin) Set(args []string) error {
110
+	m := make(map[string]string, len(args))
111
+	for _, arg := range args {
112
+		i := strings.Index(arg, "=")
113
+		if i < 0 {
114
+			return fmt.Errorf("No equal sign '=' found in %s", arg)
115
+		}
116
+		m[arg[:i]] = arg[i+1:]
117
+	}
118
+	return errors.New("not implemented")
119
+}
120
+
121
+// ComputePrivileges takes the manifest file and computes the list of access necessary
122
+// for the plugin on the host.
123
+func (p *Plugin) ComputePrivileges() types.PluginPrivileges {
124
+	m := p.PluginObj.Manifest
125
+	var privileges types.PluginPrivileges
126
+	if m.Network.Type != "null" && m.Network.Type != "bridge" {
127
+		privileges = append(privileges, types.PluginPrivilege{
128
+			Name:        "network",
129
+			Description: "",
130
+			Value:       []string{m.Network.Type},
131
+		})
132
+	}
133
+	for _, mount := range m.Mounts {
134
+		if mount.Source != nil {
135
+			privileges = append(privileges, types.PluginPrivilege{
136
+				Name:        "mount",
137
+				Description: "",
138
+				Value:       []string{*mount.Source},
139
+			})
140
+		}
141
+	}
142
+	for _, device := range m.Devices {
143
+		if device.Path != nil {
144
+			privileges = append(privileges, types.PluginPrivilege{
145
+				Name:        "device",
146
+				Description: "",
147
+				Value:       []string{*device.Path},
148
+			})
149
+		}
150
+	}
151
+	if len(m.Capabilities) > 0 {
152
+		privileges = append(privileges, types.PluginPrivilege{
153
+			Name:        "capabilities",
154
+			Description: "",
155
+			Value:       m.Capabilities,
156
+		})
157
+	}
158
+	return privileges
159
+}
160
+
161
+// IsEnabled returns the active state of the plugin.
162
+func (p *Plugin) IsEnabled() bool {
163
+	p.RLock()
164
+	defer p.RUnlock()
165
+
166
+	return p.PluginObj.Enabled
167
+}
168
+
169
+// GetID returns the plugin's ID.
170
+func (p *Plugin) GetID() string {
171
+	p.RLock()
172
+	defer p.RUnlock()
173
+
174
+	return p.PluginObj.ID
175
+}
176
+
177
+// GetSocket returns the plugin socket.
178
+func (p *Plugin) GetSocket() string {
179
+	p.RLock()
180
+	defer p.RUnlock()
181
+
182
+	return p.PluginObj.Manifest.Interface.Socket
183
+}
184
+
185
+// GetTypes returns the interface types of a plugin.
186
+func (p *Plugin) GetTypes() []types.PluginInterfaceType {
187
+	p.RLock()
188
+	defer p.RUnlock()
189
+
190
+	return p.PluginObj.Manifest.Interface.Types
191
+}
192
+
193
+// InitSpec creates an OCI spec from the plugin's config.
194
+func (p *Plugin) InitSpec(s specs.Spec, libRoot string) (*specs.Spec, error) {
195
+	rootfs := filepath.Join(libRoot, p.PluginObj.ID, "rootfs")
196
+	s.Root = specs.Root{
197
+		Path:     rootfs,
198
+		Readonly: false, // TODO: all plugins should be readonly? settable in manifest?
199
+	}
200
+
201
+	mounts := append(p.PluginObj.Config.Mounts, types.PluginMount{
202
+		Source:      &p.RuntimeSourcePath,
203
+		Destination: defaultPluginRuntimeDestination,
204
+		Type:        "bind",
205
+		Options:     []string{"rbind", "rshared"},
206
+	})
207
+	for _, mount := range mounts {
208
+		m := specs.Mount{
209
+			Destination: mount.Destination,
210
+			Type:        mount.Type,
211
+			Options:     mount.Options,
212
+		}
213
+		// TODO: if nil, then it's required and user didn't set it
214
+		if mount.Source != nil {
215
+			m.Source = *mount.Source
216
+		}
217
+		if m.Source != "" && m.Type == "bind" {
218
+			fi, err := os.Lstat(filepath.Join(rootfs, m.Destination)) // TODO: followsymlinks
219
+			if err != nil {
220
+				return nil, err
221
+			}
222
+			if fi.IsDir() {
223
+				if err := os.MkdirAll(m.Source, 0700); err != nil {
224
+					return nil, err
225
+				}
226
+			}
227
+		}
228
+		s.Mounts = append(s.Mounts, m)
229
+	}
230
+
231
+	envs := make([]string, 1, len(p.PluginObj.Config.Env)+1)
232
+	envs[0] = "PATH=" + system.DefaultPathEnv
233
+	envs = append(envs, p.PluginObj.Config.Env...)
234
+
235
+	args := append(p.PluginObj.Manifest.Entrypoint, p.PluginObj.Config.Args...)
236
+	cwd := p.PluginObj.Manifest.Workdir
237
+	if len(cwd) == 0 {
238
+		cwd = "/"
239
+	}
240
+	s.Process = specs.Process{
241
+		Terminal: false,
242
+		Args:     args,
243
+		Cwd:      cwd,
244
+		Env:      envs,
245
+	}
246
+
247
+	return &s, nil
248
+}
... ...
@@ -7,14 +7,17 @@ import (
7 7
 	"sync"
8 8
 
9 9
 	"github.com/docker/docker/pkg/locker"
10
-	pluginStore "github.com/docker/docker/plugin/store"
10
+	"github.com/docker/docker/plugin/getter"
11 11
 	"github.com/docker/docker/volume"
12 12
 )
13 13
 
14 14
 // currently created by hand. generation tool would generate this like:
15 15
 // $ extpoint-gen Driver > volume/extpoint.go
16 16
 
17
-var drivers = &driverExtpoint{extensions: make(map[string]volume.Driver), driverLock: &locker.Locker{}}
17
+var drivers = &driverExtpoint{
18
+	extensions: make(map[string]volume.Driver),
19
+	driverLock: &locker.Locker{},
20
+}
18 21
 
19 22
 const extName = "VolumeDriver"
20 23
 
... ...
@@ -49,7 +52,13 @@ type volumeDriver interface {
49 49
 type driverExtpoint struct {
50 50
 	extensions map[string]volume.Driver
51 51
 	sync.Mutex
52
-	driverLock *locker.Locker
52
+	driverLock   *locker.Locker
53
+	plugingetter getter.PluginGetter
54
+}
55
+
56
+// RegisterPluginGetter sets the plugingetter
57
+func RegisterPluginGetter(plugingetter getter.PluginGetter) {
58
+	drivers.plugingetter = plugingetter
53 59
 }
54 60
 
55 61
 // Register associates the given driver to the given name, checking if
... ...
@@ -72,6 +81,7 @@ func Register(extension volume.Driver, name string) bool {
72 72
 	}
73 73
 
74 74
 	drivers.extensions[name] = extension
75
+
75 76
 	return true
76 77
 }
77 78
 
... ...
@@ -102,7 +112,7 @@ func lookup(name string, mode int) (volume.Driver, error) {
102 102
 		return ext, nil
103 103
 	}
104 104
 
105
-	p, err := pluginStore.LookupWithCapability(name, extName, mode)
105
+	p, err := drivers.plugingetter.Get(name, extName, mode)
106 106
 	if err != nil {
107 107
 		return nil, fmt.Errorf("Error looking up volume plugin %s: %v", name, err)
108 108
 	}
... ...
@@ -112,7 +122,7 @@ func lookup(name string, mode int) (volume.Driver, error) {
112 112
 		return nil, err
113 113
 	}
114 114
 
115
-	if p.IsLegacy() {
115
+	if p.IsV1() {
116 116
 		drivers.Lock()
117 117
 		drivers.extensions[name] = d
118 118
 		drivers.Unlock()
... ...
@@ -134,7 +144,7 @@ func GetDriver(name string) (volume.Driver, error) {
134 134
 	if name == "" {
135 135
 		name = volume.DefaultDriverName
136 136
 	}
137
-	return lookup(name, pluginStore.LOOKUP)
137
+	return lookup(name, getter.LOOKUP)
138 138
 }
139 139
 
140 140
 // CreateDriver returns a volume driver by its name and increments RefCount.
... ...
@@ -143,7 +153,7 @@ func CreateDriver(name string) (volume.Driver, error) {
143 143
 	if name == "" {
144 144
 		name = volume.DefaultDriverName
145 145
 	}
146
-	return lookup(name, pluginStore.CREATE)
146
+	return lookup(name, getter.CREATE)
147 147
 }
148 148
 
149 149
 // RemoveDriver returns a volume driver by its name and decrements RefCount..
... ...
@@ -152,7 +162,7 @@ func RemoveDriver(name string) (volume.Driver, error) {
152 152
 	if name == "" {
153 153
 		name = volume.DefaultDriverName
154 154
 	}
155
-	return lookup(name, pluginStore.REMOVE)
155
+	return lookup(name, getter.REMOVE)
156 156
 }
157 157
 
158 158
 // GetDriverList returns list of volume drivers registered.
... ...
@@ -169,7 +179,7 @@ func GetDriverList() []string {
169 169
 
170 170
 // GetAllDrivers lists all the registered drivers
171 171
 func GetAllDrivers() ([]volume.Driver, error) {
172
-	plugins, err := pluginStore.FindWithCapability(extName)
172
+	plugins, err := drivers.plugingetter.GetAllByCap(extName)
173 173
 	if err != nil {
174 174
 		return nil, fmt.Errorf("error listing plugins: %v", err)
175 175
 	}
... ...
@@ -190,7 +200,7 @@ func GetAllDrivers() ([]volume.Driver, error) {
190 190
 		}
191 191
 
192 192
 		ext = NewVolumeDriver(name, p.Client())
193
-		if p.IsLegacy() {
193
+		if p.IsV1() {
194 194
 			drivers.extensions[name] = ext
195 195
 		}
196 196
 		ds = append(ds, ext)
... ...
@@ -3,16 +3,20 @@ package volumedrivers
3 3
 import (
4 4
 	"testing"
5 5
 
6
+	pluginstore "github.com/docker/docker/plugin/store"
6 7
 	volumetestutils "github.com/docker/docker/volume/testutils"
7 8
 )
8 9
 
9 10
 func TestGetDriver(t *testing.T) {
11
+	pluginStore := pluginstore.NewStore("/var/lib/docker")
12
+	RegisterPluginGetter(pluginStore)
13
+
10 14
 	_, err := GetDriver("missing")
11 15
 	if err == nil {
12 16
 		t.Fatal("Expected error, was nil")
13 17
 	}
14
-
15 18
 	Register(volumetestutils.NewFakeDriver("fake"), "fake")
19
+
16 20
 	d, err := GetDriver("fake")
17 21
 	if err != nil {
18 22
 		t.Fatal(err)
... ...
@@ -5,11 +5,15 @@ import (
5 5
 	"strings"
6 6
 	"testing"
7 7
 
8
+	pluginstore "github.com/docker/docker/plugin/store"
8 9
 	"github.com/docker/docker/volume/drivers"
9 10
 	volumetestutils "github.com/docker/docker/volume/testutils"
10 11
 )
11 12
 
12 13
 func TestCreate(t *testing.T) {
14
+	pluginStore := pluginstore.NewStore("/var/lib/docker")
15
+	volumedrivers.RegisterPluginGetter(pluginStore)
16
+
13 17
 	volumedrivers.Register(volumetestutils.NewFakeDriver("fake"), "fake")
14 18
 	defer volumedrivers.Unregister("fake")
15 19
 	s, err := New("")