fix compile error
[platform/upstream/docker-engine.git] / container / state.go
1 package container
2
3 import (
4         "errors"
5         "fmt"
6         "sync"
7         "time"
8
9         "golang.org/x/net/context"
10
11         "github.com/docker/docker/api/types"
12         "github.com/docker/go-units"
13 )
14
15 // State holds the current container state, and has methods to get and
16 // set the state. Container has an embed, which allows all of the
17 // functions defined against State to run against Container.
18 type State struct {
19         sync.Mutex
20         // Note that `Running` and `Paused` are not mutually exclusive:
21         // When pausing a container (on Linux), the cgroups freezer is used to suspend
22         // all processes in the container. Freezing the process requires the process to
23         // be running. As a result, paused containers are both `Running` _and_ `Paused`.
24         Running           bool
25         Paused            bool
26         Restarting        bool
27         OOMKilled         bool
28         RemovalInProgress bool // Not need for this to be persistent on disk.
29         Dead              bool
30         Pid               int
31         ExitCodeValue     int    `json:"ExitCode"`
32         ErrorMsg          string `json:"Error"` // contains last known error when starting the container
33         StartedAt         time.Time
34         FinishedAt        time.Time
35         Health            *Health
36
37         waitStop   chan struct{}
38         waitRemove chan struct{}
39 }
40
41 // StateStatus is used to return container wait results.
42 // Implements exec.ExitCode interface.
43 // This type is needed as State include a sync.Mutex field which make
44 // copying it unsafe.
45 type StateStatus struct {
46         exitCode int
47         err      error
48 }
49
50 // ExitCode returns current exitcode for the state.
51 func (s StateStatus) ExitCode() int {
52         return s.exitCode
53 }
54
55 // Err returns current error for the state. Returns nil if the container had
56 // exited on its own.
57 func (s StateStatus) Err() error {
58         return s.err
59 }
60
61 // NewState creates a default state object with a fresh channel for state changes.
62 func NewState() *State {
63         return &State{
64                 waitStop:   make(chan struct{}),
65                 waitRemove: make(chan struct{}),
66         }
67 }
68
69 // String returns a human-readable description of the state
70 func (s *State) String() string {
71         if s.Running {
72                 if s.Paused {
73                         return fmt.Sprintf("Up %s (Paused)", units.HumanDuration(time.Now().UTC().Sub(s.StartedAt)))
74                 }
75                 if s.Restarting {
76                         return fmt.Sprintf("Restarting (%d) %s ago", s.ExitCodeValue, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt)))
77                 }
78
79                 if h := s.Health; h != nil {
80                         return fmt.Sprintf("Up %s (%s)", units.HumanDuration(time.Now().UTC().Sub(s.StartedAt)), h.String())
81                 }
82
83                 return fmt.Sprintf("Up %s", units.HumanDuration(time.Now().UTC().Sub(s.StartedAt)))
84         }
85
86         if s.RemovalInProgress {
87                 return "Removal In Progress"
88         }
89
90         if s.Dead {
91                 return "Dead"
92         }
93
94         if s.StartedAt.IsZero() {
95                 return "Created"
96         }
97
98         if s.FinishedAt.IsZero() {
99                 return ""
100         }
101
102         return fmt.Sprintf("Exited (%d) %s ago", s.ExitCodeValue, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt)))
103 }
104
105 // HealthString returns a single string to describe health status.
106 func (s *State) HealthString() string {
107         if s.Health == nil {
108                 return types.NoHealthcheck
109         }
110
111         return s.Health.String()
112 }
113
114 // IsValidHealthString checks if the provided string is a valid container health status or not.
115 func IsValidHealthString(s string) bool {
116         return s == types.Starting ||
117                 s == types.Healthy ||
118                 s == types.Unhealthy ||
119                 s == types.NoHealthcheck
120 }
121
122 // StateString returns a single string to describe state
123 func (s *State) StateString() string {
124         if s.Running {
125                 if s.Paused {
126                         return "paused"
127                 }
128                 if s.Restarting {
129                         return "restarting"
130                 }
131                 return "running"
132         }
133
134         if s.RemovalInProgress {
135                 return "removing"
136         }
137
138         if s.Dead {
139                 return "dead"
140         }
141
142         if s.StartedAt.IsZero() {
143                 return "created"
144         }
145
146         return "exited"
147 }
148
149 // IsValidStateString checks if the provided string is a valid container state or not.
150 func IsValidStateString(s string) bool {
151         if s != "paused" &&
152                 s != "restarting" &&
153                 s != "removing" &&
154                 s != "running" &&
155                 s != "dead" &&
156                 s != "created" &&
157                 s != "exited" {
158                 return false
159         }
160         return true
161 }
162
163 // WaitCondition is an enum type for different states to wait for.
164 type WaitCondition int
165
166 // Possible WaitCondition Values.
167 //
168 // WaitConditionNotRunning (default) is used to wait for any of the non-running
169 // states: "created", "exited", "dead", "removing", or "removed".
170 //
171 // WaitConditionNextExit is used to wait for the next time the state changes
172 // to a non-running state. If the state is currently "created" or "exited",
173 // this would cause Wait() to block until either the container runs and exits
174 // or is removed.
175 //
176 // WaitConditionRemoved is used to wait for the container to be removed.
177 const (
178         WaitConditionNotRunning WaitCondition = iota
179         WaitConditionNextExit
180         WaitConditionRemoved
181 )
182
183 // Wait waits until the container is in a certain state indicated by the given
184 // condition. A context must be used for cancelling the request, controlling
185 // timeouts, and avoiding goroutine leaks. Wait must be called without holding
186 // the state lock. Returns a channel from which the caller will receive the
187 // result. If the container exited on its own, the result's Err() method will
188 // be nil and its ExitCode() method will return the conatiners exit code,
189 // otherwise, the results Err() method will return an error indicating why the
190 // wait operation failed.
191 func (s *State) Wait(ctx context.Context, condition WaitCondition) <-chan StateStatus {
192         s.Lock()
193         defer s.Unlock()
194
195         if condition == WaitConditionNotRunning && !s.Running {
196                 // Buffer so we can put it in the channel now.
197                 resultC := make(chan StateStatus, 1)
198
199                 // Send the current status.
200                 resultC <- StateStatus{
201                         exitCode: s.ExitCode(),
202                         err:      s.Err(),
203                 }
204
205                 return resultC
206         }
207
208         // If we are waiting only for removal, the waitStop channel should
209         // remain nil and block forever.
210         var waitStop chan struct{}
211         if condition < WaitConditionRemoved {
212                 waitStop = s.waitStop
213         }
214
215         // Always wait for removal, just in case the container gets removed
216         // while it is still in a "created" state, in which case it is never
217         // actually stopped.
218         waitRemove := s.waitRemove
219
220         resultC := make(chan StateStatus)
221
222         go func() {
223                 select {
224                 case <-ctx.Done():
225                         // Context timeout or cancellation.
226                         resultC <- StateStatus{
227                                 exitCode: -1,
228                                 err:      ctx.Err(),
229                         }
230                         return
231                 case <-waitStop:
232                 case <-waitRemove:
233                 }
234
235                 s.Lock()
236                 result := StateStatus{
237                         exitCode: s.ExitCode(),
238                         err:      s.Err(),
239                 }
240                 s.Unlock()
241
242                 resultC <- result
243         }()
244
245         return resultC
246 }
247
248 // IsRunning returns whether the running flag is set. Used by Container to check whether a container is running.
249 func (s *State) IsRunning() bool {
250         s.Lock()
251         res := s.Running
252         s.Unlock()
253         return res
254 }
255
256 // GetPID holds the process id of a container.
257 func (s *State) GetPID() int {
258         s.Lock()
259         res := s.Pid
260         s.Unlock()
261         return res
262 }
263
264 // ExitCode returns current exitcode for the state. Take lock before if state
265 // may be shared.
266 func (s *State) ExitCode() int {
267         return s.ExitCodeValue
268 }
269
270 // SetExitCode sets current exitcode for the state. Take lock before if state
271 // may be shared.
272 func (s *State) SetExitCode(ec int) {
273         s.ExitCodeValue = ec
274 }
275
276 // SetRunning sets the state of the container to "running".
277 func (s *State) SetRunning(pid int, initial bool) {
278         s.ErrorMsg = ""
279         s.Running = true
280         s.Restarting = false
281         s.ExitCodeValue = 0
282         s.Pid = pid
283         if initial {
284                 s.StartedAt = time.Now().UTC()
285         }
286 }
287
288 // SetStopped sets the container state to "stopped" without locking.
289 func (s *State) SetStopped(exitStatus *ExitStatus) {
290         s.Running = false
291         s.Paused = false
292         s.Restarting = false
293         s.Pid = 0
294         s.FinishedAt = time.Now().UTC()
295         s.setFromExitStatus(exitStatus)
296         close(s.waitStop) // Fire waiters for stop
297         s.waitStop = make(chan struct{})
298 }
299
300 // SetRestarting sets the container state to "restarting" without locking.
301 // It also sets the container PID to 0.
302 func (s *State) SetRestarting(exitStatus *ExitStatus) {
303         // we should consider the container running when it is restarting because of
304         // all the checks in docker around rm/stop/etc
305         s.Running = true
306         s.Restarting = true
307         s.Pid = 0
308         s.FinishedAt = time.Now().UTC()
309         s.setFromExitStatus(exitStatus)
310         close(s.waitStop) // Fire waiters for stop
311         s.waitStop = make(chan struct{})
312 }
313
314 // SetError sets the container's error state. This is useful when we want to
315 // know the error that occurred when container transits to another state
316 // when inspecting it
317 func (s *State) SetError(err error) {
318         s.ErrorMsg = err.Error()
319 }
320
321 // IsPaused returns whether the container is paused or not.
322 func (s *State) IsPaused() bool {
323         s.Lock()
324         res := s.Paused
325         s.Unlock()
326         return res
327 }
328
329 // IsRestarting returns whether the container is restarting or not.
330 func (s *State) IsRestarting() bool {
331         s.Lock()
332         res := s.Restarting
333         s.Unlock()
334         return res
335 }
336
337 // SetRemovalInProgress sets the container state as being removed.
338 // It returns true if the container was already in that state.
339 func (s *State) SetRemovalInProgress() bool {
340         s.Lock()
341         defer s.Unlock()
342         if s.RemovalInProgress {
343                 return true
344         }
345         s.RemovalInProgress = true
346         return false
347 }
348
349 // ResetRemovalInProgress makes the RemovalInProgress state to false.
350 func (s *State) ResetRemovalInProgress() {
351         s.Lock()
352         s.RemovalInProgress = false
353         s.Unlock()
354 }
355
356 // SetDead sets the container state to "dead"
357 func (s *State) SetDead() {
358         s.Lock()
359         s.Dead = true
360         s.Unlock()
361 }
362
363 // SetRemoved assumes this container is already in the "dead" state and
364 // closes the internal waitRemove channel to unblock callers waiting for a
365 // container to be removed.
366 func (s *State) SetRemoved() {
367         s.Lock()
368         close(s.waitRemove) // Unblock those waiting on remove.
369         s.Unlock()
370 }
371
372 // Err returns an error if there is one.
373 func (s *State) Err() error {
374         if s.ErrorMsg != "" {
375                 return errors.New(s.ErrorMsg)
376         }
377         return nil
378 }