github.com/daaku/docker@v1.5.0/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  	Pid        int
    19  	ExitCode   int
    20  	Error      string // contains last known error when starting the container
    21  	StartedAt  time.Time
    22  	FinishedAt time.Time
    23  	waitChan   chan struct{}
    24  }
    25  
    26  func NewState() *State {
    27  	return &State{
    28  		waitChan: make(chan struct{}),
    29  	}
    30  }
    31  
    32  // String returns a human-readable description of the state
    33  func (s *State) String() string {
    34  	if s.Running {
    35  		if s.Paused {
    36  			return fmt.Sprintf("Up %s (Paused)", units.HumanDuration(time.Now().UTC().Sub(s.StartedAt)))
    37  		}
    38  		if s.Restarting {
    39  			return fmt.Sprintf("Restarting (%d) %s ago", s.ExitCode, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt)))
    40  		}
    41  
    42  		return fmt.Sprintf("Up %s", units.HumanDuration(time.Now().UTC().Sub(s.StartedAt)))
    43  	}
    44  
    45  	if s.FinishedAt.IsZero() {
    46  		return ""
    47  	}
    48  
    49  	return fmt.Sprintf("Exited (%d) %s ago", s.ExitCode, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt)))
    50  }
    51  
    52  // StateString returns a single string to describe state
    53  func (s *State) StateString() string {
    54  	if s.Running {
    55  		if s.Paused {
    56  			return "paused"
    57  		}
    58  		if s.Restarting {
    59  			return "restarting"
    60  		}
    61  		return "running"
    62  	}
    63  	return "exited"
    64  }
    65  
    66  func wait(waitChan <-chan struct{}, timeout time.Duration) error {
    67  	if timeout < 0 {
    68  		<-waitChan
    69  		return nil
    70  	}
    71  	select {
    72  	case <-time.After(timeout):
    73  		return fmt.Errorf("Timed out: %v", timeout)
    74  	case <-waitChan:
    75  		return nil
    76  	}
    77  }
    78  
    79  // WaitRunning waits until state is running. If state already running it returns
    80  // immediately. If you want wait forever you must supply negative timeout.
    81  // Returns pid, that was passed to SetRunning
    82  func (s *State) WaitRunning(timeout time.Duration) (int, error) {
    83  	s.Lock()
    84  	if s.Running {
    85  		pid := s.Pid
    86  		s.Unlock()
    87  		return pid, nil
    88  	}
    89  	waitChan := s.waitChan
    90  	s.Unlock()
    91  	if err := wait(waitChan, timeout); err != nil {
    92  		return -1, err
    93  	}
    94  	return s.GetPid(), nil
    95  }
    96  
    97  // WaitStop waits until state is stopped. If state already stopped it returns
    98  // immediately. If you want wait forever you must supply negative timeout.
    99  // Returns exit code, that was passed to SetStopped
   100  func (s *State) WaitStop(timeout time.Duration) (int, error) {
   101  	s.Lock()
   102  	if !s.Running {
   103  		exitCode := s.ExitCode
   104  		s.Unlock()
   105  		return exitCode, nil
   106  	}
   107  	waitChan := s.waitChan
   108  	s.Unlock()
   109  	if err := wait(waitChan, timeout); err != nil {
   110  		return -1, err
   111  	}
   112  	return s.GetExitCode(), nil
   113  }
   114  
   115  func (s *State) IsRunning() bool {
   116  	s.Lock()
   117  	res := s.Running
   118  	s.Unlock()
   119  	return res
   120  }
   121  
   122  func (s *State) GetPid() int {
   123  	s.Lock()
   124  	res := s.Pid
   125  	s.Unlock()
   126  	return res
   127  }
   128  
   129  func (s *State) GetExitCode() int {
   130  	s.Lock()
   131  	res := s.ExitCode
   132  	s.Unlock()
   133  	return res
   134  }
   135  
   136  func (s *State) SetRunning(pid int) {
   137  	s.Lock()
   138  	s.setRunning(pid)
   139  	s.Unlock()
   140  }
   141  
   142  func (s *State) setRunning(pid int) {
   143  	s.Error = ""
   144  	s.Running = true
   145  	s.Paused = false
   146  	s.Restarting = false
   147  	s.ExitCode = 0
   148  	s.Pid = pid
   149  	s.StartedAt = time.Now().UTC()
   150  	close(s.waitChan) // fire waiters for start
   151  	s.waitChan = make(chan struct{})
   152  }
   153  
   154  func (s *State) SetStopped(exitStatus *execdriver.ExitStatus) {
   155  	s.Lock()
   156  	s.setStopped(exitStatus)
   157  	s.Unlock()
   158  }
   159  
   160  func (s *State) setStopped(exitStatus *execdriver.ExitStatus) {
   161  	s.Running = false
   162  	s.Restarting = false
   163  	s.Pid = 0
   164  	s.FinishedAt = time.Now().UTC()
   165  	s.ExitCode = exitStatus.ExitCode
   166  	s.OOMKilled = exitStatus.OOMKilled
   167  	close(s.waitChan) // fire waiters for stop
   168  	s.waitChan = make(chan struct{})
   169  }
   170  
   171  // SetRestarting is when docker hanldes the auto restart of containers when they are
   172  // in the middle of a stop and being restarted again
   173  func (s *State) SetRestarting(exitStatus *execdriver.ExitStatus) {
   174  	s.Lock()
   175  	// we should consider the container running when it is restarting because of
   176  	// all the checks in docker around rm/stop/etc
   177  	s.Running = true
   178  	s.Restarting = true
   179  	s.Pid = 0
   180  	s.FinishedAt = time.Now().UTC()
   181  	s.ExitCode = exitStatus.ExitCode
   182  	s.OOMKilled = exitStatus.OOMKilled
   183  	close(s.waitChan) // fire waiters for stop
   184  	s.waitChan = make(chan struct{})
   185  	s.Unlock()
   186  }
   187  
   188  // setError sets the container's error state. This is useful when we want to
   189  // know the error that occurred when container transits to another state
   190  // when inspecting it
   191  func (s *State) setError(err error) {
   192  	s.Error = err.Error()
   193  }
   194  
   195  func (s *State) IsRestarting() bool {
   196  	s.Lock()
   197  	res := s.Restarting
   198  	s.Unlock()
   199  	return res
   200  }
   201  
   202  func (s *State) SetPaused() {
   203  	s.Lock()
   204  	s.Paused = true
   205  	s.Unlock()
   206  }
   207  
   208  func (s *State) SetUnpaused() {
   209  	s.Lock()
   210  	s.Paused = false
   211  	s.Unlock()
   212  }
   213  
   214  func (s *State) IsPaused() bool {
   215  	s.Lock()
   216  	res := s.Paused
   217  	s.Unlock()
   218  	return res
   219  }