github.com/rsampaio/docker@v0.7.2-0.20150827203920-fdc73cc3fc31/pkg/plugins/plugins.go (about)

     1  // Package plugins provides structures and helper functions to manage Docker
     2  // plugins.
     3  //
     4  // Docker discovers plugins by looking for them in the plugin directory whenever
     5  // a user or container tries to use one by name. UNIX domain socket files must
     6  // be located under /run/docker/plugins, whereas spec files can be located
     7  // either under /etc/docker/plugins or /usr/lib/docker/plugins. This is handled
     8  // by the Registry interface, which lets you list all plugins or get a plugin by
     9  // its name if it exists.
    10  //
    11  // The plugins need to implement an HTTP server and bind this to the UNIX socket
    12  // or the address specified in the spec files.
    13  // A handshake is send at /Plugin.Activate, and plugins are expected to return
    14  // a Manifest with a list of of Docker subsystems which this plugin implements.
    15  //
    16  // In order to use a plugins, you can use the ``Get`` with the name of the
    17  // plugin and the subsystem it implements.
    18  //
    19  //	plugin, err := plugins.Get("example", "VolumeDriver")
    20  //	if err != nil {
    21  //		return fmt.Errorf("Error looking up volume plugin example: %v", err)
    22  //	}
    23  package plugins
    24  
    25  import (
    26  	"errors"
    27  	"sync"
    28  
    29  	"github.com/Sirupsen/logrus"
    30  	"github.com/docker/docker/pkg/tlsconfig"
    31  )
    32  
    33  var (
    34  	// ErrNotImplements is returned if the plugin does not implement the requested driver.
    35  	ErrNotImplements = errors.New("Plugin does not implement the requested driver")
    36  )
    37  
    38  type plugins struct {
    39  	sync.Mutex
    40  	plugins map[string]*Plugin
    41  }
    42  
    43  var (
    44  	storage          = plugins{plugins: make(map[string]*Plugin)}
    45  	extpointHandlers = make(map[string]func(string, *Client))
    46  )
    47  
    48  // Manifest lists what a plugin implements.
    49  type Manifest struct {
    50  	// List of subsystem the plugin implements.
    51  	Implements []string
    52  }
    53  
    54  // Plugin is the definition of a docker plugin.
    55  type Plugin struct {
    56  	// Name of the plugin
    57  	Name string `json:"-"`
    58  	// Address of the plugin
    59  	Addr string
    60  	// TLS configuration of the plugin
    61  	TLSConfig tlsconfig.Options
    62  	// Client attached to the plugin
    63  	Client *Client `json:"-"`
    64  	// Manifest of the plugin (see above)
    65  	Manifest *Manifest `json:"-"`
    66  
    67  	activatErr   error
    68  	activateOnce sync.Once
    69  }
    70  
    71  func newLocalPlugin(name, addr string) *Plugin {
    72  	return &Plugin{
    73  		Name:      name,
    74  		Addr:      addr,
    75  		TLSConfig: tlsconfig.Options{InsecureSkipVerify: true},
    76  	}
    77  }
    78  
    79  func (p *Plugin) activate() error {
    80  	p.activateOnce.Do(func() {
    81  		p.activatErr = p.activateWithLock()
    82  	})
    83  	return p.activatErr
    84  }
    85  
    86  func (p *Plugin) activateWithLock() error {
    87  	c, err := NewClient(p.Addr, p.TLSConfig)
    88  	if err != nil {
    89  		return err
    90  	}
    91  	p.Client = c
    92  
    93  	m := new(Manifest)
    94  	if err = p.Client.Call("Plugin.Activate", nil, m); err != nil {
    95  		return err
    96  	}
    97  
    98  	logrus.Debugf("%s's manifest: %v", p.Name, m)
    99  	p.Manifest = m
   100  
   101  	for _, iface := range m.Implements {
   102  		handler, handled := extpointHandlers[iface]
   103  		if !handled {
   104  			continue
   105  		}
   106  		handler(p.Name, p.Client)
   107  	}
   108  	return nil
   109  }
   110  
   111  func load(name string) (*Plugin, error) {
   112  	storage.Lock()
   113  	registry := newLocalRegistry()
   114  	pl, err := registry.Plugin(name)
   115  	if err == nil {
   116  		storage.plugins[name] = pl
   117  	}
   118  	storage.Unlock()
   119  
   120  	if err != nil {
   121  		return nil, err
   122  	}
   123  
   124  	err = pl.activate()
   125  
   126  	if err != nil {
   127  		storage.Lock()
   128  		delete(storage.plugins, name)
   129  		storage.Unlock()
   130  	}
   131  
   132  	return pl, err
   133  }
   134  
   135  func get(name string) (*Plugin, error) {
   136  	storage.Lock()
   137  	pl, ok := storage.plugins[name]
   138  	storage.Unlock()
   139  	if ok {
   140  		return pl, pl.activate()
   141  	}
   142  	return load(name)
   143  }
   144  
   145  // Get returns the plugin given the specified name and requested implementation.
   146  func Get(name, imp string) (*Plugin, error) {
   147  	pl, err := get(name)
   148  	if err != nil {
   149  		return nil, err
   150  	}
   151  	for _, driver := range pl.Manifest.Implements {
   152  		logrus.Debugf("%s implements: %s", name, driver)
   153  		if driver == imp {
   154  			return pl, nil
   155  		}
   156  	}
   157  	return nil, ErrNotImplements
   158  }
   159  
   160  // Handle adds the specified function to the extpointHandlers.
   161  func Handle(iface string, fn func(string, *Client)) {
   162  	extpointHandlers[iface] = fn
   163  }