This patches avoids registering (and calling) the same plugin more than
once. Using an helper map which indexes by name guarantees this and keeps
the order.
The behavior of overriding the same name in a flag is consistent with,
for instance, the `docker run -v /test -v /test` flag which register
the volume just once.
Adds integration tests.
Without this patch:
```
Dec 20 19:34:52 localhost.localdomain docker[9988]:
time="2015-12-20T19:34:52.080901676+01:00" level=debug msg="Calling
GET
/v1.22/info"
Dec 20 19:34:52 localhost.localdomain docker[9988]:
time="2015-12-20T19:34:52.081213202+01:00" level=debug msg="AuthZ
request using plugin docker-novolume-plugin"
Dec 20 19:34:52 localhost.localdomain docker[9988]:
time="2015-12-20T19:34:52.081268132+01:00" level=debug
msg="docker-novolume-plugin implements: authz"
Dec 20 19:34:52 localhost.localdomain docker[9988]:
time="2015-12-20T19:34:52.081699788+01:00" level=debug msg="AuthZ
request using plugin docker-novolume-plugin"
Dec 20 19:34:52 localhost.localdomain docker[9988]:
time="2015-12-20T19:34:52.081762507+01:00" level=debug
msg="docker-novolume-plugin implements: authz"
Dec 20 19:34:52 localhost.localdomain docker[9988]:
time="2015-12-20T19:34:52.082092480+01:00" level=debug msg="GET
/v1.22/info"
Dec 20 19:34:52 localhost.localdomain docker[9988]:
time="2015-12-20T19:34:52.628691038+01:00" level=debug msg="AuthZ
response using plugin docker-novolume-plugin"
Dec 20 19:34:52 localhost.localdomain docker[9988]:
time="2015-12-20T19:34:52.629880930+01:00" level=debug msg="AuthZ
response using plugin docker-novolume-plugin"
```
With this patch:
```
Dec 20 19:37:32 localhost.localdomain docker[16620]:
time="2015-12-20T19:37:32.376523958+01:00" level=debug msg="Calling
GET
/v1.22/info"
Dec 20 19:37:32 localhost.localdomain docker[16620]:
time="2015-12-20T19:37:32.376715483+01:00" level=debug msg="AuthZ
request using plugin docker-novolume-plugin"
Dec 20 19:37:32 localhost.localdomain docker[16620]:
time="2015-12-20T19:37:32.376771230+01:00" level=debug
msg="docker-novolume-plugin implements: authz"
Dec 20 19:37:32 localhost.localdomain docker[16620]:
time="2015-12-20T19:37:32.377698897+01:00" level=debug msg="GET
/v1.22/info"
Dec 20 19:37:32 localhost.localdomain docker[16620]:
time="2015-12-20T19:37:32.951016441+01:00" level=debug msg="AuthZ
response using plugin docker-novolume-plugin"
```
Also removes a somehow duplicate debug statement (leaving only the
second one as it's a loop of plugin's manifest):
```
Dec 20 19:52:30 localhost.localdomain docker[25767]:
time="2015-12-20T19:52:30.544090518+01:00" level=debug
msg="docker-novolume-plugin's manifest: &{[authz]}"
Dec 20 19:52:30 localhost.localdomain docker[25767]:
time="2015-12-20T19:52:30.544170677+01:00" level=debug
msg="docker-novolume-plugin implements: authz"
```
Signed-off-by: Antonio Murdaca <runcom@redhat.com>
Upstream-commit: c28fc06e002e06deed3437da76bc213b7bd752ba
Component: engine
99 lines
2.1 KiB
Go
99 lines
2.1 KiB
Go
package plugins
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/url"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
var (
|
|
// ErrNotFound plugin not found
|
|
ErrNotFound = errors.New("plugin not found")
|
|
socketsPath = "/run/docker/plugins"
|
|
specsPaths = []string{"/etc/docker/plugins", "/usr/lib/docker/plugins"}
|
|
)
|
|
|
|
// localRegistry defines a registry that is local (using unix socket).
|
|
type localRegistry struct{}
|
|
|
|
func newLocalRegistry() localRegistry {
|
|
return localRegistry{}
|
|
}
|
|
|
|
// 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")
|
|
|
|
for _, p := range socketpaths {
|
|
if fi, err := os.Stat(p); err == nil && fi.Mode()&os.ModeSocket != 0 {
|
|
return newLocalPlugin(name, "unix://"+p), nil
|
|
}
|
|
}
|
|
|
|
var txtspecpaths []string
|
|
for _, p := range specsPaths {
|
|
txtspecpaths = append(txtspecpaths, pluginPaths(p, name, ".spec")...)
|
|
txtspecpaths = append(txtspecpaths, pluginPaths(p, name, ".json")...)
|
|
}
|
|
|
|
for _, p := range txtspecpaths {
|
|
if _, err := os.Stat(p); err == nil {
|
|
if strings.HasSuffix(p, ".json") {
|
|
return readPluginJSONInfo(name, p)
|
|
}
|
|
return readPluginInfo(name, p)
|
|
}
|
|
}
|
|
return nil, ErrNotFound
|
|
}
|
|
|
|
func readPluginInfo(name, path string) (*Plugin, error) {
|
|
content, err := ioutil.ReadFile(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
addr := strings.TrimSpace(string(content))
|
|
|
|
u, err := url.Parse(addr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(u.Scheme) == 0 {
|
|
return nil, fmt.Errorf("Unknown protocol")
|
|
}
|
|
|
|
return newLocalPlugin(name, addr), nil
|
|
}
|
|
|
|
func readPluginJSONInfo(name, path string) (*Plugin, error) {
|
|
f, err := os.Open(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer f.Close()
|
|
|
|
var p Plugin
|
|
if err := json.NewDecoder(f).Decode(&p); err != nil {
|
|
return nil, err
|
|
}
|
|
p.Name = name
|
|
if len(p.TLSConfig.CAFile) == 0 {
|
|
p.TLSConfig.InsecureSkipVerify = true
|
|
}
|
|
|
|
return &p, nil
|
|
}
|
|
|
|
func pluginPaths(base, name, ext string) []string {
|
|
return []string{
|
|
filepath.Join(base, name+ext),
|
|
filepath.Join(base, name, name+ext),
|
|
}
|
|
}
|