github.com/containerd/Containerd@v1.4.13/plugin/context.go (about)

     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  
    17  package plugin
    18  
    19  import (
    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
    30  type InitContext struct {
    31  	Context      context.Context
    32  	Root         string
    33  	State        string
    34  	Config       interface{}
    35  	Address      string
    36  	TTRPCAddress string
    37  	Events       *exchange.Exchange
    38  
    39  	Meta *Meta // plugins can fill in metadata at init.
    40  
    41  	plugins *Set
    42  }
    43  
    44  // NewContext returns a new plugin InitContext
    45  func NewContext(ctx context.Context, r *Registration, plugins *Set, root, state string) *InitContext {
    46  	return &InitContext{
    47  		Context: ctx,
    48  		Root:    filepath.Join(root, r.URI()),
    49  		State:   filepath.Join(state, r.URI()),
    50  		Meta: &Meta{
    51  			Exports: map[string]string{},
    52  		},
    53  		plugins: plugins,
    54  	}
    55  }
    56  
    57  // Get returns the first plugin by its type
    58  func (i *InitContext) Get(t Type) (interface{}, error) {
    59  	return i.plugins.Get(t)
    60  }
    61  
    62  // Meta contains information gathered from the registration and initialization
    63  // process.
    64  type Meta struct {
    65  	Platforms    []ocispec.Platform // platforms supported by plugin
    66  	Exports      map[string]string  // values exported by plugin
    67  	Capabilities []string           // feature switches for plugin
    68  }
    69  
    70  // Plugin represents an initialized plugin, used with an init context.
    71  type Plugin struct {
    72  	Registration *Registration // registration, as initialized
    73  	Config       interface{}   // config, as initialized
    74  	Meta         *Meta
    75  
    76  	instance interface{}
    77  	err      error // will be set if there was an error initializing the plugin
    78  }
    79  
    80  // Err returns the errors during initialization.
    81  // returns nil if not error was encountered
    82  func (p *Plugin) Err() error {
    83  	return p.err
    84  }
    85  
    86  // Instance returns the instance and any initialization error of the plugin
    87  func (p *Plugin) Instance() (interface{}, error) {
    88  	return p.instance, p.err
    89  }
    90  
    91  // Set defines a plugin collection, used with InitContext.
    92  //
    93  // This maintains ordering and unique indexing over the set.
    94  //
    95  // After iteratively instantiating plugins, this set should represent, the
    96  // ordered, initialization set of plugins for a containerd instance.
    97  type Set struct {
    98  	ordered     []*Plugin // order of initialization
    99  	byTypeAndID map[Type]map[string]*Plugin
   100  }
   101  
   102  // NewPluginSet returns an initialized plugin set
   103  func NewPluginSet() *Set {
   104  	return &Set{
   105  		byTypeAndID: make(map[Type]map[string]*Plugin),
   106  	}
   107  }
   108  
   109  // Add a plugin to the set
   110  func (ps *Set) Add(p *Plugin) error {
   111  	if byID, typeok := ps.byTypeAndID[p.Registration.Type]; !typeok {
   112  		ps.byTypeAndID[p.Registration.Type] = map[string]*Plugin{
   113  			p.Registration.ID: p,
   114  		}
   115  	} else if _, idok := byID[p.Registration.ID]; !idok {
   116  		byID[p.Registration.ID] = p
   117  	} else {
   118  		return errors.Wrapf(errdefs.ErrAlreadyExists, "plugin %v already initialized", p.Registration.URI())
   119  	}
   120  
   121  	ps.ordered = append(ps.ordered, p)
   122  	return nil
   123  }
   124  
   125  // Get returns the first plugin by its type
   126  func (ps *Set) Get(t Type) (interface{}, error) {
   127  	for _, v := range ps.byTypeAndID[t] {
   128  		return v.Instance()
   129  	}
   130  	return nil, errors.Wrapf(errdefs.ErrNotFound, "no plugins registered for %s", t)
   131  }
   132  
   133  // GetAll plugins in the set
   134  func (i *InitContext) GetAll() []*Plugin {
   135  	return i.plugins.ordered
   136  }
   137  
   138  // GetByType returns all plugins with the specific type.
   139  func (i *InitContext) GetByType(t Type) (map[string]*Plugin, error) {
   140  	p, ok := i.plugins.byTypeAndID[t]
   141  	if !ok {
   142  		return nil, errors.Wrapf(errdefs.ErrNotFound, "no plugins registered for %s", t)
   143  	}
   144  
   145  	return p, nil
   146  }