mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #24760 from anusha-ragunathan/plugin-events
Make daemon events listen for plugin lifecycle events.
This commit is contained in:
commit
297745b1cd
13 changed files with 167 additions and 106 deletions
|
@ -262,10 +262,6 @@ func (cli *DaemonCli) start() (err error) {
|
||||||
<-stopc // wait for daemonCli.start() to return
|
<-stopc // wait for daemonCli.start() to return
|
||||||
})
|
})
|
||||||
|
|
||||||
if err := pluginInit(cli.Config, containerdRemote, registryService); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
d, err := daemon.NewDaemon(cli.Config, registryService, containerdRemote)
|
d, err := daemon.NewDaemon(cli.Config, registryService, containerdRemote)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Error starting daemon: %v", err)
|
return fmt.Errorf("Error starting daemon: %v", err)
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
// +build !experimental !linux
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/docker/docker/daemon"
|
|
||||||
"github.com/docker/docker/libcontainerd"
|
|
||||||
"github.com/docker/docker/registry"
|
|
||||||
)
|
|
||||||
|
|
||||||
func pluginInit(config *daemon.Config, remote libcontainerd.Remote, rs registry.Service) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
// +build linux,experimental
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/docker/docker/daemon"
|
|
||||||
"github.com/docker/docker/libcontainerd"
|
|
||||||
"github.com/docker/docker/plugin"
|
|
||||||
"github.com/docker/docker/registry"
|
|
||||||
)
|
|
||||||
|
|
||||||
func pluginInit(config *daemon.Config, remote libcontainerd.Remote, rs registry.Service) error {
|
|
||||||
return plugin.Init(config.Root, remote, rs, config.LiveRestore)
|
|
||||||
}
|
|
|
@ -604,6 +604,10 @@ func NewDaemon(config *Config, registryService registry.Service, containerdRemot
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := pluginInit(d, config, containerdRemote); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return d, nil
|
return d, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
package daemon
|
package daemon
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/docker/docker/libcontainerd"
|
||||||
"github.com/docker/docker/plugin"
|
"github.com/docker/docker/plugin"
|
||||||
"github.com/docker/engine-api/types/container"
|
"github.com/docker/engine-api/types/container"
|
||||||
)
|
)
|
||||||
|
@ -11,6 +12,15 @@ func (daemon *Daemon) verifyExperimentalContainerSettings(hostConfig *container.
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func pluginShutdown() {
|
func pluginInit(d *Daemon, cfg *Config, remote libcontainerd.Remote) error {
|
||||||
plugin.GetManager().Shutdown()
|
return plugin.Init(cfg.Root, remote, d.RegistryService, cfg.LiveRestore, d.LogPluginEvent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func pluginShutdown() {
|
||||||
|
manager := plugin.GetManager()
|
||||||
|
// Check for a valid manager object. In error conditions, daemon init can fail
|
||||||
|
// and shutdown called, before plugin manager is initialized.
|
||||||
|
if manager != nil {
|
||||||
|
manager.Shutdown()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,18 @@
|
||||||
|
|
||||||
package daemon
|
package daemon
|
||||||
|
|
||||||
import "github.com/docker/engine-api/types/container"
|
import (
|
||||||
|
"github.com/docker/docker/libcontainerd"
|
||||||
|
"github.com/docker/engine-api/types/container"
|
||||||
|
)
|
||||||
|
|
||||||
func (daemon *Daemon) verifyExperimentalContainerSettings(hostConfig *container.HostConfig, config *container.Config) ([]string, error) {
|
func (daemon *Daemon) verifyExperimentalContainerSettings(hostConfig *container.HostConfig, config *container.Config) ([]string, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func pluginInit(d *Daemon, config *Config, remote libcontainerd.Remote) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func pluginShutdown() {
|
func pluginShutdown() {
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,21 @@ func (daemon *Daemon) LogImageEventWithAttributes(imageID, refName, action strin
|
||||||
daemon.EventsService.Log(action, events.ImageEventType, actor)
|
daemon.EventsService.Log(action, events.ImageEventType, actor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LogPluginEvent generates an event related to a plugin with only the default attributes.
|
||||||
|
func (daemon *Daemon) LogPluginEvent(pluginID, refName, action string) {
|
||||||
|
daemon.LogPluginEventWithAttributes(pluginID, refName, action, map[string]string{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogPluginEventWithAttributes generates an event related to a plugin with specific given attributes.
|
||||||
|
func (daemon *Daemon) LogPluginEventWithAttributes(pluginID, refName, action string, attributes map[string]string) {
|
||||||
|
attributes["name"] = refName
|
||||||
|
actor := events.Actor{
|
||||||
|
ID: pluginID,
|
||||||
|
Attributes: attributes,
|
||||||
|
}
|
||||||
|
daemon.EventsService.Log(action, events.PluginEventType, actor)
|
||||||
|
}
|
||||||
|
|
||||||
// LogVolumeEvent generates an event related to a volume.
|
// LogVolumeEvent generates an event related to a volume.
|
||||||
func (daemon *Daemon) LogVolumeEvent(volumeID, action string, attributes map[string]string) {
|
func (daemon *Daemon) LogVolumeEvent(volumeID, action string, attributes map[string]string) {
|
||||||
actor := events.Actor{
|
actor := events.Actor{
|
||||||
|
|
|
@ -22,6 +22,7 @@ func (ef *Filter) Include(ev events.Message) bool {
|
||||||
ef.filter.ExactMatch("type", ev.Type) &&
|
ef.filter.ExactMatch("type", ev.Type) &&
|
||||||
ef.matchDaemon(ev) &&
|
ef.matchDaemon(ev) &&
|
||||||
ef.matchContainer(ev) &&
|
ef.matchContainer(ev) &&
|
||||||
|
ef.matchPlugin(ev) &&
|
||||||
ef.matchVolume(ev) &&
|
ef.matchVolume(ev) &&
|
||||||
ef.matchNetwork(ev) &&
|
ef.matchNetwork(ev) &&
|
||||||
ef.matchImage(ev) &&
|
ef.matchImage(ev) &&
|
||||||
|
@ -43,6 +44,10 @@ func (ef *Filter) matchContainer(ev events.Message) bool {
|
||||||
return ef.fuzzyMatchName(ev, events.ContainerEventType)
|
return ef.fuzzyMatchName(ev, events.ContainerEventType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ef *Filter) matchPlugin(ev events.Message) bool {
|
||||||
|
return ef.fuzzyMatchName(ev, events.PluginEventType)
|
||||||
|
}
|
||||||
|
|
||||||
func (ef *Filter) matchVolume(ev events.Message) bool {
|
func (ef *Filter) matchVolume(ev events.Message) bool {
|
||||||
return ef.fuzzyMatchName(ev, events.VolumeEventType)
|
return ef.fuzzyMatchName(ev, events.VolumeEventType)
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,10 @@ Docker images report the following events:
|
||||||
|
|
||||||
delete, import, load, pull, push, save, tag, untag
|
delete, import, load, pull, push, save, tag, untag
|
||||||
|
|
||||||
|
Docker plugins(experimental) report the following events:
|
||||||
|
|
||||||
|
install, enable, disable, remove
|
||||||
|
|
||||||
Docker volumes report the following events:
|
Docker volumes report the following events:
|
||||||
|
|
||||||
create, mount, unmount, destroy
|
create, mount, unmount, destroy
|
||||||
|
@ -74,6 +78,7 @@ The currently supported filters are:
|
||||||
* container (`container=<name or id>`)
|
* container (`container=<name or id>`)
|
||||||
* event (`event=<event action>`)
|
* event (`event=<event action>`)
|
||||||
* image (`image=<tag or id>`)
|
* image (`image=<tag or id>`)
|
||||||
|
* plugin (experimental) (`plugin=<name or id>`)
|
||||||
* label (`label=<key>` or `label=<key>=<value>`)
|
* label (`label=<key>` or `label=<key>=<value>`)
|
||||||
* type (`type=<container or image or volume or network or daemon>`)
|
* type (`type=<container or image or volume or network or daemon>`)
|
||||||
* volume (`volume=<name or id>`)
|
* volume (`volume=<name or id>`)
|
||||||
|
@ -171,3 +176,7 @@ relative to the current time on the client machine:
|
||||||
$ docker events --filter 'type=network'
|
$ docker events --filter 'type=network'
|
||||||
2015-12-23T21:38:24.705709133Z network create 8b111217944ba0ba844a65b13efcd57dc494932ee2527577758f939315ba2c5b (name=test-event-network-local, type=bridge)
|
2015-12-23T21:38:24.705709133Z network create 8b111217944ba0ba844a65b13efcd57dc494932ee2527577758f939315ba2c5b (name=test-event-network-local, type=bridge)
|
||||||
2015-12-23T21:38:25.119625123Z network connect 8b111217944ba0ba844a65b13efcd57dc494932ee2527577758f939315ba2c5b (name=test-event-network-local, container=b4be644031a3d90b400f88ab3d4bdf4dc23adb250e696b6328b85441abe2c54e, type=bridge)
|
2015-12-23T21:38:25.119625123Z network connect 8b111217944ba0ba844a65b13efcd57dc494932ee2527577758f939315ba2c5b (name=test-event-network-local, container=b4be644031a3d90b400f88ab3d4bdf4dc23adb250e696b6328b85441abe2c54e, type=bridge)
|
||||||
|
|
||||||
|
$ docker events --filter 'type=plugin' (experimental)
|
||||||
|
2016-07-25T17:30:14.825557616Z plugin pull ec7b87f2ce84330fe076e666f17dfc049d2d7ae0b8190763de94e1f2d105993f (name=tiborvass/no-remove:latest)
|
||||||
|
2016-07-25T17:30:14.888127370Z plugin enable ec7b87f2ce84330fe076e666f17dfc049d2d7ae0b8190763de94e1f2d105993f (name=tiborvass/no-remove:latest)
|
||||||
|
|
|
@ -297,6 +297,32 @@ func (s *DockerSuite) TestEventsImageLoad(c *check.C) {
|
||||||
c.Assert(matches["action"], checker.Equals, "save", check.Commentf("matches: %v\nout:\n%s\n", matches, out))
|
c.Assert(matches["action"], checker.Equals, "save", check.Commentf("matches: %v\nout:\n%s\n", matches, out))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *DockerSuite) TestEventsPluginOps(c *check.C) {
|
||||||
|
testRequires(c, DaemonIsLinux, ExperimentalDaemon)
|
||||||
|
|
||||||
|
pluginName := "tiborvass/no-remove:latest"
|
||||||
|
since := daemonUnixTime(c)
|
||||||
|
|
||||||
|
dockerCmd(c, "plugin", "install", pluginName, "--grant-all-permissions")
|
||||||
|
dockerCmd(c, "plugin", "disable", pluginName)
|
||||||
|
dockerCmd(c, "plugin", "remove", pluginName)
|
||||||
|
|
||||||
|
out, _ := dockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c))
|
||||||
|
events := strings.Split(out, "\n")
|
||||||
|
events = events[:len(events)-1]
|
||||||
|
|
||||||
|
nEvents := len(events)
|
||||||
|
c.Assert(nEvents, checker.GreaterOrEqualThan, 4)
|
||||||
|
|
||||||
|
pluginEvents := eventActionsByIDAndType(c, events, pluginName, "plugin")
|
||||||
|
c.Assert(pluginEvents, checker.HasLen, 4, check.Commentf("events: %v", events))
|
||||||
|
|
||||||
|
c.Assert(pluginEvents[0], checker.Equals, "pull", check.Commentf(out))
|
||||||
|
c.Assert(pluginEvents[1], checker.Equals, "enable", check.Commentf(out))
|
||||||
|
c.Assert(pluginEvents[2], checker.Equals, "disable", check.Commentf(out))
|
||||||
|
c.Assert(pluginEvents[3], checker.Equals, "remove", check.Commentf(out))
|
||||||
|
}
|
||||||
|
|
||||||
func (s *DockerSuite) TestEventsFilters(c *check.C) {
|
func (s *DockerSuite) TestEventsFilters(c *check.C) {
|
||||||
since := daemonUnixTime(c)
|
since := daemonUnixTime(c)
|
||||||
dockerCmd(c, "run", "--rm", "busybox", "true")
|
dockerCmd(c, "run", "--rm", "busybox", "true")
|
||||||
|
|
|
@ -22,7 +22,11 @@ func (pm *Manager) Disable(name string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return pm.disable(p)
|
if err := pm.disable(p); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pm.pluginEventLogger(p.PluginObj.ID, name, "disable")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable activates a plugin, which implies that they are ready to be used by containers.
|
// Enable activates a plugin, which implies that they are ready to be used by containers.
|
||||||
|
@ -31,7 +35,11 @@ func (pm *Manager) Enable(name string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return pm.enable(p)
|
if err := pm.enable(p); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pm.pluginEventLogger(p.PluginObj.ID, name, "enable")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inspect examines a plugin manifest
|
// Inspect examines a plugin manifest
|
||||||
|
@ -40,10 +48,10 @@ func (pm *Manager) Inspect(name string) (tp types.Plugin, err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return tp, err
|
return tp, err
|
||||||
}
|
}
|
||||||
return p.P, nil
|
return p.PluginObj, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pull pulls a plugin and enables it.
|
// Pull pulls a plugin and computes the privileges required to install it.
|
||||||
func (pm *Manager) Pull(name string, metaHeader http.Header, authConfig *types.AuthConfig) (types.PluginPrivileges, error) {
|
func (pm *Manager) Pull(name string, metaHeader http.Header, authConfig *types.AuthConfig) (types.PluginPrivileges, error) {
|
||||||
ref, err := reference.ParseNamed(name)
|
ref, err := reference.ParseNamed(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -86,14 +94,15 @@ func (pm *Manager) Pull(name string, metaHeader http.Header, authConfig *types.A
|
||||||
pm.save()
|
pm.save()
|
||||||
pm.Unlock()
|
pm.Unlock()
|
||||||
|
|
||||||
return computePrivileges(&p.P.Manifest), nil
|
pm.pluginEventLogger(pluginID, name, "pull")
|
||||||
|
return computePrivileges(&p.PluginObj.Manifest), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// List displays the list of plugins and associated metadata.
|
// List displays the list of plugins and associated metadata.
|
||||||
func (pm *Manager) List() ([]types.Plugin, error) {
|
func (pm *Manager) List() ([]types.Plugin, error) {
|
||||||
out := make([]types.Plugin, 0, len(pm.plugins))
|
out := make([]types.Plugin, 0, len(pm.plugins))
|
||||||
for _, p := range pm.plugins {
|
for _, p := range pm.plugins {
|
||||||
out = append(out, p.P)
|
out = append(out, p.PluginObj)
|
||||||
}
|
}
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
@ -104,7 +113,7 @@ func (pm *Manager) Push(name string, metaHeader http.Header, authConfig *types.A
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
dest := filepath.Join(pm.libRoot, p.P.ID)
|
dest := filepath.Join(pm.libRoot, p.PluginObj.ID)
|
||||||
config, err := os.Open(filepath.Join(dest, "manifest.json"))
|
config, err := os.Open(filepath.Join(dest, "manifest.json"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -127,7 +136,11 @@ func (pm *Manager) Remove(name string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return pm.remove(p)
|
if err := pm.remove(p); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pm.pluginEventLogger(p.PluginObj.ID, name, "remove")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set sets plugin args
|
// Set sets plugin args
|
||||||
|
|
|
@ -43,7 +43,7 @@ func (e ErrInadequateCapability) Error() string {
|
||||||
|
|
||||||
type plugin struct {
|
type plugin struct {
|
||||||
//sync.RWMutex TODO
|
//sync.RWMutex TODO
|
||||||
P types.Plugin `json:"plugin"`
|
PluginObj types.Plugin `json:"plugin"`
|
||||||
client *plugins.Client
|
client *plugins.Client
|
||||||
restartManager restartmanager.RestartManager
|
restartManager restartmanager.RestartManager
|
||||||
runtimeSourcePath string
|
runtimeSourcePath string
|
||||||
|
@ -60,51 +60,53 @@ func (p *plugin) IsLegacy() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *plugin) Name() string {
|
func (p *plugin) Name() string {
|
||||||
name := p.P.Name
|
name := p.PluginObj.Name
|
||||||
if len(p.P.Tag) > 0 {
|
if len(p.PluginObj.Tag) > 0 {
|
||||||
// TODO: this feels hacky, maybe we should be storing the distribution reference rather than splitting these
|
// TODO: this feels hacky, maybe we should be storing the distribution reference rather than splitting these
|
||||||
name += ":" + p.P.Tag
|
name += ":" + p.PluginObj.Tag
|
||||||
}
|
}
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pm *Manager) newPlugin(ref reference.Named, id string) *plugin {
|
func (pm *Manager) newPlugin(ref reference.Named, id string) *plugin {
|
||||||
p := &plugin{
|
p := &plugin{
|
||||||
P: types.Plugin{
|
PluginObj: types.Plugin{
|
||||||
Name: ref.Name(),
|
Name: ref.Name(),
|
||||||
ID: id,
|
ID: id,
|
||||||
},
|
},
|
||||||
runtimeSourcePath: filepath.Join(pm.runRoot, id),
|
runtimeSourcePath: filepath.Join(pm.runRoot, id),
|
||||||
}
|
}
|
||||||
if ref, ok := ref.(reference.NamedTagged); ok {
|
if ref, ok := ref.(reference.NamedTagged); ok {
|
||||||
p.P.Tag = ref.Tag()
|
p.PluginObj.Tag = ref.Tag()
|
||||||
}
|
}
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pm *Manager) restorePlugin(p *plugin) error {
|
func (pm *Manager) restorePlugin(p *plugin) error {
|
||||||
p.runtimeSourcePath = filepath.Join(pm.runRoot, p.P.ID)
|
p.runtimeSourcePath = filepath.Join(pm.runRoot, p.PluginObj.ID)
|
||||||
if p.P.Active {
|
if p.PluginObj.Active {
|
||||||
return pm.restore(p)
|
return pm.restore(p)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type pluginMap map[string]*plugin
|
type pluginMap map[string]*plugin
|
||||||
|
type eventLogger func(id, name, action string)
|
||||||
|
|
||||||
// Manager controls the plugin subsystem.
|
// Manager controls the plugin subsystem.
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
libRoot string
|
libRoot string
|
||||||
runRoot string
|
runRoot string
|
||||||
plugins pluginMap // TODO: figure out why save() doesn't json encode *plugin object
|
plugins pluginMap // TODO: figure out why save() doesn't json encode *plugin object
|
||||||
nameToID map[string]string
|
nameToID map[string]string
|
||||||
handlers map[string]func(string, *plugins.Client)
|
handlers map[string]func(string, *plugins.Client)
|
||||||
containerdClient libcontainerd.Client
|
containerdClient libcontainerd.Client
|
||||||
registryService registry.Service
|
registryService registry.Service
|
||||||
handleLegacy bool
|
handleLegacy bool
|
||||||
liveRestore bool
|
liveRestore bool
|
||||||
shutdown bool
|
shutdown bool
|
||||||
|
pluginEventLogger eventLogger
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetManager returns the singleton plugin Manager
|
// GetManager returns the singleton plugin Manager
|
||||||
|
@ -114,21 +116,22 @@ func GetManager() *Manager {
|
||||||
|
|
||||||
// Init (was NewManager) instantiates the singleton Manager.
|
// Init (was NewManager) instantiates the singleton Manager.
|
||||||
// TODO: revert this to NewManager once we get rid of all the singletons.
|
// TODO: revert this to NewManager once we get rid of all the singletons.
|
||||||
func Init(root string, remote libcontainerd.Remote, rs registry.Service, liveRestore bool) (err error) {
|
func Init(root string, remote libcontainerd.Remote, rs registry.Service, liveRestore bool, evL eventLogger) (err error) {
|
||||||
if manager != nil {
|
if manager != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
root = filepath.Join(root, "plugins")
|
root = filepath.Join(root, "plugins")
|
||||||
manager = &Manager{
|
manager = &Manager{
|
||||||
libRoot: root,
|
libRoot: root,
|
||||||
runRoot: "/run/docker",
|
runRoot: "/run/docker",
|
||||||
plugins: make(map[string]*plugin),
|
plugins: make(map[string]*plugin),
|
||||||
nameToID: make(map[string]string),
|
nameToID: make(map[string]string),
|
||||||
handlers: make(map[string]func(string, *plugins.Client)),
|
handlers: make(map[string]func(string, *plugins.Client)),
|
||||||
registryService: rs,
|
registryService: rs,
|
||||||
handleLegacy: true,
|
handleLegacy: true,
|
||||||
liveRestore: liveRestore,
|
liveRestore: liveRestore,
|
||||||
|
pluginEventLogger: evL,
|
||||||
}
|
}
|
||||||
if err := os.MkdirAll(manager.runRoot, 0700); err != nil {
|
if err := os.MkdirAll(manager.runRoot, 0700); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -180,7 +183,7 @@ func FindWithCapability(capability string) ([]Plugin, error) {
|
||||||
defer manager.RUnlock()
|
defer manager.RUnlock()
|
||||||
pluginLoop:
|
pluginLoop:
|
||||||
for _, p := range manager.plugins {
|
for _, p := range manager.plugins {
|
||||||
for _, typ := range p.P.Manifest.Interface.Types {
|
for _, typ := range p.PluginObj.Manifest.Interface.Types {
|
||||||
if typ.Capability != capability || typ.Prefix != "docker" {
|
if typ.Capability != capability || typ.Prefix != "docker" {
|
||||||
continue pluginLoop
|
continue pluginLoop
|
||||||
}
|
}
|
||||||
|
@ -242,7 +245,7 @@ func LookupWithCapability(name, capability string) (Plugin, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
capability = strings.ToLower(capability)
|
capability = strings.ToLower(capability)
|
||||||
for _, typ := range p.P.Manifest.Interface.Types {
|
for _, typ := range p.PluginObj.Manifest.Interface.Types {
|
||||||
if typ.Capability == capability && typ.Prefix == "docker" {
|
if typ.Capability == capability && typ.Prefix == "docker" {
|
||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
@ -312,8 +315,8 @@ func (pm *Manager) init() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
pm.Lock()
|
pm.Lock()
|
||||||
pm.nameToID[p.Name()] = p.P.ID
|
pm.nameToID[p.Name()] = p.PluginObj.ID
|
||||||
requiresManualRestore := !pm.liveRestore && p.P.Active
|
requiresManualRestore := !pm.liveRestore && p.PluginObj.Active
|
||||||
pm.Unlock()
|
pm.Unlock()
|
||||||
|
|
||||||
if requiresManualRestore {
|
if requiresManualRestore {
|
||||||
|
@ -329,44 +332,44 @@ func (pm *Manager) init() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pm *Manager) initPlugin(p *plugin) error {
|
func (pm *Manager) initPlugin(p *plugin) error {
|
||||||
dt, err := os.Open(filepath.Join(pm.libRoot, p.P.ID, "manifest.json"))
|
dt, err := os.Open(filepath.Join(pm.libRoot, p.PluginObj.ID, "manifest.json"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = json.NewDecoder(dt).Decode(&p.P.Manifest)
|
err = json.NewDecoder(dt).Decode(&p.PluginObj.Manifest)
|
||||||
dt.Close()
|
dt.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
p.P.Config.Mounts = make([]types.PluginMount, len(p.P.Manifest.Mounts))
|
p.PluginObj.Config.Mounts = make([]types.PluginMount, len(p.PluginObj.Manifest.Mounts))
|
||||||
for i, mount := range p.P.Manifest.Mounts {
|
for i, mount := range p.PluginObj.Manifest.Mounts {
|
||||||
p.P.Config.Mounts[i] = mount
|
p.PluginObj.Config.Mounts[i] = mount
|
||||||
}
|
}
|
||||||
p.P.Config.Env = make([]string, 0, len(p.P.Manifest.Env))
|
p.PluginObj.Config.Env = make([]string, 0, len(p.PluginObj.Manifest.Env))
|
||||||
for _, env := range p.P.Manifest.Env {
|
for _, env := range p.PluginObj.Manifest.Env {
|
||||||
if env.Value != nil {
|
if env.Value != nil {
|
||||||
p.P.Config.Env = append(p.P.Config.Env, fmt.Sprintf("%s=%s", env.Name, *env.Value))
|
p.PluginObj.Config.Env = append(p.PluginObj.Config.Env, fmt.Sprintf("%s=%s", env.Name, *env.Value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
copy(p.P.Config.Args, p.P.Manifest.Args.Value)
|
copy(p.PluginObj.Config.Args, p.PluginObj.Manifest.Args.Value)
|
||||||
|
|
||||||
f, err := os.Create(filepath.Join(pm.libRoot, p.P.ID, "plugin-config.json"))
|
f, err := os.Create(filepath.Join(pm.libRoot, p.PluginObj.ID, "plugin-config.json"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = json.NewEncoder(f).Encode(&p.P.Config)
|
err = json.NewEncoder(f).Encode(&p.PluginObj.Config)
|
||||||
f.Close()
|
f.Close()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pm *Manager) remove(p *plugin) error {
|
func (pm *Manager) remove(p *plugin) error {
|
||||||
if p.P.Active {
|
if p.PluginObj.Active {
|
||||||
return fmt.Errorf("plugin %s is active", p.Name())
|
return fmt.Errorf("plugin %s is active", p.Name())
|
||||||
}
|
}
|
||||||
pm.Lock() // fixme: lock single record
|
pm.Lock() // fixme: lock single record
|
||||||
defer pm.Unlock()
|
defer pm.Unlock()
|
||||||
delete(pm.plugins, p.P.ID)
|
delete(pm.plugins, p.PluginObj.ID)
|
||||||
delete(pm.nameToID, p.Name())
|
delete(pm.nameToID, p.Name())
|
||||||
pm.save()
|
pm.save()
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -21,7 +21,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (pm *Manager) enable(p *plugin) error {
|
func (pm *Manager) enable(p *plugin) error {
|
||||||
if p.P.Active {
|
if p.PluginObj.Active {
|
||||||
return fmt.Errorf("plugin %s is already enabled", p.Name())
|
return fmt.Errorf("plugin %s is already enabled", p.Name())
|
||||||
}
|
}
|
||||||
spec, err := pm.initSpec(p)
|
spec, err := pm.initSpec(p)
|
||||||
|
@ -30,14 +30,14 @@ func (pm *Manager) enable(p *plugin) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
p.restartManager = restartmanager.New(container.RestartPolicy{Name: "always"}, 0)
|
p.restartManager = restartmanager.New(container.RestartPolicy{Name: "always"}, 0)
|
||||||
if err := pm.containerdClient.Create(p.P.ID, libcontainerd.Spec(*spec), libcontainerd.WithRestartManager(p.restartManager)); err != nil { // POC-only
|
if err := pm.containerdClient.Create(p.PluginObj.ID, libcontainerd.Spec(*spec), libcontainerd.WithRestartManager(p.restartManager)); err != nil { // POC-only
|
||||||
if err := p.restartManager.Cancel(); err != nil {
|
if err := p.restartManager.Cancel(); err != nil {
|
||||||
logrus.Errorf("enable: restartManager.Cancel failed due to %v", err)
|
logrus.Errorf("enable: restartManager.Cancel failed due to %v", err)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
socket := p.P.Manifest.Interface.Socket
|
socket := p.PluginObj.Manifest.Interface.Socket
|
||||||
p.client, err = plugins.NewClient("unix://"+filepath.Join(p.runtimeSourcePath, socket), nil)
|
p.client, err = plugins.NewClient("unix://"+filepath.Join(p.runtimeSourcePath, socket), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err := p.restartManager.Cancel(); err != nil {
|
if err := p.restartManager.Cancel(); err != nil {
|
||||||
|
@ -47,11 +47,11 @@ func (pm *Manager) enable(p *plugin) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
pm.Lock() // fixme: lock single record
|
pm.Lock() // fixme: lock single record
|
||||||
p.P.Active = true
|
p.PluginObj.Active = true
|
||||||
pm.save()
|
pm.save()
|
||||||
pm.Unlock()
|
pm.Unlock()
|
||||||
|
|
||||||
for _, typ := range p.P.Manifest.Interface.Types {
|
for _, typ := range p.PluginObj.Manifest.Interface.Types {
|
||||||
if handler := pm.handlers[typ.String()]; handler != nil {
|
if handler := pm.handlers[typ.String()]; handler != nil {
|
||||||
handler(p.Name(), p.Client())
|
handler(p.Name(), p.Client())
|
||||||
}
|
}
|
||||||
|
@ -62,19 +62,19 @@ func (pm *Manager) enable(p *plugin) error {
|
||||||
|
|
||||||
func (pm *Manager) restore(p *plugin) error {
|
func (pm *Manager) restore(p *plugin) error {
|
||||||
p.restartManager = restartmanager.New(container.RestartPolicy{Name: "always"}, 0)
|
p.restartManager = restartmanager.New(container.RestartPolicy{Name: "always"}, 0)
|
||||||
return pm.containerdClient.Restore(p.P.ID, libcontainerd.WithRestartManager(p.restartManager))
|
return pm.containerdClient.Restore(p.PluginObj.ID, libcontainerd.WithRestartManager(p.restartManager))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pm *Manager) initSpec(p *plugin) (*specs.Spec, error) {
|
func (pm *Manager) initSpec(p *plugin) (*specs.Spec, error) {
|
||||||
s := oci.DefaultSpec()
|
s := oci.DefaultSpec()
|
||||||
|
|
||||||
rootfs := filepath.Join(pm.libRoot, p.P.ID, "rootfs")
|
rootfs := filepath.Join(pm.libRoot, p.PluginObj.ID, "rootfs")
|
||||||
s.Root = specs.Root{
|
s.Root = specs.Root{
|
||||||
Path: rootfs,
|
Path: rootfs,
|
||||||
Readonly: false, // TODO: all plugins should be readonly? settable in manifest?
|
Readonly: false, // TODO: all plugins should be readonly? settable in manifest?
|
||||||
}
|
}
|
||||||
|
|
||||||
mounts := append(p.P.Config.Mounts, types.PluginMount{
|
mounts := append(p.PluginObj.Config.Mounts, types.PluginMount{
|
||||||
Source: &p.runtimeSourcePath,
|
Source: &p.runtimeSourcePath,
|
||||||
Destination: defaultPluginRuntimeDestination,
|
Destination: defaultPluginRuntimeDestination,
|
||||||
Type: "bind",
|
Type: "bind",
|
||||||
|
@ -104,12 +104,12 @@ func (pm *Manager) initSpec(p *plugin) (*specs.Spec, error) {
|
||||||
s.Mounts = append(s.Mounts, m)
|
s.Mounts = append(s.Mounts, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
envs := make([]string, 1, len(p.P.Config.Env)+1)
|
envs := make([]string, 1, len(p.PluginObj.Config.Env)+1)
|
||||||
envs[0] = "PATH=" + system.DefaultPathEnv
|
envs[0] = "PATH=" + system.DefaultPathEnv
|
||||||
envs = append(envs, p.P.Config.Env...)
|
envs = append(envs, p.PluginObj.Config.Env...)
|
||||||
|
|
||||||
args := append(p.P.Manifest.Entrypoint, p.P.Config.Args...)
|
args := append(p.PluginObj.Manifest.Entrypoint, p.PluginObj.Config.Args...)
|
||||||
cwd := p.P.Manifest.Workdir
|
cwd := p.PluginObj.Manifest.Workdir
|
||||||
if len(cwd) == 0 {
|
if len(cwd) == 0 {
|
||||||
cwd = "/"
|
cwd = "/"
|
||||||
}
|
}
|
||||||
|
@ -124,19 +124,19 @@ func (pm *Manager) initSpec(p *plugin) (*specs.Spec, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pm *Manager) disable(p *plugin) error {
|
func (pm *Manager) disable(p *plugin) error {
|
||||||
if !p.P.Active {
|
if !p.PluginObj.Active {
|
||||||
return fmt.Errorf("plugin %s is already disabled", p.Name())
|
return fmt.Errorf("plugin %s is already disabled", p.Name())
|
||||||
}
|
}
|
||||||
if err := p.restartManager.Cancel(); err != nil {
|
if err := p.restartManager.Cancel(); err != nil {
|
||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
}
|
}
|
||||||
if err := pm.containerdClient.Signal(p.P.ID, int(syscall.SIGKILL)); err != nil {
|
if err := pm.containerdClient.Signal(p.PluginObj.ID, int(syscall.SIGKILL)); err != nil {
|
||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
}
|
}
|
||||||
os.RemoveAll(p.runtimeSourcePath)
|
os.RemoveAll(p.runtimeSourcePath)
|
||||||
pm.Lock() // fixme: lock single record
|
pm.Lock() // fixme: lock single record
|
||||||
defer pm.Unlock()
|
defer pm.Unlock()
|
||||||
p.P.Active = false
|
p.PluginObj.Active = false
|
||||||
pm.save()
|
pm.save()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -148,7 +148,7 @@ func (pm *Manager) Shutdown() {
|
||||||
|
|
||||||
pm.shutdown = true
|
pm.shutdown = true
|
||||||
for _, p := range pm.plugins {
|
for _, p := range pm.plugins {
|
||||||
if pm.liveRestore && p.P.Active {
|
if pm.liveRestore && p.PluginObj.Active {
|
||||||
logrus.Debug("Plugin active when liveRestore is set, skipping shutdown")
|
logrus.Debug("Plugin active when liveRestore is set, skipping shutdown")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -157,9 +157,9 @@ func (pm *Manager) Shutdown() {
|
||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if pm.containerdClient != nil && p.P.Active {
|
if pm.containerdClient != nil && p.PluginObj.Active {
|
||||||
p.exitChan = make(chan bool)
|
p.exitChan = make(chan bool)
|
||||||
err := pm.containerdClient.Signal(p.P.ID, int(syscall.SIGTERM))
|
err := pm.containerdClient.Signal(p.PluginObj.ID, int(syscall.SIGTERM))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorf("Sending SIGTERM to plugin failed with error: %v", err)
|
logrus.Errorf("Sending SIGTERM to plugin failed with error: %v", err)
|
||||||
} else {
|
} else {
|
||||||
|
@ -168,14 +168,14 @@ func (pm *Manager) Shutdown() {
|
||||||
logrus.Debug("Clean shutdown of plugin")
|
logrus.Debug("Clean shutdown of plugin")
|
||||||
case <-time.After(time.Second * 10):
|
case <-time.After(time.Second * 10):
|
||||||
logrus.Debug("Force shutdown plugin")
|
logrus.Debug("Force shutdown plugin")
|
||||||
if err := pm.containerdClient.Signal(p.P.ID, int(syscall.SIGKILL)); err != nil {
|
if err := pm.containerdClient.Signal(p.PluginObj.ID, int(syscall.SIGKILL)); err != nil {
|
||||||
logrus.Errorf("Sending SIGKILL to plugin failed with error: %v", err)
|
logrus.Errorf("Sending SIGKILL to plugin failed with error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
close(p.exitChan)
|
close(p.exitChan)
|
||||||
pm.Lock()
|
pm.Lock()
|
||||||
p.P.Active = false
|
p.PluginObj.Active = false
|
||||||
pm.save()
|
pm.save()
|
||||||
pm.Unlock()
|
pm.Unlock()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue