| package container // import "github.com/docker/docker/container" | |
| import ( | |
| "context" | |
| "sync" | |
| "github.com/containerd/log" | |
| "github.com/docker/docker/api/types" | |
| ) | |
| // Health holds the current container health-check state | |
| type Health struct { | |
| types.Health | |
| stop chan struct{} // Write struct{} to stop the monitor | |
| mu sync.Mutex | |
| } | |
| // String returns a human-readable description of the health-check state | |
| func (s *Health) String() string { | |
| status := s.Status() | |
| switch status { | |
| case types.Starting: | |
| return "health: starting" | |
| default: // Healthy and Unhealthy are clear on their own | |
| return status | |
| } | |
| } | |
| // Status returns the current health status. | |
| // | |
| // Note that this takes a lock and the value may change after being read. | |
| func (s *Health) Status() string { | |
| s.mu.Lock() | |
| defer s.mu.Unlock() | |
| // This happens when the monitor has yet to be setup. | |
| if s.Health.Status == "" { | |
| return types.Unhealthy | |
| } | |
| return s.Health.Status | |
| } | |
| // SetStatus writes the current status to the underlying health structure, | |
| // obeying the locking semantics. | |
| // | |
| // Status may be set directly if another lock is used. | |
| func (s *Health) SetStatus(new string) { | |
| s.mu.Lock() | |
| defer s.mu.Unlock() | |
| s.Health.Status = new | |
| } | |
| // OpenMonitorChannel creates and returns a new monitor channel. If there | |
| // already is one, it returns nil. | |
| func (s *Health) OpenMonitorChannel() chan struct{} { | |
| s.mu.Lock() | |
| defer s.mu.Unlock() | |
| if s.stop == nil { | |
| log.G(context.TODO()).Debug("OpenMonitorChannel") | |
| s.stop = make(chan struct{}) | |
| return s.stop | |
| } | |
| return nil | |
| } | |
| // CloseMonitorChannel closes any existing monitor channel. | |
| func (s *Health) CloseMonitorChannel() { | |
| s.mu.Lock() | |
| defer s.mu.Unlock() | |
| if s.stop != nil { | |
| log.G(context.TODO()).Debug("CloseMonitorChannel: waiting for probe to stop") | |
| close(s.stop) | |
| s.stop = nil | |
| // unhealthy when the monitor has stopped for compatibility reasons | |
| s.Health.Status = types.Unhealthy | |
| log.G(context.TODO()).Debug("CloseMonitorChannel done") | |
| } | |
| } |