github.com/aimxhaisse/docker@v1.6.2/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.FinishedAt.IsZero() {
    56  		return ""
    57  	}
    58  
    59  	return fmt.Sprintf("Exited (%d) %s ago", s.ExitCode, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt)))
    60  }
    61  
    62  // StateString returns a single string to describe state
    63  func (s *State) StateString() string {
    64  	if s.Running {
    65  		if s.Paused {
    66  			return "paused"
    67  		}
    68  		if s.Restarting {
    69  			return "restarting"
    70  		}
    71  		return "running"
    72  	}
    73  
    74  	if s.Dead {
    75  		return "dead"
    76  	}
    77  
    78  	return "exited"
    79  }
    80  
    81  func wait(waitChan <-chan struct{}, timeout time.Duration) error {
    82  	if timeout < 0 {
    83  		<-waitChan
    84  		return nil
    85  	}
    86  	select {
    87  	case <-time.After(timeout):
    88  		return fmt.Errorf("Timed out: %v", timeout)
    89  	case <-waitChan:
    90  		return nil
    91  	}
    92  }
    93  
    94  // WaitRunning waits until state is running. If state already running it returns
    95  // immediately. If you want wait forever you must supply negative timeout.
    96  // Returns pid, that was passed to SetRunning
    97  func (s *State) WaitRunning(timeout time.Duration) (int, error) {
    98  	s.Lock()
    99  	if s.Running {
   100  		pid := s.Pid
   101  		s.Unlock()
   102  		return pid, nil
   103  	}
   104  	waitChan := s.waitChan
   105  	s.Unlock()
   106  	if err := wait(waitChan, timeout); err != nil {
   107  		return -1, err
   108  	}
   109  	return s.GetPid(), nil
   110  }
   111  
   112  // WaitStop waits until state is stopped. If state already stopped it returns
   113  // immediately. If you want wait forever you must supply negative timeout.
   114  // Returns exit code, that was passed to SetStopped
   115  func (s *State) WaitStop(timeout time.Duration) (int, error) {
   116  	s.Lock()
   117  	if !s.Running {
   118  		exitCode := s.ExitCode
   119  		s.Unlock()
   120  		return exitCode, nil
   121  	}
   122  	waitChan := s.waitChan
   123  	s.Unlock()
   124  	if err := wait(waitChan, timeout); err != nil {
   125  		return -1, err
   126  	}
   127  	return s.GetExitCode(), nil
   128  }
   129  
   130  func (s *State) IsRunning() bool {
   131  	s.Lock()
   132  	res := s.Running
   133  	s.Unlock()
   134  	return res
   135  }
   136  
   137  func (s *State) GetPid() int {
   138  	s.Lock()
   139  	res := s.Pid
   140  	s.Unlock()
   141  	return res
   142  }
   143  
   144  func (s *State) GetExitCode() int {
   145  	s.Lock()
   146  	res := s.ExitCode
   147  	s.Unlock()
   148  	return res
   149  }
   150  
   151  func (s *State) SetRunning(pid int) {
   152  	s.Lock()
   153  	s.setRunning(pid)
   154  	s.Unlock()
   155  }
   156  
   157  func (s *State) setRunning(pid int) {
   158  	s.Error = ""
   159  	s.Running = true
   160  	s.Paused = false
   161  	s.Restarting = false
   162  	s.ExitCode = 0
   163  	s.Pid = pid
   164  	s.StartedAt = time.Now().UTC()
   165  	close(s.waitChan) // fire waiters for start
   166  	s.waitChan = make(chan struct{})
   167  }
   168  
   169  func (s *State) SetStopped(exitStatus *execdriver.ExitStatus) {
   170  	s.Lock()
   171  	s.setStopped(exitStatus)
   172  	s.Unlock()
   173  }
   174  
   175  func (s *State) setStopped(exitStatus *execdriver.ExitStatus) {
   176  	s.Running = false
   177  	s.Restarting = false
   178  	s.Pid = 0
   179  	s.FinishedAt = time.Now().UTC()
   180  	s.ExitCode = exitStatus.ExitCode
   181  	s.OOMKilled = exitStatus.OOMKilled
   182  	close(s.waitChan) // fire waiters for stop
   183  	s.waitChan = make(chan struct{})
   184  }
   185  
   186  // SetRestarting is when docker hanldes the auto restart of containers when they are
   187  // in the middle of a stop and being restarted again
   188  func (s *State) SetRestarting(exitStatus *execdriver.ExitStatus) {
   189  	s.Lock()
   190  	// we should consider the container running when it is restarting because of
   191  	// all the checks in docker around rm/stop/etc
   192  	s.Running = true
   193  	s.Restarting = true
   194  	s.Pid = 0
   195  	s.FinishedAt = time.Now().UTC()
   196  	s.ExitCode = exitStatus.ExitCode
   197  	s.OOMKilled = exitStatus.OOMKilled
   198  	close(s.waitChan) // fire waiters for stop
   199  	s.waitChan = make(chan struct{})
   200  	s.Unlock()
   201  }
   202  
   203  // setError sets the container's error state. This is useful when we want to
   204  // know the error that occurred when container transits to another state
   205  // when inspecting it
   206  func (s *State) setError(err error) {
   207  	s.Error = err.Error()
   208  }
   209  
   210  func (s *State) IsRestarting() bool {
   211  	s.Lock()
   212  	res := s.Restarting
   213  	s.Unlock()
   214  	return res
   215  }
   216  
   217  func (s *State) SetPaused() {
   218  	s.Lock()
   219  	s.Paused = true
   220  	s.Unlock()
   221  }
   222  
   223  func (s *State) SetUnpaused() {
   224  	s.Lock()
   225  	s.Paused = false
   226  	s.Unlock()
   227  }
   228  
   229  func (s *State) IsPaused() bool {
   230  	s.Lock()
   231  	res := s.Paused
   232  	s.Unlock()
   233  	return res
   234  }
   235  
   236  func (s *State) SetRemovalInProgress() error {
   237  	s.Lock()
   238  	defer s.Unlock()
   239  	if s.removalInProgress {
   240  		return fmt.Errorf("Status is already RemovalInProgress")
   241  	}
   242  	s.removalInProgress = true
   243  	return nil
   244  }
   245  
   246  func (s *State) ResetRemovalInProgress() {
   247  	s.Lock()
   248  	s.removalInProgress = false
   249  	s.Unlock()
   250  }
   251  
   252  func (s *State) SetDead() {
   253  	s.Lock()
   254  	s.Dead = true
   255  	s.Unlock()
   256  }