mirror of https://github.com/docker/docs.git
				
				
				
			Shutdown plugins during daemon shutdown.
Signed-off-by: Anusha Ragunathan <anusha@docker.com> (cherry picked from commit 863ab9ab134d0baef3c7e5d745eded891e87e734) Signed-off-by: Tibor Vass <tibor@docker.com>
This commit is contained in:
		
							parent
							
								
									88d82eee4b
								
							
						
					
					
						commit
						db94be5084
					
				| 
						 | 
				
			
			@ -685,6 +685,8 @@ func (daemon *Daemon) Shutdown() error {
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pluginShutdown()
 | 
			
		||||
 | 
			
		||||
	if err := daemon.cleanupMounts(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,8 +2,15 @@
 | 
			
		|||
 | 
			
		||||
package daemon
 | 
			
		||||
 | 
			
		||||
import "github.com/docker/engine-api/types/container"
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/docker/docker/plugin"
 | 
			
		||||
	"github.com/docker/engine-api/types/container"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (daemon *Daemon) verifyExperimentalContainerSettings(hostConfig *container.HostConfig, config *container.Config) ([]string, error) {
 | 
			
		||||
	return nil, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func pluginShutdown() {
 | 
			
		||||
	plugin.GetManager().Shutdown()
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,3 +7,6 @@ import "github.com/docker/engine-api/types/container"
 | 
			
		|||
func (daemon *Daemon) verifyExperimentalContainerSettings(hostConfig *container.HostConfig, config *container.Config) ([]string, error) {
 | 
			
		||||
	return nil, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func pluginShutdown() {
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,9 @@ package main
 | 
			
		|||
import (
 | 
			
		||||
	"github.com/docker/docker/pkg/integration/checker"
 | 
			
		||||
	"github.com/go-check/check"
 | 
			
		||||
	"os"
 | 
			
		||||
	"os/exec"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var pluginName = "tiborvass/no-remove"
 | 
			
		||||
| 
						 | 
				
			
			@ -67,3 +70,66 @@ func (s *DockerDaemonSuite) TestDaemonRestartWithPluginDisabled(c *check.C) {
 | 
			
		|||
	c.Assert(out, checker.Contains, pluginName)
 | 
			
		||||
	c.Assert(out, checker.Contains, "false")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TestDaemonShutdownLiveRestoreWithPlugins leaves plugin running.
 | 
			
		||||
func (s *DockerDaemonSuite) TestDaemonShutdownLiveRestoreWithPlugins(c *check.C) {
 | 
			
		||||
	if err := s.d.Start("--live-restore"); err != nil {
 | 
			
		||||
		c.Fatalf("Could not start daemon: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pluginName); err != nil {
 | 
			
		||||
		c.Fatalf("Could not install plugin: %v %s", err, out)
 | 
			
		||||
	}
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if err := s.d.Restart("--live-restore"); err != nil {
 | 
			
		||||
			c.Fatalf("Could not restart daemon: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
		if out, err := s.d.Cmd("plugin", "disable", pluginName); err != nil {
 | 
			
		||||
			c.Fatalf("Could not disable plugin: %v %s", err, out)
 | 
			
		||||
		}
 | 
			
		||||
		if out, err := s.d.Cmd("plugin", "remove", pluginName); err != nil {
 | 
			
		||||
			c.Fatalf("Could not remove plugin: %v %s", err, out)
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	if err := s.d.Kill(); err != nil {
 | 
			
		||||
		c.Fatalf("Could not kill daemon: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cmd := exec.Command("pgrep", "-f", "plugin-no-remove")
 | 
			
		||||
	if out, ec, err := runCommandWithOutput(cmd); ec != 0 {
 | 
			
		||||
		c.Fatalf("Expected exit code '0', got %d err: %v output: %s ", ec, err, out)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TestDaemonShutdownWithPlugins shuts down running plugins.
 | 
			
		||||
func (s *DockerDaemonSuite) TestDaemonShutdownWithPlugins(c *check.C) {
 | 
			
		||||
	if err := s.d.Start(); err != nil {
 | 
			
		||||
		c.Fatalf("Could not start daemon: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	if out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", pluginName); err != nil {
 | 
			
		||||
		c.Fatalf("Could not install plugin: %v %s", err, out)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if err := s.d.Restart(); err != nil {
 | 
			
		||||
			c.Fatalf("Could not restart daemon: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
		if out, err := s.d.Cmd("plugin", "disable", pluginName); err != nil {
 | 
			
		||||
			c.Fatalf("Could not disable plugin: %v %s", err, out)
 | 
			
		||||
		}
 | 
			
		||||
		if out, err := s.d.Cmd("plugin", "remove", pluginName); err != nil {
 | 
			
		||||
			c.Fatalf("Could not remove plugin: %v %s", err, out)
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	if err := s.d.cmd.Process.Signal(os.Interrupt); err != nil {
 | 
			
		||||
		c.Fatalf("Could not kill daemon: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	time.Sleep(5 * time.Second)
 | 
			
		||||
 | 
			
		||||
	cmd := exec.Command("pgrep", "-f", "plugin-no-remove")
 | 
			
		||||
	if out, ec, err := runCommandWithOutput(cmd); ec != 1 {
 | 
			
		||||
		c.Fatalf("Expected exit code '1', got %d err: %v output: %s ", ec, err, out)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -47,6 +47,7 @@ type plugin struct {
 | 
			
		|||
	client            *plugins.Client
 | 
			
		||||
	restartManager    restartmanager.RestartManager
 | 
			
		||||
	runtimeSourcePath string
 | 
			
		||||
	exitChan          chan bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *plugin) Client() *plugins.Client {
 | 
			
		||||
| 
						 | 
				
			
			@ -98,6 +99,7 @@ type Manager struct {
 | 
			
		|||
	registryService  registry.Service
 | 
			
		||||
	handleLegacy     bool
 | 
			
		||||
	liveRestore      bool
 | 
			
		||||
	shutdown         bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetManager returns the singleton plugin Manager
 | 
			
		||||
| 
						 | 
				
			
			@ -250,10 +252,23 @@ func LookupWithCapability(name, capability string) (Plugin, error) {
 | 
			
		|||
	return nil, ErrInadequateCapability{name, capability}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StateChanged updates daemon inter...
 | 
			
		||||
// StateChanged updates plugin internals using from libcontainerd events.
 | 
			
		||||
func (pm *Manager) StateChanged(id string, e libcontainerd.StateInfo) error {
 | 
			
		||||
	logrus.Debugf("plugin state changed %s %#v", id, e)
 | 
			
		||||
 | 
			
		||||
	switch e.State {
 | 
			
		||||
	case libcontainerd.StateExit:
 | 
			
		||||
		pm.RLock()
 | 
			
		||||
		p, idOk := pm.plugins[id]
 | 
			
		||||
		pm.RUnlock()
 | 
			
		||||
		if !idOk {
 | 
			
		||||
			return ErrNotFound(id)
 | 
			
		||||
		}
 | 
			
		||||
		if pm.shutdown == true {
 | 
			
		||||
			p.exitChan <- true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,7 @@ import (
 | 
			
		|||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/Sirupsen/logrus"
 | 
			
		||||
	"github.com/docker/docker/libcontainerd"
 | 
			
		||||
| 
						 | 
				
			
			@ -128,3 +129,39 @@ func (pm *Manager) disable(p *plugin) error {
 | 
			
		|||
	pm.save()
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Shutdown stops all plugins and called during daemon shutdown.
 | 
			
		||||
func (pm *Manager) Shutdown() {
 | 
			
		||||
	pm.RLock()
 | 
			
		||||
	defer pm.RUnlock()
 | 
			
		||||
 | 
			
		||||
	pm.shutdown = true
 | 
			
		||||
	for _, p := range pm.plugins {
 | 
			
		||||
		if p.restartManager != nil {
 | 
			
		||||
			if err := p.restartManager.Cancel(); err != nil {
 | 
			
		||||
				logrus.Error(err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if pm.containerdClient != nil {
 | 
			
		||||
			p.exitChan = make(chan bool)
 | 
			
		||||
			err := pm.containerdClient.Signal(p.P.ID, int(syscall.SIGTERM))
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				logrus.Errorf("Sending SIGTERM to plugin failed with error: %v", err)
 | 
			
		||||
			} else {
 | 
			
		||||
				select {
 | 
			
		||||
				case <-p.exitChan:
 | 
			
		||||
					logrus.Debug("Clean shutdown of plugin")
 | 
			
		||||
				case <-time.After(time.Second * 10):
 | 
			
		||||
					logrus.Debug("Force shutdown plugin")
 | 
			
		||||
					if err := pm.containerdClient.Signal(p.P.ID, int(syscall.SIGKILL)); err != nil {
 | 
			
		||||
						logrus.Errorf("Sending SIGKILL to plugin failed with error: %v", err)
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			close(p.exitChan)
 | 
			
		||||
		}
 | 
			
		||||
		if err := os.RemoveAll(p.runtimeSourcePath); err != nil {
 | 
			
		||||
			logrus.Errorf("Remove plugin runtime failed with error: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,3 +23,7 @@ func (pm *Manager) disable(p *plugin) error {
 | 
			
		|||
func (pm *Manager) restore(p *plugin) error {
 | 
			
		||||
	return fmt.Errorf("Not implemented")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Shutdown plugins
 | 
			
		||||
func (pm *Manager) Shutdown() {
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue