Browse code

Merge pull request #13304 from coolljt0725/restart_daemon_with_paused_containers

Fix restart docker daemon with paused containers

Brian Goff authored on 2015/08/26 22:04:14
Showing 2 changed files
... ...
@@ -31,6 +31,7 @@ import (
31 31
 	"github.com/docker/docker/pkg/ioutils"
32 32
 	"github.com/docker/docker/pkg/namesgenerator"
33 33
 	"github.com/docker/docker/pkg/nat"
34
+	"github.com/docker/docker/pkg/signal"
34 35
 	"github.com/docker/docker/pkg/stringid"
35 36
 	"github.com/docker/docker/pkg/sysinfo"
36 37
 	"github.com/docker/docker/pkg/system"
... ...
@@ -766,9 +767,39 @@ func (daemon *Daemon) Shutdown() error {
766 766
 
767 767
 				go func() {
768 768
 					defer group.Done()
769
-					// If container failed to exit in 10 seconds of SIGTERM, then using the force
770
-					if err := c.Stop(10); err != nil {
771
-						logrus.Errorf("Stop container %s with error: %v", c.ID, err)
769
+					// TODO(windows): Handle docker restart with paused containers
770
+					if c.IsPaused() {
771
+						// To terminate a process in freezer cgroup, we should send
772
+						// SIGTERM to this process then unfreeze it, and the process will
773
+						// force to terminate immediately.
774
+						logrus.Debugf("Found container %s is paused, sending SIGTERM before unpause it", c.ID)
775
+						sig, ok := signal.SignalMap["TERM"]
776
+						if !ok {
777
+							logrus.Warnf("System does not support SIGTERM")
778
+							return
779
+						}
780
+						if err := daemon.Kill(c, int(sig)); err != nil {
781
+							logrus.Debugf("sending SIGTERM to container %s with error: %v", c.ID, err)
782
+							return
783
+						}
784
+						if err := c.Unpause(); err != nil {
785
+							logrus.Debugf("Failed to unpause container %s with error: %v", c.ID, err)
786
+							return
787
+						}
788
+						if _, err := c.WaitStop(10 * time.Second); err != nil {
789
+							logrus.Debugf("container %s failed to exit in 10 second of SIGTERM, sending SIGKILL to force", c.ID)
790
+							sig, ok := signal.SignalMap["KILL"]
791
+							if !ok {
792
+								logrus.Warnf("System does not support SIGKILL")
793
+								return
794
+							}
795
+							daemon.Kill(c, int(sig))
796
+						}
797
+					} else {
798
+						// If container failed to exit in 10 seconds of SIGTERM, then using the force
799
+						if err := c.Stop(10); err != nil {
800
+							logrus.Errorf("Stop container %s with error: %v", c.ID, err)
801
+						}
772 802
 					}
773 803
 					c.WaitStop(-1 * time.Second)
774 804
 					logrus.Debugf("container stopped %s", c.ID)
... ...
@@ -1624,3 +1624,41 @@ func (s *DockerDaemonSuite) TestDaemonWideLogConfig(c *check.C) {
1624 1624
 		c.Fatalf("Unexpected log-opt: %s, expected map[max-size:1k]", cfg)
1625 1625
 	}
1626 1626
 }
1627
+
1628
+func (s *DockerDaemonSuite) TestDaemonRestartWithPausedContainer(c *check.C) {
1629
+	if err := s.d.StartWithBusybox(); err != nil {
1630
+		c.Fatal(err)
1631
+	}
1632
+	if out, err := s.d.Cmd("run", "-i", "-d", "--name", "test", "busybox", "top"); err != nil {
1633
+		c.Fatal(err, out)
1634
+	}
1635
+	if out, err := s.d.Cmd("pause", "test"); err != nil {
1636
+		c.Fatal(err, out)
1637
+	}
1638
+	if err := s.d.Restart(); err != nil {
1639
+		c.Fatal(err)
1640
+	}
1641
+
1642
+	errchan := make(chan error)
1643
+	go func() {
1644
+		out, err := s.d.Cmd("start", "test")
1645
+		if err != nil {
1646
+			errchan <- fmt.Errorf("%v:\n%s", err, out)
1647
+		}
1648
+		name := strings.TrimSpace(out)
1649
+		if name != "test" {
1650
+			errchan <- fmt.Errorf("Paused container start error on docker daemon restart, expected 'test' but got '%s'", name)
1651
+		}
1652
+		close(errchan)
1653
+	}()
1654
+
1655
+	select {
1656
+	case <-time.After(5 * time.Second):
1657
+		c.Fatal("Waiting on start a container timed out")
1658
+	case err := <-errchan:
1659
+		if err != nil {
1660
+			c.Fatal(err)
1661
+		}
1662
+	}
1663
+
1664
+}