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 }