containerd/plugin/plugin.go
Derek McGowan 3db8adc5d7
Update plugin load and snapshot service
Allow plugins to be mapped and returned by their ID.
Add skip plugin to allow plugins to decide whether they should
be loaded.

Signed-off-by: Derek McGowan <derek@mcgstyle.net>
2017-06-29 16:16:26 -07:00

114 lines
2.3 KiB
Go

package plugin
import (
"fmt"
"sync"
"github.com/pkg/errors"
"google.golang.org/grpc"
)
var (
ErrNoPluginType = errors.New("plugin: no type")
ErrNoPluginID = errors.New("plugin: no id")
// SkipPlugin is used when a plugin is not initialized and should not be loaded,
// this allows the plugin loader differentiate between a plugin which is configured
// not to load and one that fails to load.
SkipPlugin = errors.New("skip plugin")
)
// IsSkipPlugin returns true if the error is skipping the plugin
func IsSkipPlugin(err error) bool {
if errors.Cause(err) == SkipPlugin {
return true
}
return false
}
type PluginType string
const (
RuntimePlugin PluginType = "io.containerd.runtime.v1"
GRPCPlugin PluginType = "io.containerd.grpc.v1"
SnapshotPlugin PluginType = "io.containerd.snapshotter.v1"
TaskMonitorPlugin PluginType = "io.containerd.monitor.v1"
DiffPlugin PluginType = "io.containerd.differ.v1"
MetadataPlugin PluginType = "io.containerd.metadata.v1"
ContentPlugin PluginType = "io.containerd.content.v1"
)
type Registration struct {
Type PluginType
ID string
Config interface{}
Requires []PluginType
Init func(*InitContext) (interface{}, error)
added bool
}
func (r *Registration) URI() string {
return fmt.Sprintf("%s.%s", r.Type, r.ID)
}
type Service interface {
Register(*grpc.Server) error
}
var register = struct {
sync.Mutex
r []*Registration
}{}
// Load loads all plugins at the provided path into containerd
func Load(path string) (err error) {
defer func() {
if v := recover(); v != nil {
rerr, ok := v.(error)
if !ok {
rerr = fmt.Errorf("%s", v)
}
err = rerr
}
}()
return loadPlugins(path)
}
func Register(r *Registration) {
register.Lock()
defer register.Unlock()
if r.Type == "" {
panic(ErrNoPluginType)
}
if r.ID == "" {
panic(ErrNoPluginID)
}
register.r = append(register.r, r)
}
func Graph() (ordered []*Registration) {
for _, r := range register.r {
children(r.Requires, &ordered)
if !r.added {
ordered = append(ordered, r)
r.added = true
}
}
return ordered
}
func children(types []PluginType, ordered *[]*Registration) {
for _, t := range types {
for _, r := range register.r {
if r.Type == t {
children(r.Requires, ordered)
if !r.added {
*ordered = append(*ordered, r)
r.added = true
}
}
}
}
}