Initial commit
This commit is contained in:
222
vendor/github.com/hyperhq/hypercli/pkg/plugins/plugins.go
generated
vendored
Normal file
222
vendor/github.com/hyperhq/hypercli/pkg/plugins/plugins.go
generated
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
// Package plugins provides structures and helper functions to manage Docker
|
||||
// plugins.
|
||||
//
|
||||
// Docker discovers plugins by looking for them in the plugin directory whenever
|
||||
// a user or container tries to use one by name. UNIX domain socket files must
|
||||
// be located under /run/docker/plugins, whereas spec files can be located
|
||||
// either under /etc/docker/plugins or /usr/lib/docker/plugins. This is handled
|
||||
// by the Registry interface, which lets you list all plugins or get a plugin by
|
||||
// its name if it exists.
|
||||
//
|
||||
// The plugins need to implement an HTTP server and bind this to the UNIX socket
|
||||
// or the address specified in the spec files.
|
||||
// A handshake is send at /Plugin.Activate, and plugins are expected to return
|
||||
// a Manifest with a list of of Docker subsystems which this plugin implements.
|
||||
//
|
||||
// In order to use a plugins, you can use the ``Get`` with the name of the
|
||||
// plugin and the subsystem it implements.
|
||||
//
|
||||
// plugin, err := plugins.Get("example", "VolumeDriver")
|
||||
// if err != nil {
|
||||
// return fmt.Errorf("Error looking up volume plugin example: %v", err)
|
||||
// }
|
||||
package plugins
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/go-connections/tlsconfig"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNotImplements is returned if the plugin does not implement the requested driver.
|
||||
ErrNotImplements = errors.New("Plugin does not implement the requested driver")
|
||||
)
|
||||
|
||||
type plugins struct {
|
||||
sync.Mutex
|
||||
plugins map[string]*Plugin
|
||||
}
|
||||
|
||||
var (
|
||||
storage = plugins{plugins: make(map[string]*Plugin)}
|
||||
extpointHandlers = make(map[string]func(string, *Client))
|
||||
)
|
||||
|
||||
// Manifest lists what a plugin implements.
|
||||
type Manifest struct {
|
||||
// List of subsystem the plugin implements.
|
||||
Implements []string
|
||||
}
|
||||
|
||||
// Plugin is the definition of a docker plugin.
|
||||
type Plugin struct {
|
||||
// Name of the plugin
|
||||
Name string `json:"-"`
|
||||
// Address of the plugin
|
||||
Addr string
|
||||
// TLS configuration of the plugin
|
||||
TLSConfig tlsconfig.Options
|
||||
// Client attached to the plugin
|
||||
Client *Client `json:"-"`
|
||||
// Manifest of the plugin (see above)
|
||||
Manifest *Manifest `json:"-"`
|
||||
|
||||
activatErr error
|
||||
activateOnce sync.Once
|
||||
}
|
||||
|
||||
func newLocalPlugin(name, addr string) *Plugin {
|
||||
return &Plugin{
|
||||
Name: name,
|
||||
Addr: addr,
|
||||
TLSConfig: tlsconfig.Options{InsecureSkipVerify: true},
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Plugin) activate() error {
|
||||
p.activateOnce.Do(func() {
|
||||
p.activatErr = p.activateWithLock()
|
||||
})
|
||||
return p.activatErr
|
||||
}
|
||||
|
||||
func (p *Plugin) activateWithLock() error {
|
||||
c, err := NewClient(p.Addr, p.TLSConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.Client = c
|
||||
|
||||
m := new(Manifest)
|
||||
if err = p.Client.Call("Plugin.Activate", nil, m); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.Manifest = m
|
||||
|
||||
for _, iface := range m.Implements {
|
||||
handler, handled := extpointHandlers[iface]
|
||||
if !handled {
|
||||
continue
|
||||
}
|
||||
handler(p.Name, p.Client)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Plugin) implements(kind string) bool {
|
||||
for _, driver := range p.Manifest.Implements {
|
||||
if driver == kind {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func load(name string) (*Plugin, error) {
|
||||
return loadWithRetry(name, true)
|
||||
}
|
||||
|
||||
func loadWithRetry(name string, retry bool) (*Plugin, error) {
|
||||
registry := newLocalRegistry()
|
||||
start := time.Now()
|
||||
|
||||
var retries int
|
||||
for {
|
||||
pl, err := registry.Plugin(name)
|
||||
if err != nil {
|
||||
if !retry {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
timeOff := backoff(retries)
|
||||
if abort(start, timeOff) {
|
||||
return nil, err
|
||||
}
|
||||
retries++
|
||||
logrus.Warnf("Unable to locate plugin: %s, retrying in %v", name, timeOff)
|
||||
time.Sleep(timeOff)
|
||||
continue
|
||||
}
|
||||
|
||||
storage.Lock()
|
||||
storage.plugins[name] = pl
|
||||
storage.Unlock()
|
||||
|
||||
err = pl.activate()
|
||||
|
||||
if err != nil {
|
||||
storage.Lock()
|
||||
delete(storage.plugins, name)
|
||||
storage.Unlock()
|
||||
}
|
||||
|
||||
return pl, err
|
||||
}
|
||||
}
|
||||
|
||||
func get(name string) (*Plugin, error) {
|
||||
storage.Lock()
|
||||
pl, ok := storage.plugins[name]
|
||||
storage.Unlock()
|
||||
if ok {
|
||||
return pl, pl.activate()
|
||||
}
|
||||
return load(name)
|
||||
}
|
||||
|
||||
// Get returns the plugin given the specified name and requested implementation.
|
||||
func Get(name, imp string) (*Plugin, error) {
|
||||
pl, err := get(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if pl.implements(imp) {
|
||||
logrus.Debugf("%s implements: %s", name, imp)
|
||||
return pl, nil
|
||||
}
|
||||
return nil, ErrNotImplements
|
||||
}
|
||||
|
||||
// Handle adds the specified function to the extpointHandlers.
|
||||
func Handle(iface string, fn func(string, *Client)) {
|
||||
extpointHandlers[iface] = fn
|
||||
}
|
||||
|
||||
// GetAll returns all the plugins for the specified implementation
|
||||
func GetAll(imp string) ([]*Plugin, error) {
|
||||
pluginNames, err := Scan()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
type plLoad struct {
|
||||
pl *Plugin
|
||||
err error
|
||||
}
|
||||
|
||||
chPl := make(chan plLoad, len(pluginNames))
|
||||
for _, name := range pluginNames {
|
||||
go func(name string) {
|
||||
pl, err := loadWithRetry(name, false)
|
||||
chPl <- plLoad{pl, err}
|
||||
}(name)
|
||||
}
|
||||
|
||||
var out []*Plugin
|
||||
for i := 0; i < len(pluginNames); i++ {
|
||||
pl := <-chPl
|
||||
if pl.err != nil {
|
||||
logrus.Error(err)
|
||||
continue
|
||||
}
|
||||
if pl.pl.implements(imp) {
|
||||
out = append(out, pl.pl)
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
Reference in New Issue
Block a user