Skip to content

Commit

Permalink
Merge pull request #7999 from mheon/signal_handler
Browse files Browse the repository at this point in the history
Add a shutdown signal handler
  • Loading branch information
openshift-merge-robot authored Oct 20, 2020
2 parents 35b4cb1 + f58d2f5 commit 6c0b600
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 11 deletions.
13 changes: 13 additions & 0 deletions libpod/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
}

Expand Down
5 changes: 5 additions & 0 deletions libpod/runtime_ctr.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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 {
Expand Down
131 changes: 131 additions & 0 deletions libpod/shutdown/handler.go
Original file line number Diff line number Diff line change
@@ -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
}
24 changes: 13 additions & 11 deletions pkg/api/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import (
"net"
"net/http"
"os"
"os/signal"
goRuntime "runtime"
"strings"
"sync"
"syscall"
"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"
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions pkg/domain/infra/abi/terminal/sigproxy_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down

0 comments on commit 6c0b600

Please sign in to comment.