1/* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15*/ 16 17package plugin 18 19import ( 20 "context" 21 "path/filepath" 22 23 "github.com/containerd/containerd/errdefs" 24 "github.com/containerd/containerd/events/exchange" 25 ocispec "github.com/opencontainers/image-spec/specs-go/v1" 26 "github.com/pkg/errors" 27) 28 29// InitContext is used for plugin inititalization 30type InitContext struct { 31 Context context.Context 32 Root string 33 State string 34 Config interface{} 35 Address string 36 Events *exchange.Exchange 37 38 Meta *Meta // plugins can fill in metadata at init. 39 40 plugins *Set 41} 42 43// NewContext returns a new plugin InitContext 44func NewContext(ctx context.Context, r *Registration, plugins *Set, root, state string) *InitContext { 45 return &InitContext{ 46 Context: ctx, 47 Root: filepath.Join(root, r.URI()), 48 State: filepath.Join(state, r.URI()), 49 Meta: &Meta{ 50 Exports: map[string]string{}, 51 }, 52 plugins: plugins, 53 } 54} 55 56// Get returns the first plugin by its type 57func (i *InitContext) Get(t Type) (interface{}, error) { 58 return i.plugins.Get(t) 59} 60 61// Meta contains information gathered from the registration and initialization 62// process. 63type Meta struct { 64 Platforms []ocispec.Platform // platforms supported by plugin 65 Exports map[string]string // values exported by plugin 66 Capabilities []string // feature switches for plugin 67} 68 69// Plugin represents an initialized plugin, used with an init context. 70type Plugin struct { 71 Registration *Registration // registration, as initialized 72 Config interface{} // config, as initialized 73 Meta *Meta 74 75 instance interface{} 76 err error // will be set if there was an error initializing the plugin 77} 78 79// Err returns the errors during initialization. 80// returns nil if not error was encountered 81func (p *Plugin) Err() error { 82 return p.err 83} 84 85// Instance returns the instance and any initialization error of the plugin 86func (p *Plugin) Instance() (interface{}, error) { 87 return p.instance, p.err 88} 89 90// Set defines a plugin collection, used with InitContext. 91// 92// This maintains ordering and unique indexing over the set. 93// 94// After iteratively instantiating plugins, this set should represent, the 95// ordered, initialization set of plugins for a containerd instance. 96type Set struct { 97 ordered []*Plugin // order of initialization 98 byTypeAndID map[Type]map[string]*Plugin 99} 100 101// NewPluginSet returns an initialized plugin set 102func NewPluginSet() *Set { 103 return &Set{ 104 byTypeAndID: make(map[Type]map[string]*Plugin), 105 } 106} 107 108// Add a plugin to the set 109func (ps *Set) Add(p *Plugin) error { 110 if byID, typeok := ps.byTypeAndID[p.Registration.Type]; !typeok { 111 ps.byTypeAndID[p.Registration.Type] = map[string]*Plugin{ 112 p.Registration.ID: p, 113 } 114 } else if _, idok := byID[p.Registration.ID]; !idok { 115 byID[p.Registration.ID] = p 116 } else { 117 return errors.Wrapf(errdefs.ErrAlreadyExists, "plugin %v already initialized", p.Registration.URI()) 118 } 119 120 ps.ordered = append(ps.ordered, p) 121 return nil 122} 123 124// Get returns the first plugin by its type 125func (ps *Set) Get(t Type) (interface{}, error) { 126 for _, v := range ps.byTypeAndID[t] { 127 return v.Instance() 128 } 129 return nil, errors.Wrapf(errdefs.ErrNotFound, "no plugins registered for %s", t) 130} 131 132// GetAll plugins in the set 133func (i *InitContext) GetAll() []*Plugin { 134 return i.plugins.ordered 135} 136 137// GetByType returns all plugins with the specific type. 138func (i *InitContext) GetByType(t Type) (map[string]*Plugin, error) { 139 p, ok := i.plugins.byTypeAndID[t] 140 if !ok { 141 return nil, errors.Wrapf(errdefs.ErrNotFound, "no plugins registered for %s", t) 142 } 143 144 return p, nil 145} 146