Remove plugins package
Signed-off-by: Derek McGowan <derek@mcg.dev>
This commit is contained in:
parent
9db21401c4
commit
411e2bce49
@ -1,179 +0,0 @@
|
|||||||
/*
|
|
||||||
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"
|
|
||||||
|
|
||||||
imagespec "github.com/opencontainers/image-spec/specs-go/v1"
|
|
||||||
)
|
|
||||||
|
|
||||||
// InitContext is used for plugin initialization
|
|
||||||
type InitContext struct {
|
|
||||||
Context context.Context
|
|
||||||
Properties map[string]string
|
|
||||||
Config interface{}
|
|
||||||
RegisterReadiness func() func()
|
|
||||||
|
|
||||||
// Meta is metadata plugins can fill in at init
|
|
||||||
Meta *Meta
|
|
||||||
|
|
||||||
plugins *Set
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewContext returns a new plugin InitContext
|
|
||||||
func NewContext(ctx context.Context, plugins *Set, properties map[string]string) *InitContext {
|
|
||||||
if properties == nil {
|
|
||||||
properties = map[string]string{}
|
|
||||||
}
|
|
||||||
return &InitContext{
|
|
||||||
Context: ctx,
|
|
||||||
Properties: properties,
|
|
||||||
Meta: &Meta{
|
|
||||||
Exports: map[string]string{},
|
|
||||||
},
|
|
||||||
plugins: plugins,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSingle returns the first plugin by its type
|
|
||||||
func (i *InitContext) GetSingle(t Type) (interface{}, error) {
|
|
||||||
return i.plugins.Get(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Meta contains information gathered from the registration and initialization
|
|
||||||
// process.
|
|
||||||
type Meta struct {
|
|
||||||
Platforms []imagespec.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 add failed for %s: %w", p.Registration.URI(), ErrPluginInitialized)
|
|
||||||
}
|
|
||||||
|
|
||||||
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, ErrPluginNotFound)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetByID returns the plugin of the given type and ID
|
|
||||||
func (ps *Set) GetByID(t Type, id string) (*Plugin, error) {
|
|
||||||
typSet, ok := ps.byTypeAndID[t]
|
|
||||||
if !ok || len(typSet) == 0 {
|
|
||||||
return nil, fmt.Errorf("no plugins registered for %s: %w", t, ErrPluginNotFound)
|
|
||||||
}
|
|
||||||
p, ok := typSet[id]
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("no plugins registered for %s %q: %w", t, id, ErrPluginNotFound)
|
|
||||||
}
|
|
||||||
return p, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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, ErrPluginNotFound)
|
|
||||||
}
|
|
||||||
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, ErrPluginNotFound)
|
|
||||||
}
|
|
||||||
|
|
||||||
return p, nil
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
/*
|
|
||||||
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 dynamic
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
// Load loads all plugins at the provided path into containerd.
|
|
||||||
//
|
|
||||||
// Load is currently only implemented on non-static, non-gccgo builds for amd64
|
|
||||||
// and arm64, and plugins must be built with the exact same version of Go as
|
|
||||||
// containerd itself.
|
|
||||||
func Load(path string) (loaded int, 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)
|
|
||||||
}
|
|
@ -1,65 +0,0 @@
|
|||||||
//go:build (amd64 || arm64) && !static_build && !gccgo
|
|
||||||
|
|
||||||
/*
|
|
||||||
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 dynamic
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"path/filepath"
|
|
||||||
"plugin"
|
|
||||||
"runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
// loadPlugins loads all plugins for the OS and Arch that containerd is built
|
|
||||||
// for inside the provided path and returns the count of successfully-loaded
|
|
||||||
// plugins
|
|
||||||
func loadPlugins(path string) (int, error) {
|
|
||||||
abs, err := filepath.Abs(path)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
pattern := filepath.Join(abs, fmt.Sprintf(
|
|
||||||
"*-%s-%s.%s",
|
|
||||||
runtime.GOOS,
|
|
||||||
runtime.GOARCH,
|
|
||||||
getLibExt(),
|
|
||||||
))
|
|
||||||
libs, err := filepath.Glob(pattern)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
loaded := 0
|
|
||||||
for _, lib := range libs {
|
|
||||||
if _, err := plugin.Open(lib); err != nil {
|
|
||||||
return loaded, err
|
|
||||||
}
|
|
||||||
loaded++
|
|
||||||
}
|
|
||||||
return loaded, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getLibExt returns a platform specific lib extension for
|
|
||||||
// the platform that containerd is running on
|
|
||||||
func getLibExt() string {
|
|
||||||
switch runtime.GOOS {
|
|
||||||
case "windows":
|
|
||||||
return "dll"
|
|
||||||
default:
|
|
||||||
return "so"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
//go:build (!amd64 && !arm64) || static_build || gccgo
|
|
||||||
|
|
||||||
/*
|
|
||||||
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 dynamic
|
|
||||||
|
|
||||||
// loadPlugins is not supported;
|
|
||||||
//
|
|
||||||
// - with gccgo: gccgo has no plugin support golang/go#36403
|
|
||||||
// - on static builds; https://github.com/containerd/containerd/commit/0d682e24a1ba8e93e5e54a73d64f7d256f87492f
|
|
||||||
// - on architectures other than amd64 and arm64 (other architectures need to be tested)
|
|
||||||
func loadPlugins(path string) (int, error) {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
176
plugin/plugin.go
176
plugin/plugin.go
@ -1,176 +0,0 @@
|
|||||||
/*
|
|
||||||
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"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// ErrNoType is returned when no type is specified
|
|
||||||
ErrNoType = errors.New("plugin: no type")
|
|
||||||
// ErrNoPluginID is returned when no id is specified
|
|
||||||
ErrNoPluginID = errors.New("plugin: no id")
|
|
||||||
// ErrIDRegistered is returned when a duplicate id is already registered
|
|
||||||
ErrIDRegistered = errors.New("plugin: id already registered")
|
|
||||||
// ErrSkipPlugin 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.
|
|
||||||
ErrSkipPlugin = errors.New("skip plugin")
|
|
||||||
// ErrPluginInitialized is used when a plugin is already initialized
|
|
||||||
ErrPluginInitialized = errors.New("plugin: already initialized")
|
|
||||||
// ErrPluginNotFound is used when a plugin is looked up but not found
|
|
||||||
ErrPluginNotFound = errors.New("plugin: not found")
|
|
||||||
|
|
||||||
// ErrInvalidRequires will be thrown if the requirements for a plugin are
|
|
||||||
// defined in an invalid manner.
|
|
||||||
ErrInvalidRequires = errors.New("invalid requires")
|
|
||||||
)
|
|
||||||
|
|
||||||
// IsSkipPlugin returns true if the error is skipping the plugin
|
|
||||||
func IsSkipPlugin(err error) bool {
|
|
||||||
return errors.Is(err, ErrSkipPlugin)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type is the type of the plugin
|
|
||||||
type Type string
|
|
||||||
|
|
||||||
func (t Type) String() string { return string(t) }
|
|
||||||
|
|
||||||
// Registration contains information for registering a plugin
|
|
||||||
type Registration struct {
|
|
||||||
// Type of the plugin
|
|
||||||
Type Type
|
|
||||||
// ID of the plugin
|
|
||||||
ID string
|
|
||||||
// Config specific to the plugin
|
|
||||||
Config interface{}
|
|
||||||
// Requires is a list of plugins that the registered plugin requires to be available
|
|
||||||
Requires []Type
|
|
||||||
|
|
||||||
// InitFn is called when initializing a plugin. The registration and
|
|
||||||
// context are passed in. The init function may modify the registration to
|
|
||||||
// add exports, capabilities and platform support declarations.
|
|
||||||
InitFn func(*InitContext) (interface{}, error)
|
|
||||||
|
|
||||||
// ConfigMigration allows a plugin to migrate configurations from an older
|
|
||||||
// version to handle plugin renames or moving of features from one plugin
|
|
||||||
// to another in a later version.
|
|
||||||
// The configuration map is keyed off the plugin name and the value
|
|
||||||
// is the configuration for that objects, with the structure defined
|
|
||||||
// for the plugin. No validation is done on the value before performing
|
|
||||||
// the migration.
|
|
||||||
ConfigMigration func(context.Context, int, map[string]interface{}) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init the registered plugin
|
|
||||||
func (r Registration) Init(ic *InitContext) *Plugin {
|
|
||||||
p, err := r.InitFn(ic)
|
|
||||||
return &Plugin{
|
|
||||||
Registration: r,
|
|
||||||
Config: ic.Config,
|
|
||||||
Meta: *ic.Meta,
|
|
||||||
instance: p,
|
|
||||||
err: err,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// URI returns the full plugin URI
|
|
||||||
func (r *Registration) URI() string {
|
|
||||||
return r.Type.String() + "." + r.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
// DisableFilter filters out disabled plugins
|
|
||||||
type DisableFilter func(r *Registration) bool
|
|
||||||
|
|
||||||
// Registry is list of registrations which can be registered to and
|
|
||||||
// produce a filtered and ordered output.
|
|
||||||
// The Registry itself is immutable and the list will be copied
|
|
||||||
// and appeneded to a new registry when new items are registered.
|
|
||||||
type Registry []*Registration
|
|
||||||
|
|
||||||
// Graph computes the ordered list of registrations based on their dependencies,
|
|
||||||
// filtering out any plugins which match the provided filter.
|
|
||||||
func (registry Registry) Graph(filter DisableFilter) []Registration {
|
|
||||||
disabled := map[*Registration]bool{}
|
|
||||||
for _, r := range registry {
|
|
||||||
if filter(r) {
|
|
||||||
disabled[r] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ordered := make([]Registration, 0, len(registry)-len(disabled))
|
|
||||||
added := map[*Registration]bool{}
|
|
||||||
for _, r := range registry {
|
|
||||||
if disabled[r] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
children(r, registry, added, disabled, &ordered)
|
|
||||||
if !added[r] {
|
|
||||||
ordered = append(ordered, *r)
|
|
||||||
added[r] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ordered
|
|
||||||
}
|
|
||||||
|
|
||||||
func children(reg *Registration, registry []*Registration, added, disabled map[*Registration]bool, ordered *[]Registration) {
|
|
||||||
for _, t := range reg.Requires {
|
|
||||||
for _, r := range registry {
|
|
||||||
if !disabled[r] && r.URI() != reg.URI() && (t == "*" || r.Type == t) {
|
|
||||||
children(r, registry, added, disabled, ordered)
|
|
||||||
if !added[r] {
|
|
||||||
*ordered = append(*ordered, *r)
|
|
||||||
added[r] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register adds the registration to a Registry and returns the
|
|
||||||
// updated Registry, panicking if registration could not succeed.
|
|
||||||
func (registry Registry) Register(r *Registration) Registry {
|
|
||||||
if r.Type == "" {
|
|
||||||
panic(ErrNoType)
|
|
||||||
}
|
|
||||||
if r.ID == "" {
|
|
||||||
panic(ErrNoPluginID)
|
|
||||||
}
|
|
||||||
if err := checkUnique(registry, r); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, requires := range r.Requires {
|
|
||||||
if requires == "*" && len(r.Requires) != 1 {
|
|
||||||
panic(ErrInvalidRequires)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return append(registry, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkUnique(registry Registry, r *Registration) error {
|
|
||||||
for _, registered := range registry {
|
|
||||||
if r.URI() == registered.URI() {
|
|
||||||
return fmt.Errorf("%s: %w", r.URI(), ErrIDRegistered)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,381 +0,0 @@
|
|||||||
/*
|
|
||||||
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 (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/containerd/containerd/v2/services"
|
|
||||||
)
|
|
||||||
|
|
||||||
func mockPluginFilter(*Registration) bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestContainerdPlugin tests the logic of Graph, use the containerd's plugin
|
|
||||||
func TestContainerdPlugin(t *testing.T) {
|
|
||||||
// Plugin types commonly used by containerd
|
|
||||||
const (
|
|
||||||
InternalPlugin Type = "io.containerd.internal.v1"
|
|
||||||
RuntimePlugin Type = "io.containerd.runtime.v1"
|
|
||||||
RuntimePluginV2 Type = "io.containerd.runtime.v2"
|
|
||||||
ServicePlugin Type = "io.containerd.service.v1"
|
|
||||||
GRPCPlugin Type = "io.containerd.grpc.v1"
|
|
||||||
SnapshotPlugin Type = "io.containerd.snapshotter.v1"
|
|
||||||
TaskMonitorPlugin Type = "io.containerd.monitor.v1"
|
|
||||||
DiffPlugin Type = "io.containerd.differ.v1"
|
|
||||||
MetadataPlugin Type = "io.containerd.metadata.v1"
|
|
||||||
ContentPlugin Type = "io.containerd.content.v1"
|
|
||||||
GCPlugin Type = "io.containerd.gc.v1"
|
|
||||||
LeasePlugin Type = "io.containerd.lease.v1"
|
|
||||||
TracingProcessorPlugin Type = "io.containerd.tracing.processor.v1"
|
|
||||||
)
|
|
||||||
|
|
||||||
var register Registry
|
|
||||||
register = register.Register(&Registration{
|
|
||||||
Type: TaskMonitorPlugin,
|
|
||||||
ID: "cgroups",
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: ServicePlugin,
|
|
||||||
ID: services.TasksService,
|
|
||||||
Requires: []Type{
|
|
||||||
RuntimePlugin,
|
|
||||||
RuntimePluginV2,
|
|
||||||
MetadataPlugin,
|
|
||||||
TaskMonitorPlugin,
|
|
||||||
},
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: ServicePlugin,
|
|
||||||
ID: services.IntrospectionService,
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: ServicePlugin,
|
|
||||||
ID: services.NamespacesService,
|
|
||||||
Requires: []Type{
|
|
||||||
MetadataPlugin,
|
|
||||||
},
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: GRPCPlugin,
|
|
||||||
ID: "namespaces",
|
|
||||||
Requires: []Type{
|
|
||||||
ServicePlugin,
|
|
||||||
},
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: GRPCPlugin,
|
|
||||||
ID: "content",
|
|
||||||
Requires: []Type{
|
|
||||||
ServicePlugin,
|
|
||||||
},
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: GRPCPlugin,
|
|
||||||
ID: "containers",
|
|
||||||
Requires: []Type{
|
|
||||||
ServicePlugin,
|
|
||||||
},
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: ServicePlugin,
|
|
||||||
ID: services.ContainersService,
|
|
||||||
Requires: []Type{
|
|
||||||
MetadataPlugin,
|
|
||||||
},
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: GRPCPlugin,
|
|
||||||
ID: "events",
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: GRPCPlugin,
|
|
||||||
ID: "leases",
|
|
||||||
Requires: []Type{
|
|
||||||
LeasePlugin,
|
|
||||||
},
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: LeasePlugin,
|
|
||||||
ID: "manager",
|
|
||||||
Requires: []Type{
|
|
||||||
MetadataPlugin,
|
|
||||||
},
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: GRPCPlugin,
|
|
||||||
ID: "diff",
|
|
||||||
Requires: []Type{
|
|
||||||
ServicePlugin,
|
|
||||||
},
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: ServicePlugin,
|
|
||||||
ID: services.DiffService,
|
|
||||||
Requires: []Type{
|
|
||||||
DiffPlugin,
|
|
||||||
},
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: ServicePlugin,
|
|
||||||
ID: services.SnapshotsService,
|
|
||||||
Requires: []Type{
|
|
||||||
MetadataPlugin,
|
|
||||||
},
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: GRPCPlugin,
|
|
||||||
ID: "snapshots",
|
|
||||||
Requires: []Type{
|
|
||||||
ServicePlugin,
|
|
||||||
},
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: GRPCPlugin,
|
|
||||||
ID: "version",
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: GRPCPlugin,
|
|
||||||
ID: "images",
|
|
||||||
Requires: []Type{
|
|
||||||
ServicePlugin,
|
|
||||||
},
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: GCPlugin,
|
|
||||||
ID: "scheduler",
|
|
||||||
Requires: []Type{
|
|
||||||
MetadataPlugin,
|
|
||||||
},
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: RuntimePluginV2,
|
|
||||||
ID: "task",
|
|
||||||
Requires: []Type{
|
|
||||||
MetadataPlugin,
|
|
||||||
},
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: GRPCPlugin,
|
|
||||||
ID: "tasks",
|
|
||||||
Requires: []Type{
|
|
||||||
ServicePlugin,
|
|
||||||
},
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: GRPCPlugin,
|
|
||||||
ID: "introspection",
|
|
||||||
Requires: []Type{"*"},
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: ServicePlugin,
|
|
||||||
ID: services.ContentService,
|
|
||||||
Requires: []Type{
|
|
||||||
MetadataPlugin,
|
|
||||||
},
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: GRPCPlugin,
|
|
||||||
ID: "healthcheck",
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: InternalPlugin,
|
|
||||||
ID: "opt",
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: GRPCPlugin,
|
|
||||||
ID: "cri",
|
|
||||||
Requires: []Type{
|
|
||||||
ServicePlugin,
|
|
||||||
},
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: RuntimePlugin,
|
|
||||||
ID: "linux",
|
|
||||||
Requires: []Type{
|
|
||||||
MetadataPlugin,
|
|
||||||
},
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: InternalPlugin,
|
|
||||||
Requires: []Type{
|
|
||||||
ServicePlugin,
|
|
||||||
},
|
|
||||||
ID: "restart",
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: DiffPlugin,
|
|
||||||
ID: "walking",
|
|
||||||
Requires: []Type{
|
|
||||||
MetadataPlugin,
|
|
||||||
},
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: SnapshotPlugin,
|
|
||||||
ID: "native",
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: SnapshotPlugin,
|
|
||||||
ID: "overlayfs",
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: ContentPlugin,
|
|
||||||
ID: "content",
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: MetadataPlugin,
|
|
||||||
ID: "bolt",
|
|
||||||
Requires: []Type{
|
|
||||||
ContentPlugin,
|
|
||||||
SnapshotPlugin,
|
|
||||||
},
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: TracingProcessorPlugin,
|
|
||||||
ID: "otlp",
|
|
||||||
}).Register(&Registration{
|
|
||||||
Type: InternalPlugin,
|
|
||||||
ID: "tracing",
|
|
||||||
Requires: []Type{
|
|
||||||
TracingProcessorPlugin,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
ordered := register.Graph(mockPluginFilter)
|
|
||||||
expectedURI := []string{
|
|
||||||
"io.containerd.monitor.v1.cgroups",
|
|
||||||
"io.containerd.content.v1.content",
|
|
||||||
"io.containerd.snapshotter.v1.native",
|
|
||||||
"io.containerd.snapshotter.v1.overlayfs",
|
|
||||||
"io.containerd.metadata.v1.bolt",
|
|
||||||
"io.containerd.runtime.v1.linux",
|
|
||||||
"io.containerd.runtime.v2.task",
|
|
||||||
"io.containerd.service.v1.tasks-service",
|
|
||||||
"io.containerd.service.v1.introspection-service",
|
|
||||||
"io.containerd.service.v1.namespaces-service",
|
|
||||||
"io.containerd.service.v1.containers-service",
|
|
||||||
"io.containerd.differ.v1.walking",
|
|
||||||
"io.containerd.service.v1.diff-service",
|
|
||||||
"io.containerd.service.v1.snapshots-service",
|
|
||||||
"io.containerd.service.v1.content-service",
|
|
||||||
"io.containerd.grpc.v1.namespaces",
|
|
||||||
"io.containerd.grpc.v1.content",
|
|
||||||
"io.containerd.grpc.v1.containers",
|
|
||||||
"io.containerd.grpc.v1.events",
|
|
||||||
"io.containerd.lease.v1.manager",
|
|
||||||
"io.containerd.grpc.v1.leases",
|
|
||||||
"io.containerd.grpc.v1.diff",
|
|
||||||
"io.containerd.grpc.v1.snapshots",
|
|
||||||
"io.containerd.grpc.v1.version",
|
|
||||||
"io.containerd.grpc.v1.images",
|
|
||||||
"io.containerd.gc.v1.scheduler",
|
|
||||||
"io.containerd.grpc.v1.tasks",
|
|
||||||
"io.containerd.grpc.v1.healthcheck",
|
|
||||||
"io.containerd.internal.v1.opt",
|
|
||||||
"io.containerd.grpc.v1.cri",
|
|
||||||
"io.containerd.internal.v1.restart",
|
|
||||||
"io.containerd.tracing.processor.v1.otlp",
|
|
||||||
"io.containerd.internal.v1.tracing",
|
|
||||||
"io.containerd.grpc.v1.introspection",
|
|
||||||
}
|
|
||||||
cmpOrdered(t, ordered, expectedURI)
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmpOrdered(t *testing.T, ordered []Registration, expectedURI []string) {
|
|
||||||
if len(ordered) != len(expectedURI) {
|
|
||||||
t.Fatalf("ordered compare failed, %d != %d", len(ordered), len(expectedURI))
|
|
||||||
}
|
|
||||||
for i := range ordered {
|
|
||||||
if ordered[i].URI() != expectedURI[i] {
|
|
||||||
t.Fatalf("graph failed, expected: %s, but return: %s", expectedURI[i], ordered[i].URI())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestPluginGraph tests the logic of Graph
|
|
||||||
func TestPluginGraph(t *testing.T) {
|
|
||||||
for _, testcase := range []struct {
|
|
||||||
input []*Registration
|
|
||||||
expectedURI []string
|
|
||||||
filter DisableFilter
|
|
||||||
}{
|
|
||||||
// test requires *
|
|
||||||
{
|
|
||||||
input: []*Registration{
|
|
||||||
{
|
|
||||||
Type: "grpc",
|
|
||||||
ID: "introspection",
|
|
||||||
Requires: []Type{
|
|
||||||
"*",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Type: "service",
|
|
||||||
ID: "container",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedURI: []string{
|
|
||||||
"service.container",
|
|
||||||
"grpc.introspection",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// test requires
|
|
||||||
{
|
|
||||||
input: []*Registration{
|
|
||||||
{
|
|
||||||
Type: "service",
|
|
||||||
ID: "container",
|
|
||||||
Requires: []Type{
|
|
||||||
"metadata",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Type: "metadata",
|
|
||||||
ID: "bolt",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedURI: []string{
|
|
||||||
"metadata.bolt",
|
|
||||||
"service.container",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: []*Registration{
|
|
||||||
{
|
|
||||||
Type: "metadata",
|
|
||||||
ID: "bolt",
|
|
||||||
Requires: []Type{
|
|
||||||
"content",
|
|
||||||
"snapshotter",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Type: "snapshotter",
|
|
||||||
ID: "overlayfs",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Type: "content",
|
|
||||||
ID: "content",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedURI: []string{
|
|
||||||
"content.content",
|
|
||||||
"snapshotter.overlayfs",
|
|
||||||
"metadata.bolt",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// test disable
|
|
||||||
{
|
|
||||||
input: []*Registration{
|
|
||||||
{
|
|
||||||
Type: "content",
|
|
||||||
ID: "content",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Type: "disable",
|
|
||||||
ID: "disable",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedURI: []string{
|
|
||||||
"content.content",
|
|
||||||
},
|
|
||||||
filter: func(r *Registration) bool {
|
|
||||||
return r.Type == "disable"
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
var register Registry
|
|
||||||
for _, in := range testcase.input {
|
|
||||||
register = register.Register(in)
|
|
||||||
}
|
|
||||||
var filter DisableFilter = mockPluginFilter
|
|
||||||
if testcase.filter != nil {
|
|
||||||
filter = testcase.filter
|
|
||||||
}
|
|
||||||
ordered := register.Graph(filter)
|
|
||||||
cmpOrdered(t, ordered, testcase.expectedURI)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
/*
|
|
||||||
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 registry
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/containerd/containerd/v2/plugin"
|
|
||||||
)
|
|
||||||
|
|
||||||
var register = struct {
|
|
||||||
sync.RWMutex
|
|
||||||
r plugin.Registry
|
|
||||||
}{}
|
|
||||||
|
|
||||||
// Register allows plugins to register
|
|
||||||
func Register(r *plugin.Registration) {
|
|
||||||
register.Lock()
|
|
||||||
defer register.Unlock()
|
|
||||||
register.r = register.r.Register(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset removes all global registrations
|
|
||||||
func Reset() {
|
|
||||||
register.Lock()
|
|
||||||
defer register.Unlock()
|
|
||||||
register.r = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Graph returns an ordered list of registered plugins for initialization.
|
|
||||||
// Plugins in disableList specified by id will be disabled.
|
|
||||||
func Graph(filter plugin.DisableFilter) []plugin.Registration {
|
|
||||||
register.RLock()
|
|
||||||
defer register.RUnlock()
|
|
||||||
return register.r.Graph(filter)
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user