stop.go 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. package daemon
  2. import (
  3. "fmt"
  4. "net/http"
  5. "time"
  6. "github.com/Sirupsen/logrus"
  7. "github.com/docker/docker/container"
  8. "github.com/docker/docker/errors"
  9. )
  10. // ContainerStop looks for the given container and terminates it,
  11. // waiting the given number of seconds before forcefully killing the
  12. // container. If a negative number of seconds is given, ContainerStop
  13. // will wait for a graceful termination. An error is returned if the
  14. // container is not found, is already stopped, or if there is a
  15. // problem stopping the container.
  16. func (daemon *Daemon) ContainerStop(name string, seconds int) error {
  17. container, err := daemon.GetContainer(name)
  18. if err != nil {
  19. return err
  20. }
  21. if !container.IsRunning() {
  22. err := fmt.Errorf("Container %s is already stopped", name)
  23. return errors.NewErrorWithStatusCode(err, http.StatusNotModified)
  24. }
  25. if err := daemon.containerStop(container, seconds); err != nil {
  26. return fmt.Errorf("Cannot stop container %s: %v", name, err)
  27. }
  28. return nil
  29. }
  30. // containerStop halts a container by sending a stop signal, waiting for the given
  31. // duration in seconds, and then calling SIGKILL and waiting for the
  32. // process to exit. If a negative duration is given, Stop will wait
  33. // for the initial signal forever. If the container is not running Stop returns
  34. // immediately.
  35. func (daemon *Daemon) containerStop(container *container.Container, seconds int) error {
  36. if !container.IsRunning() {
  37. return nil
  38. }
  39. daemon.stopHealthchecks(container)
  40. stopSignal := container.StopSignal()
  41. // 1. Send a stop signal
  42. if err := daemon.killPossiblyDeadProcess(container, stopSignal); err != nil {
  43. logrus.Infof("Failed to send signal %d to the process, force killing", stopSignal)
  44. if err := daemon.killPossiblyDeadProcess(container, 9); err != nil {
  45. return err
  46. }
  47. }
  48. // 2. Wait for the process to exit on its own
  49. if _, err := container.WaitStop(time.Duration(seconds) * time.Second); err != nil {
  50. logrus.Infof("Container %v failed to exit within %d seconds of signal %d - using the force", container.ID, seconds, stopSignal)
  51. // 3. If it doesn't, then send SIGKILL
  52. if err := daemon.Kill(container); err != nil {
  53. container.WaitStop(-1 * time.Second)
  54. logrus.Warn(err) // Don't return error because we only care that container is stopped, not what function stopped it
  55. }
  56. }
  57. daemon.LogContainerEvent(container, "stop")
  58. return nil
  59. }