Merge pull request #13951 from calavera/plugins_path

Separate plugin sockets and specs.
This commit is contained in:
Sebastiaan van Stijn 2015-07-17 21:11:31 +02:00
commit 8e5b6040fa
3 changed files with 94 additions and 82 deletions

View file

@ -11,10 +11,10 @@ import (
"strings" "strings"
) )
const defaultLocalRegistry = "/usr/share/docker/plugins"
var ( var (
ErrNotFound = errors.New("Plugin not found") ErrNotFound = errors.New("Plugin not found")
socketsPath = "/run/docker/plugins"
specsPaths = []string{"/etc/docker/plugins", "/usr/lib/docker/plugins"}
) )
type Registry interface { type Registry interface {
@ -22,41 +22,39 @@ type Registry interface {
Plugin(name string) (*Plugin, error) Plugin(name string) (*Plugin, error)
} }
type LocalRegistry struct { type LocalRegistry struct{}
path string
}
func newLocalRegistry(path string) *LocalRegistry { func newLocalRegistry() LocalRegistry {
if len(path) == 0 { return LocalRegistry{}
path = defaultLocalRegistry
}
return &LocalRegistry{path}
} }
func (l *LocalRegistry) Plugin(name string) (*Plugin, error) { func (l *LocalRegistry) Plugin(name string) (*Plugin, error) {
filepath := filepath.Join(l.path, name) socketpaths := pluginPaths(socketsPath, name, ".sock")
specpath := filepath + ".spec"
if fi, err := os.Stat(specpath); err == nil { for _, p := range socketpaths {
return readPluginSpecInfo(specpath, fi) if fi, err := os.Stat(p); err == nil && fi.Mode()&os.ModeSocket != 0 {
return newLocalPlugin(name, "unix://"+p), nil
}
} }
socketpath := filepath + ".sock" var txtspecpaths []string
if fi, err := os.Stat(socketpath); err == nil { for _, p := range specsPaths {
return readPluginSocketInfo(socketpath, fi) txtspecpaths = append(txtspecpaths, pluginPaths(p, name, ".spec")...)
txtspecpaths = append(txtspecpaths, pluginPaths(p, name, ".json")...)
} }
jsonpath := filepath + ".json" for _, p := range txtspecpaths {
if _, err := os.Stat(jsonpath); err == nil { if _, err := os.Stat(p); err == nil {
return readPluginJSONInfo(name, jsonpath) if strings.HasSuffix(p, ".json") {
return readPluginJSONInfo(name, p)
}
return readPluginInfo(name, p)
}
} }
return nil, ErrNotFound return nil, ErrNotFound
} }
func readPluginSpecInfo(path string, fi os.FileInfo) (*Plugin, error) { func readPluginInfo(name, path string) (*Plugin, error) {
name := strings.Split(fi.Name(), ".")[0]
content, err := ioutil.ReadFile(path) content, err := ioutil.ReadFile(path)
if err != nil { if err != nil {
return nil, err return nil, err
@ -75,16 +73,6 @@ func readPluginSpecInfo(path string, fi os.FileInfo) (*Plugin, error) {
return newLocalPlugin(name, addr), nil return newLocalPlugin(name, addr), nil
} }
func readPluginSocketInfo(path string, fi os.FileInfo) (*Plugin, error) {
name := strings.Split(fi.Name(), ".")[0]
if fi.Mode()&os.ModeSocket == 0 {
return nil, fmt.Errorf("%s is not a socket", path)
}
return newLocalPlugin(name, "unix://"+path), nil
}
func readPluginJSONInfo(name, path string) (*Plugin, error) { func readPluginJSONInfo(name, path string) (*Plugin, error) {
f, err := os.Open(path) f, err := os.Open(path)
if err != nil { if err != nil {
@ -103,3 +91,10 @@ func readPluginJSONInfo(name, path string) (*Plugin, error) {
return &p, nil return &p, nil
} }
func pluginPaths(base, name, ext string) []string {
return []string{
filepath.Join(base, name+ext),
filepath.Join(base, name, name+ext),
}
}

View file

@ -10,33 +10,41 @@ import (
"testing" "testing"
) )
func TestUnknownLocalPath(t *testing.T) { func setup(t *testing.T) (string, func()) {
tmpdir, err := ioutil.TempDir("", "docker-test") tmpdir, err := ioutil.TempDir("", "docker-test")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer os.RemoveAll(tmpdir) backup := socketsPath
socketsPath = tmpdir
specsPaths = []string{tmpdir}
l := newLocalRegistry(filepath.Join(tmpdir, "unknown")) return tmpdir, func() {
_, err = l.Plugin("foo") socketsPath = backup
if err == nil || err != ErrNotFound { os.RemoveAll(tmpdir)
t.Fatalf("Expected error for unknown directory")
} }
} }
func TestLocalSocket(t *testing.T) { func TestLocalSocket(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "docker-test") tmpdir, unregister := setup(t)
if err != nil { defer unregister()
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
l, err := net.Listen("unix", filepath.Join(tmpdir, "echo.sock"))
if err != nil {
t.Fatal(err)
}
defer l.Close()
r := newLocalRegistry(tmpdir) cases := []string{
filepath.Join(tmpdir, "echo.sock"),
filepath.Join(tmpdir, "echo", "echo.sock"),
}
for _, c := range cases {
if err := os.MkdirAll(filepath.Dir(c), 0755); err != nil {
t.Fatal(err)
}
l, err := net.Listen("unix", c)
if err != nil {
t.Fatal(err)
}
r := newLocalRegistry()
p, err := r.Plugin("echo") p, err := r.Plugin("echo")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -54,18 +62,20 @@ func TestLocalSocket(t *testing.T) {
t.Fatalf("Expected plugin `echo`, got %s\n", p.Name) t.Fatalf("Expected plugin `echo`, got %s\n", p.Name)
} }
addr := fmt.Sprintf("unix://%s/echo.sock", tmpdir) addr := fmt.Sprintf("unix://%s", c)
if p.Addr != addr { if p.Addr != addr {
t.Fatalf("Expected plugin addr `%s`, got %s\n", addr, p.Addr) t.Fatalf("Expected plugin addr `%s`, got %s\n", addr, p.Addr)
} }
if p.TLSConfig.InsecureSkipVerify != true {
t.Fatalf("Expected TLS verification to be skipped")
}
l.Close()
}
} }
func TestFileSpecPlugin(t *testing.T) { func TestFileSpecPlugin(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "docker-test-") tmpdir, unregister := setup(t)
if err != nil { defer unregister()
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
cases := []struct { cases := []struct {
path string path string
@ -74,16 +84,21 @@ func TestFileSpecPlugin(t *testing.T) {
fail bool fail bool
}{ }{
{filepath.Join(tmpdir, "echo.spec"), "echo", "unix://var/lib/docker/plugins/echo.sock", false}, {filepath.Join(tmpdir, "echo.spec"), "echo", "unix://var/lib/docker/plugins/echo.sock", false},
{filepath.Join(tmpdir, "echo", "echo.spec"), "echo", "unix://var/lib/docker/plugins/echo.sock", false},
{filepath.Join(tmpdir, "foo.spec"), "foo", "tcp://localhost:8080", false}, {filepath.Join(tmpdir, "foo.spec"), "foo", "tcp://localhost:8080", false},
{filepath.Join(tmpdir, "foo", "foo.spec"), "foo", "tcp://localhost:8080", false},
{filepath.Join(tmpdir, "bar.spec"), "bar", "localhost:8080", true}, // unknown transport {filepath.Join(tmpdir, "bar.spec"), "bar", "localhost:8080", true}, // unknown transport
} }
for _, c := range cases { for _, c := range cases {
if err = ioutil.WriteFile(c.path, []byte(c.addr), 0644); err != nil { if err := os.MkdirAll(filepath.Dir(c.path), 0755); err != nil {
t.Fatal(err)
}
if err := ioutil.WriteFile(c.path, []byte(c.addr), 0644); err != nil {
t.Fatal(err) t.Fatal(err)
} }
r := newLocalRegistry(tmpdir) r := newLocalRegistry()
p, err := r.Plugin(c.name) p, err := r.Plugin(c.name)
if c.fail && err == nil { if c.fail && err == nil {
continue continue
@ -100,14 +115,16 @@ func TestFileSpecPlugin(t *testing.T) {
if p.Addr != c.addr { if p.Addr != c.addr {
t.Fatalf("Expected plugin addr `%s`, got %s\n", c.addr, p.Addr) t.Fatalf("Expected plugin addr `%s`, got %s\n", c.addr, p.Addr)
} }
if p.TLSConfig.InsecureSkipVerify != true {
t.Fatalf("Expected TLS verification to be skipped")
}
} }
} }
func TestFileJSONSpecPlugin(t *testing.T) { func TestFileJSONSpecPlugin(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "docker-test-") tmpdir, unregister := setup(t)
if err != nil { defer unregister()
t.Fatal(err)
}
p := filepath.Join(tmpdir, "example.json") p := filepath.Join(tmpdir, "example.json")
spec := `{ spec := `{
@ -120,11 +137,11 @@ func TestFileJSONSpecPlugin(t *testing.T) {
} }
}` }`
if err = ioutil.WriteFile(p, []byte(spec), 0644); err != nil { if err := ioutil.WriteFile(p, []byte(spec), 0644); err != nil {
t.Fatal(err) t.Fatal(err)
} }
r := newLocalRegistry(tmpdir) r := newLocalRegistry()
plugin, err := r.Plugin("example") plugin, err := r.Plugin("example")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)

View file

@ -68,7 +68,7 @@ func (p *Plugin) activate() error {
} }
func load(name string) (*Plugin, error) { func load(name string) (*Plugin, error) {
registry := newLocalRegistry("") registry := newLocalRegistry()
pl, err := registry.Plugin(name) pl, err := registry.Plugin(name)
if err != nil { if err != nil {
return nil, err return nil, err