diff --git a/cmd/containerd/main.go b/cmd/containerd/main.go index bd2d27ae4..0f8947a65 100644 --- a/cmd/containerd/main.go +++ b/cmd/containerd/main.go @@ -104,7 +104,11 @@ func main() { if err := serveDebugAPI(); err != nil { return err } - runtimes, err := loadRuntimes() + monitor, err := loadMonitor() + if err != nil { + return err + } + runtimes, err := loadRuntimes(monitor) if err != nil { return err } @@ -237,7 +241,7 @@ func resolveContentStore() (*content.Store, error) { return content.NewStore(cp) } -func loadRuntimes() (map[string]containerd.Runtime, error) { +func loadRuntimes(monitor plugin.ContainerMonitor) (map[string]containerd.Runtime, error) { o := make(map[string]containerd.Runtime) for name, rr := range plugin.Registrations() { if rr.Type != plugin.RuntimePlugin { @@ -248,6 +252,7 @@ func loadRuntimes() (map[string]containerd.Runtime, error) { 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 { @@ -264,6 +269,30 @@ func loadRuntimes() (map[string]containerd.Runtime, error) { return o, nil } +func loadMonitor() (plugin.ContainerMonitor, error) { + var monitors []plugin.ContainerMonitor + for name, m := range plugin.Registrations() { + if m.Type != plugin.ContainerMonitorPlugin { + 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.ContainerMonitor)) + } + if len(monitors) == 0 { + return plugin.NewNoopMonitor(), nil + } + return plugin.NewMultiContainerMonitor(monitors...), nil +} + func loadSnapshotter(store *content.Store) (snapshot.Snapshotter, error) { for name, sr := range plugin.Registrations() { if sr.Type != plugin.SnapshotPlugin { diff --git a/container.go b/container.go index d1283f060..be44e7bdb 100644 --- a/container.go +++ b/container.go @@ -32,7 +32,3 @@ type State interface { // Pid is the main process id for the container Pid() uint32 } - -type ContainerMonitor interface { - Monitor(context.Context, Container) error -} diff --git a/plugin/monitor.go b/plugin/monitor.go new file mode 100644 index 000000000..1b4ccdfd9 --- /dev/null +++ b/plugin/monitor.go @@ -0,0 +1,54 @@ +package plugin + +import "github.com/docker/containerd" + +// ContainerMonitor provides an interface for monitoring of containers within containerd +type ContainerMonitor interface { + // Monitor adds the provided container to the monitor + Monitor(containerd.Container) error + // Stop stops and removes the provided container from the monitor + Stop(containerd.Container) error +} + +func NewMultiContainerMonitor(monitors ...ContainerMonitor) ContainerMonitor { + return &multiContainerMonitor{ + monitors: monitors, + } +} + +func NewNoopMonitor() ContainerMonitor { + return &noopContainerMonitor{} +} + +type noopContainerMonitor struct { +} + +func (mm *noopContainerMonitor) Monitor(c containerd.Container) error { + return nil +} + +func (mm *noopContainerMonitor) Stop(c containerd.Container) error { + return nil +} + +type multiContainerMonitor struct { + monitors []ContainerMonitor +} + +func (mm *multiContainerMonitor) Monitor(c containerd.Container) error { + for _, m := range mm.monitors { + if err := m.Monitor(c); err != nil { + return err + } + } + return nil +} + +func (mm *multiContainerMonitor) Stop(c containerd.Container) error { + for _, m := range mm.monitors { + if err := m.Stop(c); err != nil { + return err + } + } + return nil +} diff --git a/plugin/plugin.go b/plugin/plugin.go index de97e5859..1b0b958fe 100644 --- a/plugin/plugin.go +++ b/plugin/plugin.go @@ -18,6 +18,7 @@ const ( RuntimePlugin PluginType = iota + 1 GRPCPlugin SnapshotPlugin + ContainerMonitorPlugin ) type Registration struct { @@ -26,6 +27,7 @@ type Registration struct { Init func(*InitContext) (interface{}, error) } +// TODO(@crosbymichael): how to we keep this struct from growing but support dependency injection for loaded plugins? type InitContext struct { Root string State string @@ -34,6 +36,7 @@ type InitContext struct { Snapshotter snapshot.Snapshotter Config interface{} Context context.Context + Monitor ContainerMonitor } type Service interface {