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 }