diff --git a/internal/orchestrator/helpers.go b/internal/orchestrator/helpers.go index 3b94b654..19360356 100644 --- a/internal/orchestrator/helpers.go +++ b/internal/orchestrator/helpers.go @@ -19,6 +19,7 @@ import ( "context" "errors" "fmt" + "log/slog" "slices" "strings" @@ -39,25 +40,40 @@ type AppStatusInfo struct { Status Status } +type containerState struct { + Status Status + StatusMessage string +} + // parseAppStatus takes all the containers that matches the DockerAppLabel, // and construct a map of the state of an app and all its dependencies state. // For app that have at least 1 dependency, we calculate the overall state // as follow: // -// running: all running -// stopped: all stopped -// failed: at least one failed -// stopping: at least one stopping -// starting: at least one starting +// running: all running +// stopped: all stopped +// failed: at least one failed +// stopping: at least one stopping +// stopped: at least one stopped +// starting: at least one starting func parseAppStatus(containers []container.Summary) []AppStatusInfo { apps := make([]AppStatusInfo, 0, len(containers)) - appsStatusMap := make(map[string][]Status) + appsStatusMap := make(map[string][]containerState) for _, c := range containers { appPath, ok := c.Labels[DockerAppPathLabel] if !ok { continue } - appsStatusMap[appPath] = append(appsStatusMap[appPath], StatusFromDockerState(c.State)) + appsStatusMap[appPath] = append(appsStatusMap[appPath], containerState{ + Status: StatusFromDockerState(c.State), + StatusMessage: c.Status, + }) + slog.Debug("Container status", + slog.String("appPath", appPath), + slog.String("containerID", c.ID), + slog.String("state", string(c.State)), + slog.String("statusMessage", c.Status), + ) } appendResult := func(appPath *paths.Path, status Status) { @@ -73,27 +89,33 @@ func parseAppStatus(containers []container.Summary) []AppStatusInfo { appPath := paths.New(appPath) // running: all running - if !slices.ContainsFunc(s, func(v Status) bool { return v != StatusRunning }) { + if !slices.ContainsFunc(s, func(v containerState) bool { return v.Status != StatusRunning }) { appendResult(appPath, StatusRunning) continue } // stopped: all stopped - if !slices.ContainsFunc(s, func(v Status) bool { return v != StatusStopped }) { + if !slices.ContainsFunc(s, func(v containerState) bool { return v.Status != StatusStopped }) { appendResult(appPath, StatusStopped) continue } // ...else we have multiple different status we calculate the status // among the possible left: {failed, stopping, starting} - if slices.ContainsFunc(s, func(v Status) bool { return v == StatusFailed }) { + if slices.ContainsFunc(s, func(v containerState) bool { return v.Status == StatusFailed }) { + appendResult(appPath, StatusFailed) + continue + } + if slices.ContainsFunc(s, func(v containerState) bool { + return v.Status == StatusStopped && strings.Contains(v.StatusMessage, "Exited (0)") + }) { appendResult(appPath, StatusFailed) continue } - if slices.ContainsFunc(s, func(v Status) bool { return v == StatusStopping }) { + if slices.ContainsFunc(s, func(v containerState) bool { return v.Status == StatusStopping }) { appendResult(appPath, StatusStopping) continue } - if slices.ContainsFunc(s, func(v Status) bool { return v == StatusStarting }) { + if slices.ContainsFunc(s, func(v containerState) bool { return v.Status == StatusStarting }) { appendResult(appPath, StatusStarting) continue }