package checks import ( "context" "encoding/json" "os/exec" "strings" "time" ) // Container is one docker container's summary state. type Container struct { Name string Image string State string // running, exited, ... Status string // human string, e.g. "Up 3 hours" } // Containers runs `docker ps -a` and parses the line-delimited JSON output. // Returns ([], "") when docker works but no containers exist. func Containers(ctx context.Context) ([]Container, string) { ctx, cancel := context.WithTimeout(ctx, 8*time.Second) defer cancel() // docker emits one JSON object per line with --format json. out, err := exec.CommandContext(ctx, "docker", "ps", "-a", "--format", "json").Output() if err != nil { msg := err.Error() if ee, ok := err.(*exec.ExitError); ok && len(ee.Stderr) > 0 { msg = strings.TrimSpace(string(ee.Stderr)) } return nil, msg } var list []Container for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") { if line == "" { continue } var row struct { Names string `json:"Names"` Image string `json:"Image"` State string `json:"State"` Status string `json:"Status"` } if err := json.Unmarshal([]byte(line), &row); err != nil { continue } list = append(list, Container{ Name: row.Names, Image: row.Image, State: row.State, Status: row.Status, }) } return list, "" }