monitor.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. package daemon
  2. import (
  3. "errors"
  4. "fmt"
  5. "runtime"
  6. "strconv"
  7. "time"
  8. "github.com/Sirupsen/logrus"
  9. "github.com/docker/docker/api/types"
  10. "github.com/docker/docker/libcontainerd"
  11. "github.com/docker/docker/restartmanager"
  12. )
  13. // StateChanged updates daemon state changes from containerd
  14. func (daemon *Daemon) StateChanged(id string, e libcontainerd.StateInfo) error {
  15. c := daemon.containers.Get(id)
  16. if c == nil {
  17. return fmt.Errorf("no such container: %s", id)
  18. }
  19. switch e.State {
  20. case libcontainerd.StateOOM:
  21. // StateOOM is Linux specific and should never be hit on Windows
  22. if runtime.GOOS == "windows" {
  23. return errors.New("Received StateOOM from libcontainerd on Windows. This should never happen.")
  24. }
  25. daemon.updateHealthMonitor(c)
  26. daemon.LogContainerEvent(c, "oom")
  27. case libcontainerd.StateExit:
  28. // if container's AutoRemove flag is set, remove it after clean up
  29. autoRemove := func() {
  30. if c.HostConfig.AutoRemove {
  31. if err := daemon.ContainerRm(c.ID, &types.ContainerRmConfig{ForceRemove: true, RemoveVolume: true}); err != nil {
  32. logrus.Errorf("can't remove container %s: %v", c.ID, err)
  33. }
  34. }
  35. }
  36. c.Lock()
  37. c.StreamConfig.Wait()
  38. c.Reset(false)
  39. restart, wait, err := c.RestartManager().ShouldRestart(e.ExitCode, false, time.Since(c.StartedAt))
  40. if err == nil && restart {
  41. c.RestartCount++
  42. c.SetRestarting(platformConstructExitStatus(e))
  43. } else {
  44. c.SetStopped(platformConstructExitStatus(e))
  45. defer autoRemove()
  46. }
  47. daemon.updateHealthMonitor(c)
  48. attributes := map[string]string{
  49. "exitCode": strconv.Itoa(int(e.ExitCode)),
  50. }
  51. daemon.LogContainerEventWithAttributes(c, "die", attributes)
  52. daemon.Cleanup(c)
  53. if err == nil && restart {
  54. go func() {
  55. err := <-wait
  56. if err == nil {
  57. if err = daemon.containerStart(c, "", "", false); err != nil {
  58. logrus.Debugf("failed to restart container: %+v", err)
  59. }
  60. }
  61. if err != nil {
  62. c.SetStopped(platformConstructExitStatus(e))
  63. defer autoRemove()
  64. if err != restartmanager.ErrRestartCanceled {
  65. logrus.Errorf("restartmanger wait error: %+v", err)
  66. }
  67. }
  68. }()
  69. }
  70. defer c.Unlock()
  71. if err := c.ToDisk(); err != nil {
  72. return err
  73. }
  74. return daemon.postRunProcessing(c, e)
  75. case libcontainerd.StateExitProcess:
  76. if execConfig := c.ExecCommands.Get(e.ProcessID); execConfig != nil {
  77. ec := int(e.ExitCode)
  78. execConfig.Lock()
  79. defer execConfig.Unlock()
  80. execConfig.ExitCode = &ec
  81. execConfig.Running = false
  82. execConfig.StreamConfig.Wait()
  83. if err := execConfig.CloseStreams(); err != nil {
  84. logrus.Errorf("%s: %s", c.ID, err)
  85. }
  86. // remove the exec command from the container's store only and not the
  87. // daemon's store so that the exec command can be inspected.
  88. c.ExecCommands.Delete(execConfig.ID)
  89. } else {
  90. logrus.Warnf("Ignoring StateExitProcess for %v but no exec command found", e)
  91. }
  92. case libcontainerd.StateStart, libcontainerd.StateRestore:
  93. // Container is already locked in this case
  94. c.SetRunning(int(e.Pid), e.State == libcontainerd.StateStart)
  95. c.HasBeenManuallyStopped = false
  96. c.HasBeenStartedBefore = true
  97. if err := c.ToDisk(); err != nil {
  98. c.Reset(false)
  99. return err
  100. }
  101. daemon.initHealthMonitor(c)
  102. daemon.LogContainerEvent(c, "start")
  103. case libcontainerd.StatePause:
  104. // Container is already locked in this case
  105. c.Paused = true
  106. if err := c.ToDisk(); err != nil {
  107. return err
  108. }
  109. daemon.updateHealthMonitor(c)
  110. daemon.LogContainerEvent(c, "pause")
  111. case libcontainerd.StateResume:
  112. // Container is already locked in this case
  113. c.Paused = false
  114. if err := c.ToDisk(); err != nil {
  115. return err
  116. }
  117. daemon.updateHealthMonitor(c)
  118. daemon.LogContainerEvent(c, "unpause")
  119. }
  120. return nil
  121. }