mirror of https://github.com/containers/podman.git
Merge pull request #7999 from mheon/signal_handler
Add a shutdown signal handler
This commit is contained in:
commit
6c0b600e7d
|
|
@ -17,6 +17,7 @@ import (
|
|||
"github.com/containers/podman/v2/libpod/events"
|
||||
"github.com/containers/podman/v2/libpod/image"
|
||||
"github.com/containers/podman/v2/libpod/lock"
|
||||
"github.com/containers/podman/v2/libpod/shutdown"
|
||||
"github.com/containers/podman/v2/pkg/cgroups"
|
||||
"github.com/containers/podman/v2/pkg/registries"
|
||||
"github.com/containers/podman/v2/pkg/rootless"
|
||||
|
|
@ -174,9 +175,21 @@ func newRuntimeFromConfig(ctx context.Context, conf *config.Config, options ...R
|
|||
}
|
||||
}
|
||||
|
||||
if err := shutdown.Start(); err != nil {
|
||||
return nil, errors.Wrapf(err, "error starting shutdown signal handler")
|
||||
}
|
||||
|
||||
if err := makeRuntime(ctx, runtime); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := shutdown.Register("libpod", func(sig os.Signal) error {
|
||||
os.Exit(1)
|
||||
return nil
|
||||
}); err != nil {
|
||||
logrus.Errorf("Error registering shutdown handler for libpod: %v", err)
|
||||
}
|
||||
|
||||
return runtime, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/containers/common/pkg/config"
|
||||
"github.com/containers/podman/v2/libpod/define"
|
||||
"github.com/containers/podman/v2/libpod/events"
|
||||
"github.com/containers/podman/v2/libpod/shutdown"
|
||||
"github.com/containers/podman/v2/pkg/cgroups"
|
||||
"github.com/containers/podman/v2/pkg/rootless"
|
||||
"github.com/containers/storage"
|
||||
|
|
@ -149,6 +150,10 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// Inhibit shutdown until creation succeeds
|
||||
shutdown.Inhibit()
|
||||
defer shutdown.Uninhibit()
|
||||
|
||||
// Allocate a lock for the container
|
||||
lock, err := r.lockManager.AllocateLock()
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,131 @@
|
|||
package shutdown
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var (
|
||||
stopped bool
|
||||
sigChan chan os.Signal
|
||||
cancelChan chan bool
|
||||
// Definitions of all on-shutdown handlers
|
||||
handlers map[string]func(os.Signal) error
|
||||
// Ordering that on-shutdown handlers will be invoked.
|
||||
handlerOrder []string
|
||||
shutdownInhibit sync.RWMutex
|
||||
)
|
||||
|
||||
// Start begins handling SIGTERM and SIGINT and will run the given on-signal
|
||||
// handlers when one is called. This can be cancelled by calling Stop().
|
||||
func Start() error {
|
||||
if sigChan != nil {
|
||||
// Already running, do nothing.
|
||||
return nil
|
||||
}
|
||||
|
||||
sigChan = make(chan os.Signal, 1)
|
||||
cancelChan = make(chan bool, 1)
|
||||
stopped = false
|
||||
|
||||
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
go func() {
|
||||
select {
|
||||
case <-cancelChan:
|
||||
signal.Stop(sigChan)
|
||||
close(sigChan)
|
||||
close(cancelChan)
|
||||
stopped = true
|
||||
return
|
||||
case sig := <-sigChan:
|
||||
logrus.Infof("Received shutdown signal %v, terminating!", sig)
|
||||
shutdownInhibit.Lock()
|
||||
for _, name := range handlerOrder {
|
||||
handler, ok := handlers[name]
|
||||
if !ok {
|
||||
logrus.Errorf("Shutdown handler %s definition not found!", name)
|
||||
continue
|
||||
}
|
||||
logrus.Infof("Invoking shutdown handler %s", name)
|
||||
if err := handler(sig); err != nil {
|
||||
logrus.Errorf("Error running shutdown handler %s: %v", name, err)
|
||||
}
|
||||
}
|
||||
shutdownInhibit.Unlock()
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop the shutdown signal handler.
|
||||
func Stop() error {
|
||||
if cancelChan == nil {
|
||||
return errors.New("shutdown signal handler has not yet been started")
|
||||
}
|
||||
if stopped {
|
||||
return nil
|
||||
}
|
||||
|
||||
cancelChan <- true
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Temporarily inhibit signals from shutting down Libpod.
|
||||
func Inhibit() {
|
||||
shutdownInhibit.RLock()
|
||||
}
|
||||
|
||||
// Stop inhibiting signals from shutting down Libpod.
|
||||
func Uninhibit() {
|
||||
shutdownInhibit.RUnlock()
|
||||
}
|
||||
|
||||
// Register registers a function that will be executed when Podman is terminated
|
||||
// by a signal. Handlers are invoked LIFO - the last handler registered is the
|
||||
// first run.
|
||||
func Register(name string, handler func(os.Signal) error) error {
|
||||
if handlers == nil {
|
||||
handlers = make(map[string]func(os.Signal) error)
|
||||
}
|
||||
|
||||
if _, ok := handlers[name]; ok {
|
||||
return errors.Errorf("handler with name %s already exists", name)
|
||||
}
|
||||
|
||||
handlers[name] = handler
|
||||
handlerOrder = append([]string{name}, handlerOrder...)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unregister un-registers a given shutdown handler.
|
||||
func Unregister(name string) error {
|
||||
if handlers == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, ok := handlers[name]; !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
delete(handlers, name)
|
||||
|
||||
newOrder := []string{}
|
||||
for _, checkName := range handlerOrder {
|
||||
if checkName != name {
|
||||
newOrder = append(newOrder, checkName)
|
||||
}
|
||||
}
|
||||
handlerOrder = newOrder
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -7,7 +7,6 @@ import (
|
|||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
goRuntime "runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
|
|
@ -15,6 +14,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/containers/podman/v2/libpod"
|
||||
"github.com/containers/podman/v2/libpod/shutdown"
|
||||
"github.com/containers/podman/v2/pkg/api/handlers"
|
||||
"github.com/containers/podman/v2/pkg/api/server/idle"
|
||||
"github.com/coreos/go-systemd/v22/activation"
|
||||
|
|
@ -180,8 +180,17 @@ func setupSystemd() {
|
|||
// Serve starts responding to HTTP requests.
|
||||
func (s *APIServer) Serve() error {
|
||||
setupSystemd()
|
||||
sigChan := make(chan os.Signal, 1)
|
||||
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
// Start the shutdown signal handler.
|
||||
if err := shutdown.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := shutdown.Register("server", func(sig os.Signal) error {
|
||||
return s.Shutdown()
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
errChan := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
|
|
@ -217,14 +226,7 @@ func (s *APIServer) Serve() error {
|
|||
errChan <- nil
|
||||
}()
|
||||
|
||||
select {
|
||||
case err := <-errChan:
|
||||
return err
|
||||
case sig := <-sigChan:
|
||||
logrus.Infof("APIServer terminated by signal %v", sig)
|
||||
}
|
||||
|
||||
return nil
|
||||
return <-errChan
|
||||
}
|
||||
|
||||
// Shutdown is a clean shutdown waiting on existing clients
|
||||
|
|
|
|||
|
|
@ -5,12 +5,17 @@ import (
|
|||
"syscall"
|
||||
|
||||
"github.com/containers/podman/v2/libpod"
|
||||
"github.com/containers/podman/v2/libpod/shutdown"
|
||||
"github.com/containers/podman/v2/pkg/signal"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// ProxySignals ...
|
||||
func ProxySignals(ctr *libpod.Container) {
|
||||
// Stop catching the shutdown signals (SIGINT, SIGTERM) - they're going
|
||||
// to the container now.
|
||||
shutdown.Stop()
|
||||
|
||||
sigBuffer := make(chan os.Signal, 128)
|
||||
signal.CatchAll(sigBuffer)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue