monitor.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  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/container"
  11. "github.com/docker/docker/libcontainerd"
  12. "github.com/docker/docker/restartmanager"
  13. )
  14. func (daemon *Daemon) setStateCounter(c *container.Container) {
  15. switch c.StateString() {
  16. case "paused":
  17. stateCtr.set(c.ID, "paused")
  18. case "running":
  19. stateCtr.set(c.ID, "running")
  20. default:
  21. stateCtr.set(c.ID, "stopped")
  22. }
  23. }
  24. // StateChanged updates daemon state changes from containerd
  25. func (daemon *Daemon) StateChanged(id string, e libcontainerd.StateInfo) error {
  26. c := daemon.containers.Get(id)
  27. if c == nil {
  28. return fmt.Errorf("no such container: %s", id)
  29. }
  30. switch e.State {
  31. case libcontainerd.StateOOM:
  32. // StateOOM is Linux specific and should never be hit on Windows
  33. if runtime.GOOS == "windows" {
  34. return errors.New("Received StateOOM from libcontainerd on Windows. This should never happen.")
  35. }
  36. daemon.updateHealthMonitor(c)
  37. daemon.LogContainerEvent(c, "oom")
  38. case libcontainerd.StateExit:
  39. c.Lock()
  40. c.StreamConfig.Wait()
  41. c.Reset(false)
  42. restart, wait, err := c.RestartManager().ShouldRestart(e.ExitCode, c.HasBeenManuallyStopped, time.Since(c.StartedAt))
  43. if err == nil && restart {
  44. c.RestartCount++
  45. c.SetRestarting(platformConstructExitStatus(e))
  46. } else {
  47. c.SetStopped(platformConstructExitStatus(e))
  48. defer daemon.autoRemove(c)
  49. }
  50. // cancel healthcheck here, they will be automatically
  51. // restarted if/when the container is started again
  52. daemon.stopHealthchecks(c)
  53. attributes := map[string]string{
  54. "exitCode": strconv.Itoa(int(e.ExitCode)),
  55. }
  56. daemon.LogContainerEventWithAttributes(c, "die", attributes)
  57. daemon.Cleanup(c)
  58. if err == nil && restart {
  59. go func() {
  60. err := <-wait
  61. if err == nil {
  62. if err = daemon.containerStart(c, "", "", false); err != nil {
  63. logrus.Debugf("failed to restart container: %+v", err)
  64. }
  65. }
  66. if err != nil {
  67. c.SetStopped(platformConstructExitStatus(e))
  68. defer daemon.autoRemove(c)
  69. if err != restartmanager.ErrRestartCanceled {
  70. logrus.Errorf("restartmanger wait error: %+v", err)
  71. }
  72. }
  73. }()
  74. }
  75. daemon.setStateCounter(c)
  76. defer c.Unlock()
  77. if err := c.ToDisk(); err != nil {
  78. return err
  79. }
  80. return daemon.postRunProcessing(c, e)
  81. case libcontainerd.StateExitProcess:
  82. if execConfig := c.ExecCommands.Get(e.ProcessID); execConfig != nil {
  83. ec := int(e.ExitCode)
  84. execConfig.Lock()
  85. defer execConfig.Unlock()
  86. execConfig.ExitCode = &ec
  87. execConfig.Running = false
  88. execConfig.StreamConfig.Wait()
  89. if err := execConfig.CloseStreams(); err != nil {
  90. logrus.Errorf("failed to cleanup exec %s streams: %s", c.ID, err)
  91. }
  92. // remove the exec command from the container's store only and not the
  93. // daemon's store so that the exec command can be inspected.
  94. c.ExecCommands.Delete(execConfig.ID)
  95. } else {
  96. logrus.Warnf("Ignoring StateExitProcess for %v but no exec command found", e)
  97. }
  98. case libcontainerd.StateStart, libcontainerd.StateRestore:
  99. // Container is already locked in this case
  100. c.SetRunning(int(e.Pid), e.State == libcontainerd.StateStart)
  101. c.HasBeenManuallyStopped = false
  102. c.HasBeenStartedBefore = true
  103. daemon.setStateCounter(c)
  104. if err := c.ToDisk(); err != nil {
  105. c.Reset(false)
  106. return err
  107. }
  108. daemon.initHealthMonitor(c)
  109. daemon.LogContainerEvent(c, "start")
  110. case libcontainerd.StatePause:
  111. // Container is already locked in this case
  112. c.Paused = true
  113. daemon.setStateCounter(c)
  114. if err := c.ToDisk(); err != nil {
  115. return err
  116. }
  117. daemon.updateHealthMonitor(c)
  118. daemon.LogContainerEvent(c, "pause")
  119. case libcontainerd.StateResume:
  120. // Container is already locked in this case
  121. c.Paused = false
  122. daemon.setStateCounter(c)
  123. if err := c.ToDisk(); err != nil {
  124. return err
  125. }
  126. daemon.updateHealthMonitor(c)
  127. daemon.LogContainerEvent(c, "unpause")
  128. }
  129. return nil
  130. }
  131. func (daemon *Daemon) autoRemove(c *container.Container) {
  132. c.Lock()
  133. ar := c.HostConfig.AutoRemove
  134. c.Unlock()
  135. if !ar {
  136. return
  137. }
  138. var err error
  139. if err = daemon.ContainerRm(c.ID, &types.ContainerRmConfig{ForceRemove: true, RemoveVolume: true}); err == nil {
  140. return
  141. }
  142. if c := daemon.containers.Get(c.ID); c == nil {
  143. return
  144. }
  145. if err != nil {
  146. logrus.WithError(err).WithField("container", c.ID).Error("error removing container")
  147. }
  148. }