github.com/jiasir/docker@v1.3.3-0.20170609024000-252e610103e7/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/container"
    13  	"github.com/docker/docker/libcontainerd"
    14  	"github.com/docker/docker/restartmanager"
    15  )
    16  
    17  func (daemon *Daemon) setStateCounter(c *container.Container) {
    18  	switch c.StateString() {
    19  	case "paused":
    20  		stateCtr.set(c.ID, "paused")
    21  	case "running":
    22  		stateCtr.set(c.ID, "running")
    23  	default:
    24  		stateCtr.set(c.ID, "stopped")
    25  	}
    26  }
    27  
    28  // StateChanged updates daemon state changes from containerd
    29  func (daemon *Daemon) StateChanged(id string, e libcontainerd.StateInfo) error {
    30  	c := daemon.containers.Get(id)
    31  	if c == nil {
    32  		return fmt.Errorf("no such container: %s", id)
    33  	}
    34  
    35  	switch e.State {
    36  	case libcontainerd.StateOOM:
    37  		// StateOOM is Linux specific and should never be hit on Windows
    38  		if runtime.GOOS == "windows" {
    39  			return errors.New("Received StateOOM from libcontainerd on Windows. This should never happen.")
    40  		}
    41  		daemon.updateHealthMonitor(c)
    42  		daemon.LogContainerEvent(c, "oom")
    43  	case libcontainerd.StateExit:
    44  
    45  		c.Lock()
    46  		c.StreamConfig.Wait()
    47  		c.Reset(false)
    48  
    49  		// If daemon is being shutdown, don't let the container restart
    50  		restart, wait, err := c.RestartManager().ShouldRestart(e.ExitCode, daemon.IsShuttingDown() || c.HasBeenManuallyStopped, time.Since(c.StartedAt))
    51  		if err == nil && restart {
    52  			c.RestartCount++
    53  			c.SetRestarting(platformConstructExitStatus(e))
    54  		} else {
    55  			c.SetStopped(platformConstructExitStatus(e))
    56  			defer daemon.autoRemove(c)
    57  		}
    58  
    59  		// cancel healthcheck here, they will be automatically
    60  		// restarted if/when the container is started again
    61  		daemon.stopHealthchecks(c)
    62  		attributes := map[string]string{
    63  			"exitCode": strconv.Itoa(int(e.ExitCode)),
    64  		}
    65  		daemon.LogContainerEventWithAttributes(c, "die", attributes)
    66  		daemon.Cleanup(c)
    67  
    68  		if err == nil && restart {
    69  			go func() {
    70  				err := <-wait
    71  				if err == nil {
    72  					if err = daemon.containerStart(c, "", "", false); err != nil {
    73  						logrus.Debugf("failed to restart container: %+v", err)
    74  					}
    75  				}
    76  				if err != nil {
    77  					c.SetStopped(platformConstructExitStatus(e))
    78  					defer daemon.autoRemove(c)
    79  					if err != restartmanager.ErrRestartCanceled {
    80  						logrus.Errorf("restartmanger wait error: %+v", err)
    81  					}
    82  				}
    83  			}()
    84  		}
    85  
    86  		daemon.setStateCounter(c)
    87  
    88  		defer c.Unlock()
    89  		if err := c.ToDisk(); err != nil {
    90  			return err
    91  		}
    92  		return daemon.postRunProcessing(c, e)
    93  	case libcontainerd.StateExitProcess:
    94  		if execConfig := c.ExecCommands.Get(e.ProcessID); execConfig != nil {
    95  			ec := int(e.ExitCode)
    96  			execConfig.Lock()
    97  			defer execConfig.Unlock()
    98  			execConfig.ExitCode = &ec
    99  			execConfig.Running = false
   100  			execConfig.StreamConfig.Wait()
   101  			if err := execConfig.CloseStreams(); err != nil {
   102  				logrus.Errorf("failed to cleanup exec %s streams: %s", c.ID, err)
   103  			}
   104  
   105  			// remove the exec command from the container's store only and not the
   106  			// daemon's store so that the exec command can be inspected.
   107  			c.ExecCommands.Delete(execConfig.ID)
   108  		} else {
   109  			logrus.Warnf("Ignoring StateExitProcess for %v but no exec command found", e)
   110  		}
   111  	case libcontainerd.StateStart, libcontainerd.StateRestore:
   112  		// Container is already locked in this case
   113  		c.SetRunning(int(e.Pid), e.State == libcontainerd.StateStart)
   114  		c.HasBeenManuallyStopped = false
   115  		c.HasBeenStartedBefore = true
   116  		daemon.setStateCounter(c)
   117  
   118  		if err := c.ToDisk(); err != nil {
   119  			c.Reset(false)
   120  			return err
   121  		}
   122  		daemon.initHealthMonitor(c)
   123  
   124  		daemon.LogContainerEvent(c, "start")
   125  	case libcontainerd.StatePause:
   126  		// Container is already locked in this case
   127  		c.Paused = true
   128  		daemon.setStateCounter(c)
   129  		if err := c.ToDisk(); err != nil {
   130  			return err
   131  		}
   132  		daemon.updateHealthMonitor(c)
   133  		daemon.LogContainerEvent(c, "pause")
   134  	case libcontainerd.StateResume:
   135  		// Container is already locked in this case
   136  		c.Paused = false
   137  		daemon.setStateCounter(c)
   138  		if err := c.ToDisk(); err != nil {
   139  			return err
   140  		}
   141  		daemon.updateHealthMonitor(c)
   142  		daemon.LogContainerEvent(c, "unpause")
   143  	}
   144  	return nil
   145  }
   146  
   147  func (daemon *Daemon) autoRemove(c *container.Container) {
   148  	c.Lock()
   149  	ar := c.HostConfig.AutoRemove
   150  	c.Unlock()
   151  	if !ar {
   152  		return
   153  	}
   154  
   155  	var err error
   156  	if err = daemon.ContainerRm(c.ID, &types.ContainerRmConfig{ForceRemove: true, RemoveVolume: true}); err == nil {
   157  		return
   158  	}
   159  	if c := daemon.containers.Get(c.ID); c == nil {
   160  		return
   161  	}
   162  
   163  	if err != nil {
   164  		logrus.WithError(err).WithField("container", c.ID).Error("error removing container")
   165  	}
   166  }