From c28a87cbc174dba89121b1c0708f9eb487da3ef8 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Mon, 21 Mar 2016 12:54:05 -0700 Subject: [PATCH] Handle term signals gracefully Signed-off-by: Michael Crosby --- containerd/main.go | 45 ++++++++++++++++++++++++++++++++------ containerd/main_linux.go | 14 ------------ containerd/main_windows.go | 29 ------------------------ 3 files changed, 38 insertions(+), 50 deletions(-) delete mode 100644 containerd/main_windows.go diff --git a/containerd/main.go b/containerd/main.go index d8d54e8..74f7048 100644 --- a/containerd/main.go +++ b/containerd/main.go @@ -4,7 +4,9 @@ import ( "fmt" "net" "os" + "os/signal" "sync" + "syscall" "time" "google.golang.org/grpc" @@ -14,6 +16,7 @@ import ( "github.com/docker/containerd" "github.com/docker/containerd/api/grpc/server" "github.com/docker/containerd/api/grpc/types" + "github.com/docker/containerd/osutils" "github.com/docker/containerd/supervisor" ) @@ -80,7 +83,11 @@ func main() { func daemon(address, stateDir string, concurrency int, runtimeName string) error { // setup a standard reaper so that we don't leave any zombies if we are still alive // this is just good practice because we are spawning new processes - go reapProcesses() + s := make(chan os.Signal, 2048) + signal.Notify(s, syscall.SIGCHLD, syscall.SIGTERM, syscall.SIGINT) + if err := osutils.SetSubreaper(1); err != nil { + logrus.WithField("error", err).Error("containerd: set subpreaper") + } sv, err := supervisor.New(stateDir, runtimeName) if err != nil { return err @@ -94,17 +101,41 @@ func daemon(address, stateDir string, concurrency int, runtimeName string) error if err := sv.Start(); err != nil { return err } - if err := os.RemoveAll(address); err != nil { - return err - } - l, err := net.Listen(defaultListenType, address) + server, err := startServer(address, sv) if err != nil { return err } + for ss := range s { + switch ss { + case syscall.SIGCHLD: + if _, err := osutils.Reap(); err != nil { + logrus.WithField("error", err).Warn("containerd: reap child processes") + } + default: + server.Stop() + os.Exit(0) + } + } + return nil +} + +func startServer(address string, sv *supervisor.Supervisor) (*grpc.Server, error) { + if err := os.RemoveAll(address); err != nil { + return nil, err + } + l, err := net.Listen(defaultListenType, address) + if err != nil { + return nil, err + } s := grpc.NewServer() types.RegisterAPIServer(s, server.NewServer(sv)) - logrus.Debugf("containerd: grpc api on %s", address) - return s.Serve(l) + go func() { + logrus.Debugf("containerd: grpc api on %s", address) + if err := s.Serve(l); err != nil { + logrus.WithField("error", err).Fatal("containerd: serve grpc") + } + }() + return s, nil } // getDefaultID returns the hostname for the instance host diff --git a/containerd/main_linux.go b/containerd/main_linux.go index 2abf327..49fc790 100644 --- a/containerd/main_linux.go +++ b/containerd/main_linux.go @@ -4,7 +4,6 @@ import ( "log" "net" "os" - "os/signal" "runtime" "syscall" "time" @@ -62,19 +61,6 @@ func checkLimits() error { return nil } -func reapProcesses() { - s := make(chan os.Signal, 2048) - signal.Notify(s, syscall.SIGCHLD) - if err := osutils.SetSubreaper(1); err != nil { - logrus.WithField("error", err).Error("containerd: set subpreaper") - } - for range s { - if _, err := osutils.Reap(); err != nil { - logrus.WithField("error", err).Error("containerd: reap child processes") - } - } -} - func processMetrics() { var ( g = metrics.NewGauge() diff --git a/containerd/main_windows.go b/containerd/main_windows.go deleted file mode 100644 index 06c5750..0000000 --- a/containerd/main_windows.go +++ /dev/null @@ -1,29 +0,0 @@ -package main - -import ( - "os" - - "github.com/codegangsta/cli" -) - -var defaultStateDir = os.Getenv("PROGRAMDATA") + `\docker\containerd` - -const ( - defaultListenType = "tcp" - defaultGRPCEndpoint = "localhost:2377" -) - -func appendPlatformFlags() { -} - -// TODO Windows: May be able to factor out entirely -func checkLimits() error { - return nil -} - -// No idea how to implement this on Windows. -func reapProcesses() { -} - -func setAppBefore(app *cli.App) { -}