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 }