2018-02-05 16:05:59 -05:00
package daemon // import "github.com/docker/docker/daemon"
2014-07-31 16:24:54 -04:00
2015-10-12 19:34:03 -04:00
import (
2017-03-30 16:52:40 -04:00
"context"
2015-10-12 19:34:03 -04:00
"fmt"
"runtime"
"syscall"
2015-11-02 18:25:26 -05:00
"time"
2015-10-12 19:34:03 -04:00
2017-03-30 23:01:41 -04:00
containerpkg "github.com/docker/docker/container"
2018-01-11 14:53:06 -05:00
"github.com/docker/docker/errdefs"
2017-09-22 09:52:41 -04:00
"github.com/docker/docker/libcontainerd"
2015-10-12 19:34:03 -04:00
"github.com/docker/docker/pkg/signal"
2017-07-19 10:20:13 -04:00
"github.com/pkg/errors"
2017-07-26 17:42:13 -04:00
"github.com/sirupsen/logrus"
2015-10-12 19:34:03 -04:00
)
2014-07-31 16:24:54 -04:00
2016-03-04 15:41:06 -05:00
type errNoSuchProcess struct {
pid int
signal int
}
func ( e errNoSuchProcess ) Error ( ) string {
return fmt . Sprintf ( "Cannot kill process (pid=%d) with signal %d: no such process." , e . pid , e . signal )
}
2017-07-19 10:20:13 -04:00
func ( errNoSuchProcess ) NotFound ( ) { }
2016-03-04 15:41:06 -05:00
// isErrNoSuchProcess returns true if the error
// is an instance of errNoSuchProcess.
func isErrNoSuchProcess ( err error ) bool {
_ , ok := err . ( errNoSuchProcess )
return ok
}
2016-03-17 13:15:32 -04:00
// ContainerKill sends signal to the container
2014-07-31 16:24:54 -04:00
// If no signal is given (sig 0), then Kill with SIGKILL and wait
// for the container to exit.
// If a signal is given, then just send it to the container and return.
2015-09-29 13:51:40 -04:00
func ( daemon * Daemon ) ContainerKill ( name string , sig uint64 ) error {
2015-12-11 12:39:28 -05:00
container , err := daemon . GetContainer ( name )
2014-12-16 18:06:35 -05:00
if err != nil {
2015-03-25 03:44:12 -04:00
return err
2014-12-16 18:06:35 -05:00
}
2015-10-12 19:34:03 -04:00
if sig != 0 && ! signal . ValidSignalForPlatform ( syscall . Signal ( sig ) ) {
return fmt . Errorf ( "The %s daemon does not support signal %d" , runtime . GOOS , sig )
}
2014-12-16 18:06:35 -05:00
// If no signal is passed, or SIGKILL, perform regular Kill (SIGKILL + wait())
if sig == 0 || syscall . Signal ( sig ) == syscall . SIGKILL {
2015-11-11 20:19:39 -05:00
return daemon . Kill ( container )
2014-07-31 16:24:54 -04:00
}
2015-11-11 20:19:39 -05:00
return daemon . killWithSignal ( container , int ( sig ) )
2014-07-31 16:24:54 -04:00
}
2015-11-02 18:25:26 -05:00
// killWithSignal sends the container the given signal. This wrapper for the
// host specific kill command prepares the container before attempting
// to send the signal. An error is returned if the container is paused
// or not running, or if there is a problem returned from the
// underlying kill command.
2017-03-30 23:01:41 -04:00
func ( daemon * Daemon ) killWithSignal ( container * containerpkg . Container , sig int ) error {
2016-07-31 13:00:38 -04:00
logrus . Debugf ( "Sending kill signal %d to container %s" , sig , container . ID )
2015-11-02 18:25:26 -05:00
container . Lock ( )
defer container . Unlock ( )
2017-11-14 20:59:40 -05:00
daemon . stopHealthchecks ( container )
2015-11-02 18:25:26 -05:00
if ! container . Running {
2017-07-19 10:20:13 -04:00
return errNotRunning ( container . ID )
2015-11-02 18:25:26 -05:00
}
2017-07-09 09:34:14 -04:00
var unpause bool
2017-05-22 09:57:39 -04:00
if container . Config . StopSignal != "" && syscall . Signal ( sig ) != syscall . SIGKILL {
2016-10-24 14:10:14 -04:00
containerStopSignal , err := signal . ParseSignal ( container . Config . StopSignal )
if err != nil {
return err
}
if containerStopSignal == syscall . Signal ( sig ) {
container . ExitOnNext ( )
2017-07-09 09:34:14 -04:00
unpause = container . Paused
2016-10-24 14:10:14 -04:00
}
} else {
container . ExitOnNext ( )
2017-07-09 09:34:14 -04:00
unpause = container . Paused
2016-10-24 14:10:14 -04:00
}
2015-11-02 18:25:26 -05:00
2016-03-18 14:50:19 -04:00
if ! daemon . IsShuttingDown ( ) {
container . HasBeenManuallyStopped = true
}
2015-11-02 18:25:26 -05:00
// if the container is currently restarting we do not need to send the signal
2016-07-21 06:03:37 -04:00
// to the process. Telling the monitor that it should exit on its next event
2015-11-02 18:25:26 -05:00
// loop is enough
if container . Restarting {
return nil
}
if err := daemon . kill ( container , sig ) ; err != nil {
2017-12-15 10:00:15 -05:00
if errdefs . IsNotFound ( err ) {
2017-07-09 09:34:14 -04:00
unpause = false
2017-12-15 10:00:15 -05:00
logrus . WithError ( err ) . WithField ( "container" , container . ID ) . WithField ( "action" , "kill" ) . Debug ( "container kill failed because of 'container not found' or 'no such process'" )
2016-04-07 10:05:29 -04:00
} else {
2017-12-15 10:00:15 -05:00
return errors . Wrapf ( err , "Cannot kill container %s" , container . ID )
2016-04-07 10:05:29 -04:00
}
2015-11-02 18:25:26 -05:00
}
2017-07-09 09:34:14 -04:00
if unpause {
// above kill signal will be sent once resume is finished
2017-09-22 09:52:41 -04:00
if err := daemon . containerd . Resume ( context . Background ( ) , container . ID ) ; err != nil {
2017-07-09 09:34:14 -04:00
logrus . Warn ( "Cannot unpause container %s: %s" , container . ID , err )
}
}
2016-01-07 17:14:05 -05:00
attributes := map [ string ] string {
"signal" : fmt . Sprintf ( "%d" , sig ) ,
}
daemon . LogContainerEventWithAttributes ( container , "kill" , attributes )
2015-11-02 18:25:26 -05:00
return nil
}
// Kill forcefully terminates a container.
2017-03-30 23:01:41 -04:00
func ( daemon * Daemon ) Kill ( container * containerpkg . Container ) error {
2015-11-02 18:25:26 -05:00
if ! container . IsRunning ( ) {
2017-07-19 10:20:13 -04:00
return errNotRunning ( container . ID )
2015-11-02 18:25:26 -05:00
}
// 1. Send SIGKILL
if err := daemon . killPossiblyDeadProcess ( container , int ( syscall . SIGKILL ) ) ; err != nil {
// While normally we might "return err" here we're not going to
// because if we can't stop the container by this point then
2016-12-23 07:48:25 -05:00
// it's probably because it's already stopped. Meaning, between
2015-11-02 18:25:26 -05:00
// the time of the IsRunning() call above and now it stopped.
2016-03-18 15:43:17 -04:00
// Also, since the err return will be environment specific we can't
2015-11-02 18:25:26 -05:00
// look for any particular (common) error that would indicate
// that the process is already dead vs something else going wrong.
// So, instead we'll give it up to 2 more seconds to complete and if
// by that time the container is still running, then the error
// we got is probably valid and so we return it to the caller.
2016-03-04 15:41:06 -05:00
if isErrNoSuchProcess ( err ) {
return nil
}
2015-11-02 18:25:26 -05:00
2017-03-30 16:52:40 -04:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , 2 * time . Second )
defer cancel ( )
2017-03-30 23:01:41 -04:00
if status := <- container . Wait ( ctx , containerpkg . WaitConditionNotRunning ) ; status . Err ( ) != nil {
2016-08-15 19:51:45 -04:00
return err
2015-11-02 18:25:26 -05:00
}
}
// 2. Wait for the process to die, in last resort, try to kill the process directly
if err := killProcessDirectly ( container ) ; err != nil {
2016-03-04 15:41:06 -05:00
if isErrNoSuchProcess ( err ) {
return nil
}
2015-11-02 18:25:26 -05:00
return err
}
2017-03-30 16:52:40 -04:00
// Wait for exit with no timeout.
// Ignore returned status.
2017-09-06 04:54:24 -04:00
<- container . Wait ( context . Background ( ) , containerpkg . WaitConditionNotRunning )
2017-03-30 16:52:40 -04:00
2015-11-02 18:25:26 -05:00
return nil
}
2015-12-13 11:00:39 -05:00
// killPossibleDeadProcess is a wrapper around killSig() suppressing "no such process" error.
2017-03-30 23:01:41 -04:00
func ( daemon * Daemon ) killPossiblyDeadProcess ( container * containerpkg . Container , sig int ) error {
2015-11-02 18:25:26 -05:00
err := daemon . killWithSignal ( container , sig )
2017-12-15 10:00:15 -05:00
if errdefs . IsNotFound ( err ) {
2016-03-04 15:41:06 -05:00
e := errNoSuchProcess { container . GetPID ( ) , sig }
logrus . Debug ( e )
return e
2015-11-02 18:25:26 -05:00
}
return err
}
2016-05-24 11:49:26 -04:00
2017-03-30 23:01:41 -04:00
func ( daemon * Daemon ) kill ( c * containerpkg . Container , sig int ) error {
2017-09-22 09:52:41 -04:00
return daemon . containerd . SignalProcess ( context . Background ( ) , c . ID , libcontainerd . InitProcessName , sig )
2016-05-24 11:49:26 -04:00
}