Signed-off-by: haoyun <yun.hao@daocloud.io> Co-authored-by: zounengren <zouyee1989@gmail.com>
		
			
				
	
	
		
			162 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			162 lines
		
	
	
		
			4.5 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 not 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 plugins in the set
 | 
						|
func (i *InitContext) GetAll() []*Plugin {
 | 
						|
	return i.plugins.ordered
 | 
						|
}
 | 
						|
 | 
						|
// 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
 | 
						|
}
 |