Setup plugin ids and dependencies
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
parent
6bbed2c125
commit
94e7f8e943
@ -2,6 +2,7 @@ package containerd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
@ -19,6 +20,7 @@ import (
|
||||
versionservice "github.com/containerd/containerd/api/services/version"
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/plugin"
|
||||
"github.com/containerd/containerd/remotes"
|
||||
"github.com/containerd/containerd/remotes/docker"
|
||||
contentservice "github.com/containerd/containerd/services/content"
|
||||
@ -83,7 +85,7 @@ func New(address string, opts ...ClientOpt) (*Client, error) {
|
||||
}
|
||||
return &Client{
|
||||
conn: conn,
|
||||
runtime: runtime.GOOS,
|
||||
runtime: fmt.Sprintf("%s.%s", plugin.RuntimePlugin, runtime.GOOS),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -37,8 +37,6 @@ func loadConfig(path string) error {
|
||||
// config specifies the containerd configuration file in the TOML format.
|
||||
// It contains fields to configure various subsystems and containerd as a whole.
|
||||
type config struct {
|
||||
// State is the path to a directory where containerd will store runtime state
|
||||
State string `toml:"state"`
|
||||
// Root is the path to a directory where containerd will store persistent data
|
||||
Root string `toml:"root"`
|
||||
// GRPC configuration settings
|
||||
|
@ -2,8 +2,7 @@ package main
|
||||
|
||||
func defaultConfig() *config {
|
||||
return &config{
|
||||
Root: "/var/lib/containerd",
|
||||
State: "/run/containerd",
|
||||
Root: "/var/lib/containerd",
|
||||
GRPC: grpcConfig{
|
||||
Address: "/run/containerd/containerd.sock",
|
||||
},
|
||||
@ -11,7 +10,7 @@ func defaultConfig() *config {
|
||||
Level: "info",
|
||||
Address: "/run/containerd/debug.sock",
|
||||
},
|
||||
Snapshotter: "overlay",
|
||||
Differ: "base",
|
||||
Snapshotter: "io.containerd.snapshotter.v1.overlayfs",
|
||||
Differ: "io.containerd.differ.v1.base-diff",
|
||||
}
|
||||
}
|
||||
|
@ -4,8 +4,7 @@ package main
|
||||
|
||||
func defaultConfig() *config {
|
||||
return &config{
|
||||
Root: "/var/lib/containerd",
|
||||
State: "/run/containerd",
|
||||
Root: "/var/lib/containerd",
|
||||
GRPC: grpcConfig{
|
||||
Address: "/run/containerd/containerd.sock",
|
||||
},
|
||||
@ -13,7 +12,7 @@ func defaultConfig() *config {
|
||||
Level: "info",
|
||||
Address: "/run/containerd/debug.sock",
|
||||
},
|
||||
Snapshotter: "naive",
|
||||
Differ: "base",
|
||||
Snapshotter: "io.containerd.snapshotter.v1.naive",
|
||||
Differ: "io.containerd.differ.v1.base-diff",
|
||||
}
|
||||
}
|
||||
|
@ -7,8 +7,7 @@ import (
|
||||
|
||||
func defaultConfig() *config {
|
||||
return &config{
|
||||
Root: filepath.Join(os.Getenv("programfiles"), "containerd", "root"),
|
||||
State: filepath.Join(os.Getenv("programfiles"), "containerd", "state"),
|
||||
Root: filepath.Join(os.Getenv("programfiles"), "containerd", "root"),
|
||||
GRPC: grpcConfig{
|
||||
Address: `\\.\pipe\containerd-containerd`,
|
||||
},
|
||||
@ -16,7 +15,7 @@ func defaultConfig() *config {
|
||||
Level: "info",
|
||||
Address: `\\.\pipe\containerd-debug`,
|
||||
},
|
||||
Snapshotter: "windows",
|
||||
Differ: "base",
|
||||
Snapshotter: "io.containerd.snapshotter.v1.windows",
|
||||
Differ: "io.containerd.differ.v1.base-diff",
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,6 @@ import (
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/containerd/containerd/plugin"
|
||||
"github.com/containerd/containerd/snapshot"
|
||||
"github.com/containerd/containerd/sys"
|
||||
"github.com/containerd/containerd/version"
|
||||
metrics "github.com/docker/go-metrics"
|
||||
@ -105,41 +104,42 @@ func main() {
|
||||
if err := plugin.Load(filepath.Join(conf.Root, "plugins")); err != nil {
|
||||
return err
|
||||
}
|
||||
registerContentStore()
|
||||
registerMetaDB()
|
||||
// start debug and metrics APIs
|
||||
if err := serveDebugAPI(); err != nil {
|
||||
return err
|
||||
}
|
||||
monitor, err := loadMonitor()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
runtimes, err := loadRuntimes(monitor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
store, err := resolveContentStore()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
meta, err := resolveMetaDB(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer meta.Close()
|
||||
snapshotter, err := loadSnapshotter(store)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
var (
|
||||
services []plugin.Service
|
||||
plugins = make(map[plugin.PluginType][]interface{})
|
||||
)
|
||||
for _, init := range plugin.Graph() {
|
||||
id := init.URI()
|
||||
log.G(global).WithField("type", init.Type).Infof("loading plugin %q...", id)
|
||||
if !shouldLoad(init) {
|
||||
continue
|
||||
}
|
||||
ic := plugin.NewContext(plugins)
|
||||
ic.Root = filepath.Join(conf.Root, id)
|
||||
ic.Context = log.WithModule(global, id)
|
||||
if init.Config != nil {
|
||||
if err := loadPluginConfig(init.ID, init.Config, ic); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
p, err := init.Init(ic)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
plugins[init.Type] = append(plugins[init.Type], p)
|
||||
if s, ok := p.(plugin.Service); ok {
|
||||
services = append(services, s)
|
||||
}
|
||||
}
|
||||
|
||||
differ, err := loadDiffer(snapshotter, store)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
services, err := loadServices(runtimes, store, snapshotter, meta, differ)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// start the GRPC api with the execution service registered
|
||||
server := newGRPCServer()
|
||||
for _, service := range services {
|
||||
@ -159,7 +159,6 @@ func main() {
|
||||
log.G(global).Infof("containerd successfully booted in %fs", time.Since(start).Seconds())
|
||||
return handleSignals(signals, server)
|
||||
}
|
||||
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "containerd: %s\n", err)
|
||||
os.Exit(1)
|
||||
@ -184,10 +183,6 @@ func before(context *cli.Context) error {
|
||||
name: "root",
|
||||
d: &conf.Root,
|
||||
},
|
||||
{
|
||||
name: "state",
|
||||
d: &conf.State,
|
||||
},
|
||||
{
|
||||
name: "address",
|
||||
d: &conf.GRPC.Address,
|
||||
@ -254,139 +249,27 @@ func serveDebugAPI() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func resolveContentStore() (content.Store, error) {
|
||||
cp := filepath.Join(conf.Root, "content")
|
||||
return content.NewStore(cp)
|
||||
func registerContentStore() {
|
||||
plugin.Register(&plugin.Registration{
|
||||
Type: plugin.ContentPlugin,
|
||||
ID: "content",
|
||||
Init: func(ic *plugin.InitContext) (interface{}, error) {
|
||||
return content.NewStore(ic.Root)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func resolveMetaDB(ctx *cli.Context) (*bolt.DB, error) {
|
||||
path := filepath.Join(conf.Root, "meta.db")
|
||||
|
||||
db, err := bolt.Open(path, 0644, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return db, nil
|
||||
}
|
||||
|
||||
func loadRuntimes(monitor plugin.TaskMonitor) (map[string]plugin.Runtime, error) {
|
||||
o := make(map[string]plugin.Runtime)
|
||||
for name, rr := range plugin.Registrations() {
|
||||
if rr.Type != plugin.RuntimePlugin {
|
||||
continue
|
||||
}
|
||||
log.G(global).Infof("loading runtime plugin %q...", name)
|
||||
ic := &plugin.InitContext{
|
||||
Root: conf.Root,
|
||||
State: conf.State,
|
||||
Context: log.WithModule(global, fmt.Sprintf("runtime-%s", name)),
|
||||
Monitor: monitor,
|
||||
}
|
||||
if rr.Config != nil {
|
||||
if err := conf.decodePlugin(name, rr.Config); err != nil {
|
||||
func registerMetaDB() {
|
||||
plugin.Register(&plugin.Registration{
|
||||
Type: plugin.MetadataPlugin,
|
||||
ID: "bolt",
|
||||
Init: func(ic *plugin.InitContext) (interface{}, error) {
|
||||
if err := os.MkdirAll(ic.Root, 0700); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ic.Config = rr.Config
|
||||
}
|
||||
vr, err := rr.Init(ic)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
o[name] = vr.(plugin.Runtime)
|
||||
}
|
||||
return o, nil
|
||||
}
|
||||
|
||||
func loadMonitor() (plugin.TaskMonitor, error) {
|
||||
var monitors []plugin.TaskMonitor
|
||||
for name, m := range plugin.Registrations() {
|
||||
if m.Type != plugin.TaskMonitorPlugin {
|
||||
continue
|
||||
}
|
||||
log.G(global).Infof("loading monitor plugin %q...", name)
|
||||
ic := &plugin.InitContext{
|
||||
Root: conf.Root,
|
||||
State: conf.State,
|
||||
Context: log.WithModule(global, fmt.Sprintf("monitor-%s", name)),
|
||||
}
|
||||
mm, err := m.Init(ic)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
monitors = append(monitors, mm.(plugin.TaskMonitor))
|
||||
}
|
||||
if len(monitors) == 0 {
|
||||
return plugin.NewNoopMonitor(), nil
|
||||
}
|
||||
return plugin.NewMultiTaskMonitor(monitors...), nil
|
||||
}
|
||||
|
||||
func loadSnapshotter(store content.Store) (snapshot.Snapshotter, error) {
|
||||
for name, sr := range plugin.Registrations() {
|
||||
if sr.Type != plugin.SnapshotPlugin {
|
||||
continue
|
||||
}
|
||||
moduleName := fmt.Sprintf("snapshot-%s", conf.Snapshotter)
|
||||
if name != moduleName {
|
||||
continue
|
||||
}
|
||||
|
||||
log.G(global).Infof("loading snapshot plugin %q...", name)
|
||||
ic := &plugin.InitContext{
|
||||
Root: conf.Root,
|
||||
State: conf.State,
|
||||
Content: store,
|
||||
Context: log.WithModule(global, moduleName),
|
||||
}
|
||||
if sr.Config != nil {
|
||||
if err := conf.decodePlugin(name, sr.Config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ic.Config = sr.Config
|
||||
}
|
||||
sn, err := sr.Init(ic)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sn.(snapshot.Snapshotter), nil
|
||||
}
|
||||
return nil, fmt.Errorf("snapshotter not loaded: %v", conf.Snapshotter)
|
||||
}
|
||||
|
||||
func loadDiffer(snapshotter snapshot.Snapshotter, store content.Store) (plugin.Differ, error) {
|
||||
for name, sr := range plugin.Registrations() {
|
||||
if sr.Type != plugin.DiffPlugin {
|
||||
continue
|
||||
}
|
||||
moduleName := fmt.Sprintf("diff-%s", conf.Differ)
|
||||
if name != moduleName {
|
||||
continue
|
||||
}
|
||||
|
||||
log.G(global).Infof("loading differ plugin %q...", name)
|
||||
ic := &plugin.InitContext{
|
||||
Root: conf.Root,
|
||||
State: conf.State,
|
||||
Content: store,
|
||||
Snapshotter: snapshotter,
|
||||
Context: log.WithModule(global, moduleName),
|
||||
}
|
||||
if sr.Config != nil {
|
||||
if err := conf.decodePlugin(name, sr.Config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ic.Config = sr.Config
|
||||
}
|
||||
sn, err := sr.Init(ic)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sn.(plugin.Differ), nil
|
||||
}
|
||||
return nil, fmt.Errorf("differ not loaded: %v", conf.Differ)
|
||||
return bolt.Open(filepath.Join(ic.Root, "meta.db"), 0644, nil)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func newGRPCServer() *grpc.Server {
|
||||
@ -397,40 +280,6 @@ func newGRPCServer() *grpc.Server {
|
||||
return s
|
||||
}
|
||||
|
||||
func loadServices(runtimes map[string]plugin.Runtime,
|
||||
store content.Store, sn snapshot.Snapshotter,
|
||||
meta *bolt.DB, differ plugin.Differ) ([]plugin.Service, error) {
|
||||
var o []plugin.Service
|
||||
for name, sr := range plugin.Registrations() {
|
||||
if sr.Type != plugin.GRPCPlugin {
|
||||
continue
|
||||
}
|
||||
log.G(global).Infof("loading grpc service plugin %q...", name)
|
||||
ic := &plugin.InitContext{
|
||||
Root: conf.Root,
|
||||
State: conf.State,
|
||||
Context: log.WithModule(global, fmt.Sprintf("service-%s", name)),
|
||||
Runtimes: runtimes,
|
||||
Content: store,
|
||||
Meta: meta,
|
||||
Snapshotter: sn,
|
||||
Differ: differ,
|
||||
}
|
||||
if sr.Config != nil {
|
||||
if err := conf.decodePlugin(name, sr.Config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ic.Config = sr.Config
|
||||
}
|
||||
vs, err := sr.Init(ic)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
o = append(o, vs.(plugin.Service))
|
||||
}
|
||||
return o, nil
|
||||
}
|
||||
|
||||
func serveGRPC(server *grpc.Server) error {
|
||||
path := conf.GRPC.Address
|
||||
if path == "" {
|
||||
@ -494,3 +343,23 @@ func dumpStacks() {
|
||||
buf = buf[:stackSize]
|
||||
logrus.Infof("=== BEGIN goroutine stack dump ===\n%s\n=== END goroutine stack dump ===", buf)
|
||||
}
|
||||
|
||||
func loadPluginConfig(name string, c interface{}, ic *plugin.InitContext) error {
|
||||
if err := conf.decodePlugin(name, c); err != nil {
|
||||
return err
|
||||
}
|
||||
ic.Config = c
|
||||
return nil
|
||||
}
|
||||
|
||||
func shouldLoad(r *plugin.Registration) bool {
|
||||
// only load certain plugins based on the config values
|
||||
switch r.Type {
|
||||
case plugin.SnapshotPlugin:
|
||||
return r.URI() == conf.Snapshotter
|
||||
case plugin.DiffPlugin:
|
||||
return r.URI() == conf.Differ
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -12,13 +12,14 @@ import (
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultConfigPath = "/etc/containerd/config.toml"
|
||||
)
|
||||
const defaultConfigPath = "/etc/containerd/config.toml"
|
||||
|
||||
var (
|
||||
handledSignals = []os.Signal{unix.SIGTERM, unix.SIGINT, unix.SIGUSR1, unix.SIGCHLD}
|
||||
)
|
||||
var handledSignals = []os.Signal{
|
||||
unix.SIGTERM,
|
||||
unix.SIGINT,
|
||||
unix.SIGUSR1,
|
||||
unix.SIGCHLD,
|
||||
}
|
||||
|
||||
func platformInit(context *cli.Context) error {
|
||||
if conf.Subreaper {
|
||||
@ -33,12 +34,6 @@ func platformInit(context *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := os.MkdirAll(conf.State, 0750); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.Chown(conf.State, conf.GRPC.Uid, conf.GRPC.Gid); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -22,12 +22,6 @@ var (
|
||||
)
|
||||
|
||||
func platformInit(context *cli.Context) error {
|
||||
if err := os.MkdirAll(conf.State, 0750); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.Chown(conf.State, conf.GRPC.Uid, conf.GRPC.Gid); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -55,8 +55,8 @@ var runCommand = cli.Command{
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "runtime",
|
||||
Usage: "runtime name (linux, windows, vmware-linux)",
|
||||
Value: "linux",
|
||||
Usage: "runtime name (io.containerd.runtime.v1.linux, io.containerd.runtime.v1.windows, io.containerd.runtime.v1.com.vmware.linux)",
|
||||
Value: "io.containerd.runtime.v1.linux",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "readonly",
|
||||
|
@ -18,10 +18,23 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
plugin.Register("diff-base", &plugin.Registration{
|
||||
plugin.Register(&plugin.Registration{
|
||||
Type: plugin.DiffPlugin,
|
||||
ID: "base-diff",
|
||||
Requires: []plugin.PluginType{
|
||||
plugin.ContentPlugin,
|
||||
plugin.SnapshotPlugin,
|
||||
},
|
||||
Init: func(ic *plugin.InitContext) (interface{}, error) {
|
||||
return newBaseDiff(ic.Content, ic.Snapshotter)
|
||||
c, err := ic.Get(plugin.ContentPlugin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s, err := ic.Get(plugin.SnapshotPlugin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newBaseDiff(c.(content.Store), s.(snapshot.Snapshotter))
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -32,19 +32,23 @@ import (
|
||||
var (
|
||||
ErrTaskNotExists = errors.New("task does not exist")
|
||||
ErrTaskAlreadyExists = errors.New("task already exists")
|
||||
pluginID = fmt.Sprintf("%s.%s", plugin.RuntimePlugin, "linux")
|
||||
)
|
||||
|
||||
const (
|
||||
runtimeName = "linux"
|
||||
configFilename = "config.json"
|
||||
defaultRuntime = "runc"
|
||||
defaultShim = "containerd-shim"
|
||||
)
|
||||
|
||||
func init() {
|
||||
plugin.Register(runtimeName, &plugin.Registration{
|
||||
plugin.Register(&plugin.Registration{
|
||||
Type: plugin.RuntimePlugin,
|
||||
ID: "linux",
|
||||
Init: New,
|
||||
Requires: []plugin.PluginType{
|
||||
plugin.TaskMonitorPlugin,
|
||||
},
|
||||
Config: &Config{
|
||||
Shim: defaultShim,
|
||||
Runtime: defaultRuntime,
|
||||
@ -129,25 +133,28 @@ func (l *taskList) delete(ctx context.Context, t *Task) {
|
||||
}
|
||||
|
||||
func New(ic *plugin.InitContext) (interface{}, error) {
|
||||
path := filepath.Join(ic.State, runtimeName)
|
||||
if err := os.MkdirAll(path, 0700); err != nil {
|
||||
if err := os.MkdirAll(ic.Root, 0700); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
monitor, err := ic.Get(plugin.TaskMonitorPlugin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfg := ic.Config.(*Config)
|
||||
c, cancel := context.WithCancel(ic.Context)
|
||||
r := &Runtime{
|
||||
root: path,
|
||||
root: ic.Root,
|
||||
remote: !cfg.NoShim,
|
||||
shim: cfg.Shim,
|
||||
runtime: cfg.Runtime,
|
||||
events: make(chan *plugin.Event, 2048),
|
||||
eventsContext: c,
|
||||
eventsCancel: cancel,
|
||||
monitor: ic.Monitor,
|
||||
monitor: monitor.(plugin.TaskMonitor),
|
||||
tasks: newTaskList(),
|
||||
}
|
||||
// set the events output for a monitor if it generates events
|
||||
ic.Monitor.Events(r.events)
|
||||
r.monitor.Events(r.events)
|
||||
tasks, err := r.loadAllTasks(ic.Context)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -157,7 +164,6 @@ func New(ic *plugin.InitContext) (interface{}, error) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// load all tasks from disk
|
||||
return r, nil
|
||||
}
|
||||
|
||||
@ -174,6 +180,10 @@ type Runtime struct {
|
||||
tasks *taskList
|
||||
}
|
||||
|
||||
func (r *Runtime) ID() string {
|
||||
return pluginID
|
||||
}
|
||||
|
||||
func (r *Runtime) Create(ctx context.Context, id string, opts plugin.CreateOpts) (t plugin.Task, err error) {
|
||||
namespace, err := namespaces.NamespaceRequired(ctx)
|
||||
if err != nil {
|
||||
@ -358,7 +368,7 @@ func (r *Runtime) forward(events shim.Shim_EventsClient) {
|
||||
}
|
||||
r.events <- &plugin.Event{
|
||||
Timestamp: time.Now(),
|
||||
Runtime: runtimeName,
|
||||
Runtime: r.ID(),
|
||||
Type: et,
|
||||
Pid: e.Pid,
|
||||
ID: e.ID,
|
||||
|
@ -35,7 +35,7 @@ func (c *Task) Info() plugin.TaskInfo {
|
||||
return plugin.TaskInfo{
|
||||
ID: c.containerID,
|
||||
ContainerID: c.containerID,
|
||||
Runtime: runtimeName,
|
||||
Runtime: pluginID,
|
||||
Spec: c.spec,
|
||||
Namespace: c.namespace,
|
||||
}
|
||||
|
@ -13,11 +13,10 @@ import (
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
const name = "cgroups"
|
||||
|
||||
func init() {
|
||||
plugin.Register(name, &plugin.Registration{
|
||||
plugin.Register(&plugin.Registration{
|
||||
Type: plugin.TaskMonitorPlugin,
|
||||
ID: "cgroups",
|
||||
Init: New,
|
||||
})
|
||||
}
|
||||
|
36
plugin/context.go
Normal file
36
plugin/context.go
Normal file
@ -0,0 +1,36 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func NewContext(plugins map[PluginType][]interface{}) *InitContext {
|
||||
return &InitContext{
|
||||
plugins: plugins,
|
||||
}
|
||||
}
|
||||
|
||||
type InitContext struct {
|
||||
Root string
|
||||
Context context.Context
|
||||
Config interface{}
|
||||
|
||||
plugins map[PluginType][]interface{}
|
||||
}
|
||||
|
||||
func (i *InitContext) Get(t PluginType) (interface{}, error) {
|
||||
p := i.plugins[t]
|
||||
if len(p) == 0 {
|
||||
return nil, fmt.Errorf("no plugins registered for %s", t)
|
||||
}
|
||||
return p[0], nil
|
||||
}
|
||||
|
||||
func (i *InitContext) GetAll(t PluginType) ([]interface{}, error) {
|
||||
p, ok := i.plugins[t]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no plugins registered for %s", t)
|
||||
}
|
||||
return p, nil
|
||||
}
|
@ -3,7 +3,6 @@ package plugin
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
ErrUnknownRuntime = errors.New("unknown runtime")
|
||||
ErrContainerExists = errors.New("container with id already exists")
|
||||
ErrContainerNotExist = errors.New("container does not exist")
|
||||
ErrRuntimeNotExist = errors.New("runtime does not exist")
|
||||
|
@ -1,45 +1,42 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/snapshot"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type PluginType int
|
||||
var (
|
||||
ErrNoPluginType = errors.New("plugin: no type")
|
||||
ErrNoPluginID = errors.New("plugin: no id")
|
||||
)
|
||||
|
||||
type PluginType string
|
||||
|
||||
const (
|
||||
RuntimePlugin PluginType = iota + 1
|
||||
GRPCPlugin
|
||||
SnapshotPlugin
|
||||
TaskMonitorPlugin
|
||||
DiffPlugin
|
||||
RuntimePlugin PluginType = "io.containerd.runtime.v1"
|
||||
GRPCPlugin PluginType = "io.containerd.grpc.v1"
|
||||
SnapshotPlugin PluginType = "io.containerd.snapshotter.v1"
|
||||
TaskMonitorPlugin PluginType = "io.containerd.monitor.v1"
|
||||
DiffPlugin PluginType = "io.containerd.differ.v1"
|
||||
MetadataPlugin PluginType = "io.containerd.metadata.v1"
|
||||
ContentPlugin PluginType = "io.containerd.content.v1"
|
||||
)
|
||||
|
||||
type Registration struct {
|
||||
Type PluginType
|
||||
Config interface{}
|
||||
Init func(*InitContext) (interface{}, error)
|
||||
Type PluginType
|
||||
ID string
|
||||
Config interface{}
|
||||
Requires []PluginType
|
||||
Init func(*InitContext) (interface{}, error)
|
||||
|
||||
added bool
|
||||
}
|
||||
|
||||
// TODO(@crosbymichael): how do we keep this struct from growing but support dependency injection for loaded plugins?
|
||||
type InitContext struct {
|
||||
Root string
|
||||
State string
|
||||
Runtimes map[string]Runtime
|
||||
Content content.Store
|
||||
Meta *bolt.DB
|
||||
Snapshotter snapshot.Snapshotter
|
||||
Differ Differ
|
||||
Config interface{}
|
||||
Context context.Context
|
||||
Monitor TaskMonitor
|
||||
func (r *Registration) URI() string {
|
||||
return fmt.Sprintf("%s.%s", r.Type, r.ID)
|
||||
}
|
||||
|
||||
type Service interface {
|
||||
@ -48,10 +45,8 @@ type Service interface {
|
||||
|
||||
var register = struct {
|
||||
sync.Mutex
|
||||
r map[string]*Registration
|
||||
}{
|
||||
r: make(map[string]*Registration),
|
||||
}
|
||||
r []*Registration
|
||||
}{}
|
||||
|
||||
// Load loads all plugins at the provided path into containerd
|
||||
func Load(path string) (err error) {
|
||||
@ -67,16 +62,39 @@ func Load(path string) (err error) {
|
||||
return loadPlugins(path)
|
||||
}
|
||||
|
||||
func Register(name string, r *Registration) error {
|
||||
func Register(r *Registration) {
|
||||
register.Lock()
|
||||
defer register.Unlock()
|
||||
if _, ok := register.r[name]; ok {
|
||||
return fmt.Errorf("plugin already registered as %q", name)
|
||||
if r.Type == "" {
|
||||
panic(ErrNoPluginType)
|
||||
}
|
||||
register.r[name] = r
|
||||
return nil
|
||||
if r.ID == "" {
|
||||
panic(ErrNoPluginID)
|
||||
}
|
||||
register.r = append(register.r, r)
|
||||
}
|
||||
|
||||
func Registrations() map[string]*Registration {
|
||||
return register.r
|
||||
func Graph() (ordered []*Registration) {
|
||||
for _, r := range register.r {
|
||||
children(r.Requires, &ordered)
|
||||
if !r.added {
|
||||
ordered = append(ordered, r)
|
||||
r.added = true
|
||||
}
|
||||
}
|
||||
return ordered
|
||||
}
|
||||
|
||||
func children(types []PluginType, ordered *[]*Registration) {
|
||||
for _, t := range types {
|
||||
for _, r := range register.r {
|
||||
if r.Type == t {
|
||||
children(r.Requires, ordered)
|
||||
if !r.added {
|
||||
*ordered = append(*ordered, r)
|
||||
r.added = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,8 @@ type Exit struct {
|
||||
// Runtime is responsible for the creation of containers for a certain platform,
|
||||
// arch, or custom usage.
|
||||
type Runtime interface {
|
||||
// ID of the runtime
|
||||
ID() string
|
||||
// Create creates a container with the provided id and options
|
||||
Create(ctx context.Context, id string, opts CreateOpts) (Task, error)
|
||||
// Get returns a container
|
||||
|
@ -13,10 +13,18 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
plugin.Register("containers-grpc", &plugin.Registration{
|
||||
plugin.Register(&plugin.Registration{
|
||||
Type: plugin.GRPCPlugin,
|
||||
ID: "containers",
|
||||
Requires: []plugin.PluginType{
|
||||
plugin.MetadataPlugin,
|
||||
},
|
||||
Init: func(ic *plugin.InitContext) (interface{}, error) {
|
||||
return NewService(ic.Meta), nil
|
||||
m, err := ic.Get(plugin.MetadataPlugin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewService(m.(*bolt.DB)), nil
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -30,15 +30,23 @@ var bufPool = sync.Pool{
|
||||
var _ api.ContentServer = &Service{}
|
||||
|
||||
func init() {
|
||||
plugin.Register("content-grpc", &plugin.Registration{
|
||||
plugin.Register(&plugin.Registration{
|
||||
Type: plugin.GRPCPlugin,
|
||||
ID: "content",
|
||||
Requires: []plugin.PluginType{
|
||||
plugin.ContentPlugin,
|
||||
},
|
||||
Init: NewService,
|
||||
})
|
||||
}
|
||||
|
||||
func NewService(ic *plugin.InitContext) (interface{}, error) {
|
||||
c, err := ic.Get(plugin.ContentPlugin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Service{
|
||||
store: ic.Content,
|
||||
store: c.(content.Store),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -10,11 +10,19 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
plugin.Register("diff-grpc", &plugin.Registration{
|
||||
plugin.Register(&plugin.Registration{
|
||||
Type: plugin.GRPCPlugin,
|
||||
ID: "diff",
|
||||
Requires: []plugin.PluginType{
|
||||
plugin.DiffPlugin,
|
||||
},
|
||||
Init: func(ic *plugin.InitContext) (interface{}, error) {
|
||||
d, err := ic.Get(plugin.DiffPlugin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &service{
|
||||
diff: ic.Differ,
|
||||
diff: d.(plugin.Differ),
|
||||
}, nil
|
||||
},
|
||||
})
|
||||
|
@ -35,22 +35,45 @@ var (
|
||||
)
|
||||
|
||||
func init() {
|
||||
plugin.Register("tasks-grpc", &plugin.Registration{
|
||||
plugin.Register(&plugin.Registration{
|
||||
Type: plugin.GRPCPlugin,
|
||||
ID: "tasks",
|
||||
Requires: []plugin.PluginType{
|
||||
plugin.RuntimePlugin,
|
||||
plugin.MetadataPlugin,
|
||||
plugin.ContentPlugin,
|
||||
},
|
||||
Init: New,
|
||||
})
|
||||
}
|
||||
|
||||
func New(ic *plugin.InitContext) (interface{}, error) {
|
||||
c, err := newCollector(ic.Context, ic.Runtimes)
|
||||
rt, err := ic.GetAll(plugin.RuntimePlugin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m, err := ic.Get(plugin.MetadataPlugin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ct, err := ic.Get(plugin.ContentPlugin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
runtimes := make(map[string]plugin.Runtime)
|
||||
for _, rr := range rt {
|
||||
r := rr.(plugin.Runtime)
|
||||
runtimes[r.ID()] = r
|
||||
}
|
||||
c, err := newCollector(ic.Context, runtimes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Service{
|
||||
runtimes: ic.Runtimes,
|
||||
db: ic.Meta,
|
||||
runtimes: runtimes,
|
||||
db: m.(*bolt.DB),
|
||||
collector: c,
|
||||
store: ic.Content,
|
||||
store: ct.(content.Store),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -461,7 +484,7 @@ func (s *Service) getTask(ctx context.Context, id string) (plugin.Task, error) {
|
||||
func (s *Service) getRuntime(name string) (plugin.Runtime, error) {
|
||||
runtime, ok := s.runtimes[name]
|
||||
if !ok {
|
||||
return nil, plugin.ErrUnknownRuntime
|
||||
return nil, fmt.Errorf("unknown runtime %q", name)
|
||||
}
|
||||
return runtime, nil
|
||||
}
|
||||
|
@ -13,8 +13,9 @@ type Service struct {
|
||||
}
|
||||
|
||||
func init() {
|
||||
plugin.Register("healthcheck-grpc", &plugin.Registration{
|
||||
plugin.Register(&plugin.Registration{
|
||||
Type: plugin.GRPCPlugin,
|
||||
ID: "healthcheck",
|
||||
Init: NewService,
|
||||
})
|
||||
}
|
||||
|
@ -12,10 +12,18 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
plugin.Register("images-grpc", &plugin.Registration{
|
||||
plugin.Register(&plugin.Registration{
|
||||
Type: plugin.GRPCPlugin,
|
||||
ID: "images",
|
||||
Requires: []plugin.PluginType{
|
||||
plugin.MetadataPlugin,
|
||||
},
|
||||
Init: func(ic *plugin.InitContext) (interface{}, error) {
|
||||
return NewService(ic.Meta), nil
|
||||
m, err := ic.Get(plugin.MetadataPlugin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewService(m.(*bolt.DB)), nil
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -15,10 +15,18 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
plugin.Register("namespaces-grpc", &plugin.Registration{
|
||||
plugin.Register(&plugin.Registration{
|
||||
Type: plugin.GRPCPlugin,
|
||||
ID: "namespaces",
|
||||
Requires: []plugin.PluginType{
|
||||
plugin.MetadataPlugin,
|
||||
},
|
||||
Init: func(ic *plugin.InitContext) (interface{}, error) {
|
||||
return NewService(ic.Meta), nil
|
||||
m, err := ic.Get(plugin.MetadataPlugin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewService(m.(*bolt.DB)), nil
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -16,10 +16,18 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
plugin.Register("snapshots-grpc", &plugin.Registration{
|
||||
plugin.Register(&plugin.Registration{
|
||||
Type: plugin.GRPCPlugin,
|
||||
ID: "snapshots",
|
||||
Requires: []plugin.PluginType{
|
||||
plugin.SnapshotPlugin,
|
||||
},
|
||||
Init: func(ic *plugin.InitContext) (interface{}, error) {
|
||||
return newService(ic.Snapshotter)
|
||||
s, err := ic.Get(plugin.SnapshotPlugin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newService(s.(snapshot.Snapshotter))
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -12,8 +12,9 @@ import (
|
||||
var _ api.VersionServer = &Service{}
|
||||
|
||||
func init() {
|
||||
plugin.Register("version-grpc", &plugin.Registration{
|
||||
plugin.Register(&plugin.Registration{
|
||||
Type: plugin.GRPCPlugin,
|
||||
ID: "version",
|
||||
Init: New,
|
||||
})
|
||||
}
|
||||
|
@ -20,11 +20,11 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
plugin.Register("snapshot-btrfs", &plugin.Registration{
|
||||
plugin.Register(&plugin.Registration{
|
||||
ID: "btrfs",
|
||||
Type: plugin.SnapshotPlugin,
|
||||
Init: func(ic *plugin.InitContext) (interface{}, error) {
|
||||
root := filepath.Join(ic.Root, "snapshot", "btrfs")
|
||||
return NewSnapshotter(root)
|
||||
return NewSnapshotter(ic.Root)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -16,10 +16,11 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
plugin.Register("snapshot-naive", &plugin.Registration{
|
||||
plugin.Register(&plugin.Registration{
|
||||
Type: plugin.SnapshotPlugin,
|
||||
ID: "naive",
|
||||
Init: func(ic *plugin.InitContext) (interface{}, error) {
|
||||
return NewSnapshotter(filepath.Join(ic.Root, "snapshot", "naive"))
|
||||
return NewSnapshotter(ic.Root)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -20,10 +20,11 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
plugin.Register("snapshot-overlay", &plugin.Registration{
|
||||
plugin.Register(&plugin.Registration{
|
||||
Type: plugin.SnapshotPlugin,
|
||||
ID: "overlayfs",
|
||||
Init: func(ic *plugin.InitContext) (interface{}, error) {
|
||||
return NewSnapshotter(filepath.Join(ic.Root, "snapshot", "overlay"))
|
||||
return NewSnapshotter(ic.Root)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ package windows
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/containerd/containerd/mount"
|
||||
"github.com/containerd/containerd/plugin"
|
||||
@ -17,10 +16,11 @@ var (
|
||||
)
|
||||
|
||||
func init() {
|
||||
plugin.Register("snapshot-windows", &plugin.Registration{
|
||||
plugin.Register(&plugin.Registration{
|
||||
Type: plugin.SnapshotPlugin,
|
||||
ID: "windows",
|
||||
Init: func(ic *plugin.InitContext) (interface{}, error) {
|
||||
return NewSnapshotter(filepath.Join(ic.Root, "snapshot", "windows"))
|
||||
return NewSnapshotter(ic.Root)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -27,14 +27,15 @@ const (
|
||||
var _ = (plugin.Runtime)(&Runtime{})
|
||||
|
||||
func init() {
|
||||
plugin.Register(runtimeName, &plugin.Registration{
|
||||
plugin.Register(&plugin.Registration{
|
||||
ID: "windows",
|
||||
Type: plugin.RuntimePlugin,
|
||||
Init: New,
|
||||
})
|
||||
}
|
||||
|
||||
func New(ic *plugin.InitContext) (interface{}, error) {
|
||||
rootDir := filepath.Join(ic.Root, runtimeName)
|
||||
rootDir := filepath.Join(ic.Root)
|
||||
if err := os.MkdirAll(rootDir, 0755); err != nil {
|
||||
return nil, errors.Wrapf(err, "could not create state directory at %s", rootDir)
|
||||
}
|
||||
@ -63,7 +64,7 @@ func New(ic *plugin.InitContext) (interface{}, error) {
|
||||
}
|
||||
|
||||
// Try to delete the old state dir and recreate it
|
||||
stateDir := filepath.Join(ic.State, runtimeName)
|
||||
stateDir := filepath.Join(ic.Root, "state")
|
||||
if err := os.RemoveAll(stateDir); err != nil {
|
||||
log.G(c).WithError(err).Warnf("failed to cleanup old state directory at %s", stateDir)
|
||||
}
|
||||
@ -99,6 +100,10 @@ type RuntimeSpec struct {
|
||||
hcs.Configuration
|
||||
}
|
||||
|
||||
func (r *Runtime) ID() string {
|
||||
return fmt.Sprintf("%s.%s", plugin.RuntimePlugin, runtimeName)
|
||||
}
|
||||
|
||||
func (r *Runtime) Create(ctx context.Context, id string, opts plugin.CreateOpts) (plugin.Task, error) {
|
||||
var rtSpec RuntimeSpec
|
||||
if err := json.Unmarshal(opts.Spec, &rtSpec); err != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user