github.com/slene/docker@v1.8.0-rc1/daemon/state.go (about) 1 package daemon 2 3 import ( 4 "fmt" 5 "sync" 6 "time" 7 8 "github.com/docker/docker/daemon/execdriver" 9 "github.com/docker/docker/pkg/units" 10 ) 11 12 type State struct { 13 sync.Mutex 14 Running bool 15 Paused bool 16 Restarting bool 17 OOMKilled bool 18 removalInProgress bool // Not need for this to be persistent on disk. 19 Dead bool 20 Pid int 21 ExitCode int 22 Error string // contains last known error when starting the container 23 StartedAt time.Time 24 FinishedAt time.Time 25 waitChan chan struct{} 26 } 27 28 func NewState() *State { 29 return &State{ 30 waitChan: make(chan struct{}), 31 } 32 } 33 34 // String returns a human-readable description of the state 35 func (s *State) String() string { 36 if s.Running { 37 if s.Paused { 38 return fmt.Sprintf("Up %s (Paused)", units.HumanDuration(time.Now().UTC().Sub(s.StartedAt))) 39 } 40 if s.Restarting { 41 return fmt.Sprintf("Restarting (%d) %s ago", s.ExitCode, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt))) 42 } 43 44 return fmt.Sprintf("Up %s", units.HumanDuration(time.Now().UTC().Sub(s.StartedAt))) 45 } 46 47 if s.removalInProgress { 48 return "Removal In Progress" 49 } 50 51 if s.Dead { 52 return "Dead" 53 } 54 55 if s.StartedAt.IsZero() { 56 return "Created" 57 } 58 59 if s.FinishedAt.IsZero() { 60 return "" 61 } 62 63 return fmt.Sprintf("Exited (%d) %s ago", s.ExitCode, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt))) 64 } 65 66 // StateString returns a single string to describe state 67 func (s *State) StateString() string { 68 if s.Running { 69 if s.Paused { 70 return "paused" 71 } 72 if s.Restarting { 73 return "restarting" 74 } 75 return "running" 76 } 77 78 if s.Dead { 79 return "dead" 80 } 81 82 if s.StartedAt.IsZero() { 83 return "created" 84 } 85 86 return "exited" 87 } 88 89 func isValidStateString(s string) bool { 90 if s != "paused" && 91 s != "restarting" && 92 s != "running" && 93 s != "dead" && 94 s != "created" && 95 s != "exited" { 96 return false 97 } 98 return true 99 } 100 101 func wait(waitChan <-chan struct{}, timeout time.Duration) error { 102 if timeout < 0 { 103 <-waitChan 104 return nil 105 } 106 select { 107 case <-time.After(timeout): 108 return fmt.Errorf("Timed out: %v", timeout) 109 case <-waitChan: 110 return nil 111 } 112 } 113 114 // WaitRunning waits until state is running. If state already running it returns 115 // immediately. If you want wait forever you must supply negative timeout. 116 // Returns pid, that was passed to SetRunning 117 func (s *State) WaitRunning(timeout time.Duration) (int, error) { 118 s.Lock() 119 if s.Running { 120 pid := s.Pid 121 s.Unlock() 122 return pid, nil 123 } 124 waitChan := s.waitChan 125 s.Unlock() 126 if err := wait(waitChan, timeout); err != nil { 127 return -1, err 128 } 129 return s.GetPid(), nil 130 } 131 132 // WaitStop waits until state is stopped. If state already stopped it returns 133 // immediately. If you want wait forever you must supply negative timeout. 134 // Returns exit code, that was passed to SetStopped 135 func (s *State) WaitStop(timeout time.Duration) (int, error) { 136 s.Lock() 137 if !s.Running { 138 exitCode := s.ExitCode 139 s.Unlock() 140 return exitCode, nil 141 } 142 waitChan := s.waitChan 143 s.Unlock() 144 if err := wait(waitChan, timeout); err != nil { 145 return -1, err 146 } 147 return s.GetExitCode(), nil 148 } 149 150 func (s *State) IsRunning() bool { 151 s.Lock() 152 res := s.Running 153 s.Unlock() 154 return res 155 } 156 157 func (s *State) GetPid() int { 158 s.Lock() 159 res := s.Pid 160 s.Unlock() 161 return res 162 } 163 164 func (s *State) GetExitCode() int { 165 s.Lock() 166 res := s.ExitCode 167 s.Unlock() 168 return res 169 } 170 171 func (s *State) SetRunning(pid int) { 172 s.Lock() 173 s.setRunning(pid) 174 s.Unlock() 175 } 176 177 func (s *State) setRunning(pid int) { 178 s.Error = "" 179 s.Running = true 180 s.Paused = false 181 s.Restarting = false 182 s.ExitCode = 0 183 s.Pid = pid 184 s.StartedAt = time.Now().UTC() 185 close(s.waitChan) // fire waiters for start 186 s.waitChan = make(chan struct{}) 187 } 188 189 func (s *State) SetStopped(exitStatus *execdriver.ExitStatus) { 190 s.Lock() 191 s.setStopped(exitStatus) 192 s.Unlock() 193 } 194 195 func (s *State) setStopped(exitStatus *execdriver.ExitStatus) { 196 s.Running = false 197 s.Restarting = false 198 s.Pid = 0 199 s.FinishedAt = time.Now().UTC() 200 s.ExitCode = exitStatus.ExitCode 201 s.OOMKilled = exitStatus.OOMKilled 202 close(s.waitChan) // fire waiters for stop 203 s.waitChan = make(chan struct{}) 204 } 205 206 // SetRestarting is when docker handles the auto restart of containers when they are 207 // in the middle of a stop and being restarted again 208 func (s *State) SetRestarting(exitStatus *execdriver.ExitStatus) { 209 s.Lock() 210 // we should consider the container running when it is restarting because of 211 // all the checks in docker around rm/stop/etc 212 s.Running = true 213 s.Restarting = true 214 s.Pid = 0 215 s.FinishedAt = time.Now().UTC() 216 s.ExitCode = exitStatus.ExitCode 217 s.OOMKilled = exitStatus.OOMKilled 218 close(s.waitChan) // fire waiters for stop 219 s.waitChan = make(chan struct{}) 220 s.Unlock() 221 } 222 223 // setError sets the container's error state. This is useful when we want to 224 // know the error that occurred when container transits to another state 225 // when inspecting it 226 func (s *State) setError(err error) { 227 s.Error = err.Error() 228 } 229 230 func (s *State) IsRestarting() bool { 231 s.Lock() 232 res := s.Restarting 233 s.Unlock() 234 return res 235 } 236 237 func (s *State) SetPaused() { 238 s.Lock() 239 s.Paused = true 240 s.Unlock() 241 } 242 243 func (s *State) SetUnpaused() { 244 s.Lock() 245 s.Paused = false 246 s.Unlock() 247 } 248 249 func (s *State) IsPaused() bool { 250 s.Lock() 251 res := s.Paused 252 s.Unlock() 253 return res 254 } 255 256 func (s *State) SetRemovalInProgress() error { 257 s.Lock() 258 defer s.Unlock() 259 if s.removalInProgress { 260 return fmt.Errorf("Status is already RemovalInProgress") 261 } 262 s.removalInProgress = true 263 return nil 264 } 265 266 func (s *State) ResetRemovalInProgress() { 267 s.Lock() 268 s.removalInProgress = false 269 s.Unlock() 270 } 271 272 func (s *State) SetDead() { 273 s.Lock() 274 s.Dead = true 275 s.Unlock() 276 }