172 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			172 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| /*
 | |
|    Copyright The containerd Authors.
 | |
| 
 | |
|    Licensed under the Apache License, Version 2.0 (the "License");
 | |
|    you may not use this file except in compliance with the License.
 | |
|    You may obtain a copy of the License at
 | |
| 
 | |
|        http://www.apache.org/licenses/LICENSE-2.0
 | |
| 
 | |
|    Unless required by applicable law or agreed to in writing, software
 | |
|    distributed under the License is distributed on an "AS IS" BASIS,
 | |
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|    See the License for the specific language governing permissions and
 | |
|    limitations under the License.
 | |
| */
 | |
| 
 | |
| package plugin
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"fmt"
 | |
| 	"path/filepath"
 | |
| 
 | |
| 	"github.com/containerd/containerd/errdefs"
 | |
| 	"github.com/containerd/containerd/events/exchange"
 | |
| 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 | |
| )
 | |
| 
 | |
| // InitContext is used for plugin initialization
 | |
| type InitContext struct {
 | |
| 	Context      context.Context
 | |
| 	Root         string
 | |
| 	State        string
 | |
| 	Config       interface{}
 | |
| 	Address      string
 | |
| 	TTRPCAddress string
 | |
| 
 | |
| 	// deprecated: will be removed in 2.0, use plugin.EventType
 | |
| 	Events *exchange.Exchange
 | |
| 
 | |
| 	Meta *Meta // plugins can fill in metadata at init.
 | |
| 
 | |
| 	plugins *Set
 | |
| }
 | |
| 
 | |
| // NewContext returns a new plugin InitContext
 | |
| func NewContext(ctx context.Context, r *Registration, plugins *Set, root, state string) *InitContext {
 | |
| 	return &InitContext{
 | |
| 		Context: ctx,
 | |
| 		Root:    filepath.Join(root, r.URI()),
 | |
| 		State:   filepath.Join(state, r.URI()),
 | |
| 		Meta: &Meta{
 | |
| 			Exports: map[string]string{},
 | |
| 		},
 | |
| 		plugins: plugins,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Get returns the first plugin by its type
 | |
| func (i *InitContext) Get(t Type) (interface{}, error) {
 | |
| 	return i.plugins.Get(t)
 | |
| }
 | |
| 
 | |
| // Meta contains information gathered from the registration and initialization
 | |
| // process.
 | |
| type Meta struct {
 | |
| 	Platforms    []ocispec.Platform // platforms supported by plugin
 | |
| 	Exports      map[string]string  // values exported by plugin
 | |
| 	Capabilities []string           // feature switches for plugin
 | |
| }
 | |
| 
 | |
| // Plugin represents an initialized plugin, used with an init context.
 | |
| type Plugin struct {
 | |
| 	Registration *Registration // registration, as initialized
 | |
| 	Config       interface{}   // config, as initialized
 | |
| 	Meta         *Meta
 | |
| 
 | |
| 	instance interface{}
 | |
| 	err      error // will be set if there was an error initializing the plugin
 | |
| }
 | |
| 
 | |
| // Err returns the errors during initialization.
 | |
| // returns nil if no error was encountered
 | |
| func (p *Plugin) Err() error {
 | |
| 	return p.err
 | |
| }
 | |
| 
 | |
| // Instance returns the instance and any initialization error of the plugin
 | |
| func (p *Plugin) Instance() (interface{}, error) {
 | |
| 	return p.instance, p.err
 | |
| }
 | |
| 
 | |
| // Set defines a plugin collection, used with InitContext.
 | |
| //
 | |
| // This maintains ordering and unique indexing over the set.
 | |
| //
 | |
| // After iteratively instantiating plugins, this set should represent, the
 | |
| // ordered, initialization set of plugins for a containerd instance.
 | |
| type Set struct {
 | |
| 	ordered     []*Plugin // order of initialization
 | |
| 	byTypeAndID map[Type]map[string]*Plugin
 | |
| }
 | |
| 
 | |
| // NewPluginSet returns an initialized plugin set
 | |
| func NewPluginSet() *Set {
 | |
| 	return &Set{
 | |
| 		byTypeAndID: make(map[Type]map[string]*Plugin),
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Add a plugin to the set
 | |
| func (ps *Set) Add(p *Plugin) error {
 | |
| 	if byID, typeok := ps.byTypeAndID[p.Registration.Type]; !typeok {
 | |
| 		ps.byTypeAndID[p.Registration.Type] = map[string]*Plugin{
 | |
| 			p.Registration.ID: p,
 | |
| 		}
 | |
| 	} else if _, idok := byID[p.Registration.ID]; !idok {
 | |
| 		byID[p.Registration.ID] = p
 | |
| 	} else {
 | |
| 		return fmt.Errorf("plugin %v already initialized: %w", p.Registration.URI(), errdefs.ErrAlreadyExists)
 | |
| 	}
 | |
| 
 | |
| 	ps.ordered = append(ps.ordered, p)
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // Get returns the first plugin by its type
 | |
| func (ps *Set) Get(t Type) (interface{}, error) {
 | |
| 	for _, v := range ps.byTypeAndID[t] {
 | |
| 		return v.Instance()
 | |
| 	}
 | |
| 	return nil, fmt.Errorf("no plugins registered for %s: %w", t, errdefs.ErrNotFound)
 | |
| }
 | |
| 
 | |
| // GetAll returns all initialized plugins
 | |
| func (ps *Set) GetAll() []*Plugin {
 | |
| 	return ps.ordered
 | |
| }
 | |
| 
 | |
| // Plugins returns plugin set
 | |
| func (i *InitContext) Plugins() *Set {
 | |
| 	return i.plugins
 | |
| }
 | |
| 
 | |
| // GetAll plugins in the set
 | |
| func (i *InitContext) GetAll() []*Plugin {
 | |
| 	return i.plugins.GetAll()
 | |
| }
 | |
| 
 | |
| // GetByID returns the plugin of the given type and ID
 | |
| func (i *InitContext) GetByID(t Type, id string) (interface{}, error) {
 | |
| 	ps, err := i.GetByType(t)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	p, ok := ps[id]
 | |
| 	if !ok {
 | |
| 		return nil, fmt.Errorf("no %s plugins with id %s: %w", t, id, errdefs.ErrNotFound)
 | |
| 	}
 | |
| 	return p.Instance()
 | |
| }
 | |
| 
 | |
| // GetByType returns all plugins with the specific type.
 | |
| func (i *InitContext) GetByType(t Type) (map[string]*Plugin, error) {
 | |
| 	p, ok := i.plugins.byTypeAndID[t]
 | |
| 	if !ok {
 | |
| 		return nil, fmt.Errorf("no plugins registered for %s: %w", t, errdefs.ErrNotFound)
 | |
| 	}
 | |
| 
 | |
| 	return p, nil
 | |
| }
 | 
