github.com/gravitational/moby@v1.13.1/daemon/monitor.go (about)

     1  package daemon
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"runtime"
     7  	"strconv"
     8  	"time"
     9  
    10  	"github.com/Sirupsen/logrus"
    11  	"github.com/docker/docker/api/types"
    12  	"github.com/docker/docker/libcontainerd"
    13  	"github.com/docker/docker/restartmanager"
    14  )
    15  
    16  // StateChanged updates daemon state changes from containerd
    17  func (daemon *Daemon) StateChanged(id string, e libcontainerd.StateInfo) error {
    18  	c := daemon.containers.Get(id)
    19  	if c == nil {
    20  		return fmt.Errorf("no such container: %s", id)
    21  	}
    22  
    23  	switch e.State {
    24  	case libcontainerd.StateOOM:
    25  		// StateOOM is Linux specific and should never be hit on Windows
    26  		if runtime.GOOS == "windows" {
    27  			return errors.New("Received StateOOM from libcontainerd on Windows. This should never happen.")
    28  		}
    29  		daemon.updateHealthMonitor(c)
    30  		daemon.LogContainerEvent(c, "oom")
    31  	case libcontainerd.StateExit:
    32  		// if container's AutoRemove flag is set, remove it after clean up
    33  		autoRemove := func() {
    34  			if c.HostConfig.AutoRemove {
    35  				if err := daemon.ContainerRm(c.ID, &types.ContainerRmConfig{ForceRemove: true, RemoveVolume: true}); err != nil {
    36  					logrus.Errorf("can't remove container %s: %v", c.ID, err)
    37  				}
    38  			}
    39  		}
    40  
    41  		c.Lock()
    42  		c.StreamConfig.Wait()
    43  		c.Reset(false)
    44  
    45  		restart, wait, err := c.RestartManager().ShouldRestart(e.ExitCode, false, time.Since(c.StartedAt))
    46  		if err == nil && restart {
    47  			c.RestartCount++
    48  			c.SetRestarting(platformConstructExitStatus(e))
    49  		} else {
    50  			c.SetStopped(platformConstructExitStatus(e))
    51  			defer autoRemove()
    52  		}
    53  
    54  		daemon.updateHealthMonitor(c)
    55  		attributes := map[string]string{
    56  			"exitCode": strconv.Itoa(int(e.ExitCode)),
    57  		}
    58  		daemon.LogContainerEventWithAttributes(c, "die", attributes)
    59  		daemon.Cleanup(c)
    60  
    61  		if err == nil && restart {
    62  			go func() {
    63  				err := <-wait
    64  				if err == nil {
    65  					if err = daemon.containerStart(c, "", "", false); err != nil {
    66  						logrus.Debugf("failed to restart container: %+v", err)
    67  					}
    68  				}
    69  				if err != nil {
    70  					c.SetStopped(platformConstructExitStatus(e))
    71  					defer autoRemove()
    72  					if err != restartmanager.ErrRestartCanceled {
    73  						logrus.Errorf("restartmanger wait error: %+v", err)
    74  					}
    75  				}
    76  			}()
    77  		}
    78  
    79  		defer c.Unlock()
    80  		if err := c.ToDisk(); err != nil {
    81  			return err
    82  		}
    83  		return daemon.postRunProcessing(c, e)
    84  	case libcontainerd.StateExitProcess:
    85  		if execConfig := c.ExecCommands.Get(e.ProcessID); execConfig != nil {
    86  			ec := int(e.ExitCode)
    87  			execConfig.Lock()
    88  			defer execConfig.Unlock()
    89  			execConfig.ExitCode = &ec
    90  			execConfig.Running = false
    91  			execConfig.StreamConfig.Wait()
    92  			if err := execConfig.CloseStreams(); err != nil {
    93  				logrus.Errorf("%s: %s", c.ID, err)
    94  			}
    95  
    96  			// remove the exec command from the container's store only and not the
    97  			// daemon's store so that the exec command can be inspected.
    98  			c.ExecCommands.Delete(execConfig.ID)
    99  		} else {
   100  			logrus.Warnf("Ignoring StateExitProcess for %v but no exec command found", e)
   101  		}
   102  	case libcontainerd.StateStart, libcontainerd.StateRestore:
   103  		// Container is already locked in this case
   104  		c.SetRunning(int(e.Pid), e.State == libcontainerd.StateStart)
   105  		c.HasBeenManuallyStopped = false
   106  		c.HasBeenStartedBefore = true
   107  		if err := c.ToDisk(); err != nil {
   108  			c.Reset(false)
   109  			return err
   110  		}
   111  		daemon.initHealthMonitor(c)
   112  		daemon.LogContainerEvent(c, "start")
   113  	case libcontainerd.StatePause:
   114  		// Container is already locked in this case
   115  		c.Paused = true
   116  		if err := c.ToDisk(); err != nil {
   117  			return err
   118  		}
   119  		daemon.updateHealthMonitor(c)
   120  		daemon.LogContainerEvent(c, "pause")
   121  	case libcontainerd.StateResume:
   122  		// Container is already locked in this case
   123  		c.Paused = false
   124  		if err := c.ToDisk(); err != nil {
   125  			return err
   126  		}
   127  		daemon.updateHealthMonitor(c)
   128  		daemon.LogContainerEvent(c, "unpause")
   129  	}
   130  
   131  	return nil
   132  }