github.com/iamlotus/docker@v1.8.1/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  }