 3db8adc5d7
			
		
	
	3db8adc5d7
	
	
	
		
			
			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>
		
			
				
	
	
		
			114 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			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
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 |