updated
This commit is contained in:
@@ -18,12 +18,14 @@ import (
|
||||
type ContainerState string
|
||||
|
||||
const (
|
||||
StateRunning ContainerState = "running"
|
||||
StateStopped ContainerState = "stopped"
|
||||
StateRestarting ContainerState = "restarting"
|
||||
StateExited ContainerState = "exited"
|
||||
StatePaused ContainerState = "paused"
|
||||
StateUnknown ContainerState = "unknown"
|
||||
StateRunning ContainerState = "running"
|
||||
StateStarting ContainerState = "starting" // running but health: starting
|
||||
StateUnhealthy ContainerState = "unhealthy" // running but health: unhealthy
|
||||
StateStopped ContainerState = "stopped"
|
||||
StateRestarting ContainerState = "restarting"
|
||||
StateExited ContainerState = "exited"
|
||||
StatePaused ContainerState = "paused"
|
||||
StateUnknown ContainerState = "unknown"
|
||||
StateNotDeployed ContainerState = "not_deployed"
|
||||
)
|
||||
|
||||
@@ -32,7 +34,7 @@ type ContainerInfo struct {
|
||||
Name string `json:"name"`
|
||||
Image string `json:"image"`
|
||||
State ContainerState `json:"state"`
|
||||
Status string `json:"status"` // e.g. "Up 3 hours"
|
||||
Status string `json:"status"` // e.g. "Up 3 hours (healthy)"
|
||||
}
|
||||
|
||||
// Stack represents a docker compose stack on disk.
|
||||
@@ -193,9 +195,9 @@ func (m *Manager) refreshStatusLocked() error {
|
||||
}
|
||||
|
||||
ci := ContainerInfo{
|
||||
Name: parts[0],
|
||||
Image: parts[1],
|
||||
State: parseContainerState(parts[2]),
|
||||
Name: parts[0],
|
||||
Image: parts[1],
|
||||
State: resolveContainerState(parts[2], parts[3]),
|
||||
Status: parts[3],
|
||||
}
|
||||
projectContainers[parts[4]] = append(projectContainers[parts[4]], ci)
|
||||
@@ -220,10 +222,27 @@ func (m *Manager) refreshStatusLocked() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseContainerState(s string) ContainerState {
|
||||
switch strings.ToLower(strings.TrimSpace(s)) {
|
||||
// resolveContainerState determines the effective state by combining Docker's
|
||||
// State field (running/exited/etc.) with the Status field that contains health info.
|
||||
//
|
||||
// Docker State: "running", "exited", "restarting", "paused", "created", "dead", "removing"
|
||||
// Docker Status: "Up 3 hours (healthy)", "Up 9 seconds (health: starting)", "Up 2 min (unhealthy)"
|
||||
func resolveContainerState(dockerState, dockerStatus string) ContainerState {
|
||||
state := strings.ToLower(strings.TrimSpace(dockerState))
|
||||
status := strings.ToLower(dockerStatus)
|
||||
|
||||
switch state {
|
||||
case "running":
|
||||
// Check health sub-status for containers with healthchecks
|
||||
if strings.Contains(status, "(health: starting)") {
|
||||
return StateStarting
|
||||
}
|
||||
if strings.Contains(status, "(unhealthy)") {
|
||||
return StateUnhealthy
|
||||
}
|
||||
// "(healthy)" or no healthcheck = running
|
||||
return StateRunning
|
||||
|
||||
case "exited":
|
||||
return StateExited
|
||||
case "restarting":
|
||||
@@ -237,20 +256,61 @@ func parseContainerState(s string) ContainerState {
|
||||
}
|
||||
}
|
||||
|
||||
// aggregateState determines the overall stack state from its containers.
|
||||
// Priority: unhealthy/starting > restarting > all-running > stopped
|
||||
func aggregateState(containers []ContainerInfo) ContainerState {
|
||||
if len(containers) == 0 {
|
||||
return StateNotDeployed
|
||||
}
|
||||
|
||||
running := 0
|
||||
starting := 0
|
||||
unhealthy := 0
|
||||
restarting := 0
|
||||
stopped := 0
|
||||
|
||||
for _, c := range containers {
|
||||
if c.State == StateRunning {
|
||||
return StateRunning
|
||||
switch c.State {
|
||||
case StateRunning:
|
||||
running++
|
||||
case StateStarting:
|
||||
starting++
|
||||
case StateUnhealthy:
|
||||
unhealthy++
|
||||
case StateRestarting:
|
||||
restarting++
|
||||
case StateStopped, StateExited:
|
||||
stopped++
|
||||
}
|
||||
}
|
||||
for _, c := range containers {
|
||||
if c.State == StateRestarting {
|
||||
return StateRestarting
|
||||
}
|
||||
|
||||
total := len(containers)
|
||||
|
||||
// Any unhealthy → whole stack is unhealthy
|
||||
if unhealthy > 0 {
|
||||
return StateUnhealthy
|
||||
}
|
||||
// Any still starting → stack is starting
|
||||
if starting > 0 {
|
||||
return StateStarting
|
||||
}
|
||||
// Any restarting → stack is restarting
|
||||
if restarting > 0 {
|
||||
return StateRestarting
|
||||
}
|
||||
// All running (and healthy) → stack is running
|
||||
if running == total {
|
||||
return StateRunning
|
||||
}
|
||||
// All stopped → stack is stopped
|
||||
if stopped == total {
|
||||
return StateStopped
|
||||
}
|
||||
// Mix (some running, some stopped) — report as running (partial)
|
||||
if running > 0 {
|
||||
return StateRunning
|
||||
}
|
||||
|
||||
return StateStopped
|
||||
}
|
||||
|
||||
@@ -449,4 +509,4 @@ func (m *Manager) execCommand(name string, args ...string) (string, error) {
|
||||
}
|
||||
|
||||
return stdout.String(), nil
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user