Skip to content

Commit b27f70d

Browse files
committed
Fix issue with plugin scanner going to deep
The plugin spec says that plugins can live in one of: - /var/run/docker/plugins/<name>.sock - /var/run/docker/plugins/<name>/<name>.sock - /etc/docker/plugins/<name>.[json,spec] - /etc/docker/plugins/<name>/<name>.<json,spec> - /usr/lib/docker/plugins/<name>.<json,spec> - /usr/lib/docker/plugins/<name>/<name>.<json,spec> However, the plugin scanner which is used by the volume list API was doing `filepath.Walk`, which will walk the entire tree for each of the supported paths. This means that even v2 plugins in `/var/run/docker/plugins/<id>/<name>.sock` were being detected as a v1 plugin. When the v1 plugin loader tried to load such a plugin it would log an error that it couldn't find it because it doesn't match one of the supported patterns... e.g. when in a subdir, the subdir name must match the plugin name for the socket. There is no behavior change as the error is only on the `Scan()` call, which is passing names to the plugin registry when someone calls the volume list API. Signed-off-by: Brian Goff <[email protected]>
1 parent 99cfb5f commit b27f70d

3 files changed

Lines changed: 101 additions & 22 deletions

File tree

pkg/plugins/discovery.go

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@ package plugins
22

33
import (
44
"encoding/json"
5-
"errors"
65
"fmt"
76
"io/ioutil"
87
"net/url"
98
"os"
109
"path/filepath"
1110
"strings"
1211
"sync"
12+
13+
"github.com/pkg/errors"
1314
)
1415

1516
var (
@@ -28,30 +29,52 @@ func newLocalRegistry() localRegistry {
2829
// Scan scans all the plugin paths and returns all the names it found
2930
func Scan() ([]string, error) {
3031
var names []string
31-
if err := filepath.Walk(socketsPath, func(path string, fi os.FileInfo, err error) error {
32-
if err != nil {
33-
return nil
32+
dirEntries, err := ioutil.ReadDir(socketsPath)
33+
if err != nil && !os.IsNotExist(err) {
34+
return nil, errors.Wrap(err, "error reading dir entries")
35+
}
36+
37+
for _, fi := range dirEntries {
38+
if fi.IsDir() {
39+
fi, err = os.Stat(filepath.Join(socketsPath, fi.Name(), fi.Name()+".sock"))
40+
if err != nil {
41+
continue
42+
}
3443
}
3544

3645
if fi.Mode()&os.ModeSocket != 0 {
37-
name := strings.TrimSuffix(fi.Name(), filepath.Ext(fi.Name()))
38-
names = append(names, name)
46+
names = append(names, strings.TrimSuffix(filepath.Base(fi.Name()), filepath.Ext(fi.Name())))
3947
}
40-
return nil
41-
}); err != nil {
42-
return nil, err
4348
}
4449

45-
for _, path := range specsPaths {
46-
if err := filepath.Walk(path, func(p string, fi os.FileInfo, err error) error {
47-
if err != nil || fi.IsDir() {
48-
return nil
50+
for _, p := range specsPaths {
51+
dirEntries, err := ioutil.ReadDir(p)
52+
if err != nil && !os.IsNotExist(err) {
53+
return nil, errors.Wrap(err, "error reading dir entries")
54+
}
55+
56+
for _, fi := range dirEntries {
57+
if fi.IsDir() {
58+
infos, err := ioutil.ReadDir(filepath.Join(p, fi.Name()))
59+
if err != nil {
60+
continue
61+
}
62+
63+
for _, info := range infos {
64+
if strings.TrimSuffix(info.Name(), filepath.Ext(info.Name())) == fi.Name() {
65+
fi = info
66+
break
67+
}
68+
}
69+
}
70+
71+
ext := filepath.Ext(fi.Name())
72+
switch ext {
73+
case ".spec", ".json":
74+
plugin := strings.TrimSuffix(fi.Name(), ext)
75+
names = append(names, plugin)
76+
default:
4977
}
50-
name := strings.TrimSuffix(fi.Name(), filepath.Ext(fi.Name()))
51-
names = append(names, name)
52-
return nil
53-
}); err != nil {
54-
return nil, err
5578
}
5679
}
5780
return names, nil
@@ -81,7 +104,7 @@ func (l *localRegistry) Plugin(name string) (*Plugin, error) {
81104
return readPluginInfo(name, p)
82105
}
83106
}
84-
return nil, ErrNotFound
107+
return nil, errors.Wrapf(ErrNotFound, "could not find plugin %s in v1 plugin registry", name)
85108
}
86109

87110
func readPluginInfo(name, path string) (*Plugin, error) {

pkg/plugins/discovery_unix_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,63 @@ func TestScan(t *testing.T) {
9797
if err != nil {
9898
t.Fatal(err)
9999
}
100+
if len(pluginNamesNotEmpty) != 1 {
101+
t.Fatalf("expected 1 plugin entry: %v", pluginNamesNotEmpty)
102+
}
100103
if p.Name() != pluginNamesNotEmpty[0] {
101104
t.Fatalf("Unable to scan plugin with name %s", p.name)
102105
}
103106
}
107+
108+
func TestScanNotPlugins(t *testing.T) {
109+
tmpdir, unregister := Setup(t)
110+
defer unregister()
111+
112+
// not that `Setup()` above sets the sockets path and spec path dirs, which
113+
// `Scan()` uses to find plugins to the returned `tmpdir`
114+
115+
notPlugin := filepath.Join(tmpdir, "not-a-plugin")
116+
if err := os.MkdirAll(notPlugin, 0700); err != nil {
117+
t.Fatal(err)
118+
}
119+
120+
// this is named differently than the dir it's in, so the scanner should ignore it
121+
l, err := net.Listen("unix", filepath.Join(notPlugin, "foo.sock"))
122+
if err != nil {
123+
t.Fatal(err)
124+
}
125+
defer l.Close()
126+
127+
// same let's test a spec path
128+
f, err := os.Create(filepath.Join(notPlugin, "foo.spec"))
129+
if err != nil {
130+
t.Fatal(err)
131+
}
132+
defer f.Close()
133+
134+
names, err := Scan()
135+
if err != nil {
136+
t.Fatal(err)
137+
}
138+
if len(names) != 0 {
139+
t.Fatalf("expected no plugins, got %v", names)
140+
}
141+
142+
// Just as a sanity check, let's make an entry that the scanner should read
143+
f, err = os.Create(filepath.Join(notPlugin, "not-a-plugin.spec"))
144+
if err != nil {
145+
t.Fatal(err)
146+
}
147+
defer f.Close()
148+
149+
names, err = Scan()
150+
if err != nil {
151+
t.Fatal(err)
152+
}
153+
if len(names) != 1 {
154+
t.Fatalf("expected 1 entry in result: %v", names)
155+
}
156+
if names[0] != "not-a-plugin" {
157+
t.Fatalf("expected plugin named `not-a-plugin`, got: %s", names[0])
158+
}
159+
}

pkg/plugins/plugin_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package plugins
33
import (
44
"bytes"
55
"encoding/json"
6-
"errors"
76
"io"
87
"io/ioutil"
98
"net/http"
@@ -15,6 +14,7 @@ import (
1514

1615
"github.com/docker/docker/pkg/plugins/transport"
1716
"github.com/docker/go-connections/tlsconfig"
17+
"github.com/pkg/errors"
1818
"github.com/stretchr/testify/assert"
1919
)
2020

@@ -78,11 +78,11 @@ func TestGet(t *testing.T) {
7878

7979
// check negative case where plugin fruit doesn't implement banana
8080
_, err = Get("fruit", "banana")
81-
assert.Equal(t, err, ErrNotImplements)
81+
assert.Equal(t, errors.Cause(err), ErrNotImplements)
8282

8383
// check negative case where plugin vegetable doesn't exist
8484
_, err = Get("vegetable", "potato")
85-
assert.Equal(t, err, ErrNotFound)
85+
assert.Equal(t, errors.Cause(err), ErrNotFound)
8686

8787
}
8888

0 commit comments

Comments
 (0)