manager_linux.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. // +build linux
  2. package plugin
  3. import (
  4. "fmt"
  5. "path/filepath"
  6. "syscall"
  7. "time"
  8. "github.com/Sirupsen/logrus"
  9. "github.com/docker/docker/libcontainerd"
  10. "github.com/docker/docker/oci"
  11. "github.com/docker/docker/pkg/mount"
  12. "github.com/docker/docker/pkg/plugins"
  13. "github.com/docker/docker/plugin/v2"
  14. specs "github.com/opencontainers/runtime-spec/specs-go"
  15. )
  16. func (pm *Manager) enable(p *v2.Plugin, c *controller, force bool) error {
  17. p.Rootfs = filepath.Join(pm.libRoot, p.PluginObj.ID, "rootfs")
  18. if p.IsEnabled() && !force {
  19. return fmt.Errorf("plugin %s is already enabled", p.Name())
  20. }
  21. spec, err := p.InitSpec(oci.DefaultSpec())
  22. if err != nil {
  23. return err
  24. }
  25. c.restart = true
  26. c.exitChan = make(chan bool)
  27. pm.mu.Lock()
  28. pm.cMap[p] = c
  29. pm.mu.Unlock()
  30. if p.PropagatedMount != "" {
  31. if err := mount.MakeRShared(p.PropagatedMount); err != nil {
  32. return err
  33. }
  34. }
  35. if err := pm.containerdClient.Create(p.GetID(), "", "", specs.Spec(*spec), attachToLog(p.GetID())); err != nil {
  36. if p.PropagatedMount != "" {
  37. if err := mount.Unmount(p.PropagatedMount); err != nil {
  38. logrus.Warnf("Could not unmount %s: %v", p.PropagatedMount, err)
  39. }
  40. }
  41. return err
  42. }
  43. return pm.pluginPostStart(p, c)
  44. }
  45. func (pm *Manager) pluginPostStart(p *v2.Plugin, c *controller) error {
  46. client, err := plugins.NewClientWithTimeout("unix://"+filepath.Join(p.GetRuntimeSourcePath(), p.GetSocket()), nil, c.timeoutInSecs)
  47. if err != nil {
  48. c.restart = false
  49. shutdownPlugin(p, c, pm.containerdClient)
  50. return err
  51. }
  52. p.SetPClient(client)
  53. pm.pluginStore.SetState(p, true)
  54. pm.pluginStore.CallHandler(p)
  55. return nil
  56. }
  57. func (pm *Manager) restore(p *v2.Plugin) error {
  58. if err := pm.containerdClient.Restore(p.GetID(), attachToLog(p.GetID())); err != nil {
  59. return err
  60. }
  61. if pm.liveRestore {
  62. c := &controller{}
  63. if pids, _ := pm.containerdClient.GetPidsForContainer(p.GetID()); len(pids) == 0 {
  64. // plugin is not running, so follow normal startup procedure
  65. return pm.enable(p, c, true)
  66. }
  67. c.exitChan = make(chan bool)
  68. c.restart = true
  69. pm.mu.Lock()
  70. pm.cMap[p] = c
  71. pm.mu.Unlock()
  72. return pm.pluginPostStart(p, c)
  73. }
  74. return nil
  75. }
  76. func shutdownPlugin(p *v2.Plugin, c *controller, containerdClient libcontainerd.Client) {
  77. pluginID := p.GetID()
  78. err := containerdClient.Signal(pluginID, int(syscall.SIGTERM))
  79. if err != nil {
  80. logrus.Errorf("Sending SIGTERM to plugin failed with error: %v", err)
  81. } else {
  82. select {
  83. case <-c.exitChan:
  84. logrus.Debug("Clean shutdown of plugin")
  85. case <-time.After(time.Second * 10):
  86. logrus.Debug("Force shutdown plugin")
  87. if err := containerdClient.Signal(pluginID, int(syscall.SIGKILL)); err != nil {
  88. logrus.Errorf("Sending SIGKILL to plugin failed with error: %v", err)
  89. }
  90. }
  91. }
  92. }
  93. func (pm *Manager) disable(p *v2.Plugin, c *controller) error {
  94. if !p.IsEnabled() {
  95. return fmt.Errorf("plugin %s is already disabled", p.Name())
  96. }
  97. c.restart = false
  98. shutdownPlugin(p, c, pm.containerdClient)
  99. pm.pluginStore.SetState(p, false)
  100. return nil
  101. }
  102. // Shutdown stops all plugins and called during daemon shutdown.
  103. func (pm *Manager) Shutdown() {
  104. plugins := pm.pluginStore.GetAll()
  105. for _, p := range plugins {
  106. pm.mu.RLock()
  107. c := pm.cMap[p]
  108. pm.mu.RUnlock()
  109. if pm.liveRestore && p.IsEnabled() {
  110. logrus.Debug("Plugin active when liveRestore is set, skipping shutdown")
  111. continue
  112. }
  113. if pm.containerdClient != nil && p.IsEnabled() {
  114. c.restart = false
  115. shutdownPlugin(p, c, pm.containerdClient)
  116. }
  117. }
  118. }