ps shows healthcheck only for running container

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
Nicolas De Loof 2021-05-17 09:04:52 +02:00
parent 0a02f7d108
commit 221f420ce2
No known key found for this signature in database
GPG Key ID: 9858809D6F8F6E7E
4 changed files with 31 additions and 38 deletions

View File

@ -284,6 +284,7 @@ type ContainerSummary struct {
Service string
State string
Health string
ExitCode int
Publishers []PortPublisher
}

View File

@ -103,8 +103,10 @@ func runPs(ctx context.Context, backend compose.Service, services []string, opts
}
}
status := container.State
if container.Health != "" {
if status == "running" && container.Health != "" {
status = fmt.Sprintf("%s (%s)", container.State, container.Health)
} else if status == "exited" || status == "dead" {
status = fmt.Sprintf("%s (%d)", container.State, container.ExitCode)
}
_, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", container.Name, container.Service, status, strings.Join(ports, ", "))
}

View File

@ -19,10 +19,10 @@ package compose
import (
"context"
"fmt"
"golang.org/x/sync/errgroup"
"sort"
"github.com/docker/compose-cli/api/compose"
"golang.org/x/sync/errgroup"
)
func (s *composeService) Ps(ctx context.Context, projectName string, options compose.PsOptions) ([]compose.ContainerSummary, error) {
@ -42,6 +42,9 @@ func (s *composeService) Ps(ctx context.Context, projectName string, options com
i := i
eg.Go(func() error {
var publishers []compose.PortPublisher
sort.Slice(container.Ports, func(i, j int) bool {
return container.Ports[i].PrivatePort < container.Ports[j].PrivatePort
})
for _, p := range container.Ports {
var url string
if p.PublicPort != 0 {
@ -60,9 +63,19 @@ func (s *composeService) Ps(ctx context.Context, projectName string, options com
return err
}
var health string
if inspect.State != nil && inspect.State.Health != nil {
health = inspect.State.Health.Status
var (
health string
exitCode int
)
if inspect.State != nil {
switch inspect.State.Status {
case "running":
if inspect.State.Health != nil {
health = inspect.State.Health.Status
}
case "exited", "dead":
exitCode = inspect.State.ExitCode
}
}
summary[i] = compose.ContainerSummary{
@ -72,6 +85,7 @@ func (s *composeService) Ps(ctx context.Context, projectName string, options com
Service: container.Labels[serviceLabel],
State: container.State,
Health: health,
ExitCode: exitCode,
Publishers: publishers,
}
return nil

View File

@ -40,10 +40,10 @@ func TestPs(t *testing.T) {
args := filters.NewArgs(projectFilter(testProject))
args.Add("label", "com.docker.compose.oneoff=False")
listOpts := apitypes.ContainerListOptions{Filters: args, All: true}
c1, inspect1 := containerDetails("service1", "123", "Running", "healthy")
c2, inspect2 := containerDetails("service1", "456", "Running", "")
c1, inspect1 := containerDetails("service1", "123", "running", "healthy", 0)
c2, inspect2 := containerDetails("service1", "456", "running", "", 0)
c2.Ports = []apitypes.Port{{PublicPort: 80, PrivatePort: 90, IP: "localhost"}}
c3, inspect3 := containerDetails("service2", "789", "Running", "")
c3, inspect3 := containerDetails("service2", "789", "exited", "", 130)
api.EXPECT().ContainerList(ctx, listOpts).Return([]apitypes.Container{c1, c2, c3}, nil)
api.EXPECT().ContainerInspect(anyCancellableContext(), "123").Return(inspect1, nil)
api.EXPECT().ContainerInspect(anyCancellableContext(), "456").Return(inspect2, nil)
@ -52,45 +52,21 @@ func TestPs(t *testing.T) {
containers, err := tested.Ps(ctx, testProject, compose.PsOptions{})
expected := []compose.ContainerSummary{
{ID: "123", Name: "123", Project: testProject, Service: "service1", State: "Running", Health: "healthy", Publishers: nil},
{ID: "456", Name: "456", Project: testProject, Service: "service1", State: "Running", Health: "", Publishers: []compose.PortPublisher{{URL: "localhost:80", TargetPort: 90, PublishedPort: 80}}},
{ID: "789", Name: "789", Project: testProject, Service: "service2", State: "Running", Health: "", Publishers: nil},
{ID: "123", Name: "123", Project: testProject, Service: "service1", State: "running", Health: "healthy", Publishers: nil},
{ID: "456", Name: "456", Project: testProject, Service: "service1", State: "running", Health: "", Publishers: []compose.PortPublisher{{URL: "localhost:80", TargetPort: 90, PublishedPort: 80}}},
{ID: "789", Name: "789", Project: testProject, Service: "service2", State: "exited", Health: "", ExitCode: 130, Publishers: nil},
}
assert.NilError(t, err)
assert.DeepEqual(t, containers, expected)
}
func TestPsAll(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
api := mocks.NewMockAPIClient(mockCtrl)
tested.apiClient = api
ctx := context.Background()
listOpts := apitypes.ContainerListOptions{Filters: filters.NewArgs(projectFilter(testProject)), All: true}
c1, inspect1 := containerDetails("service1", "123", "Running", "healthy")
c2, inspect2 := containerDetails("service1", "456", "Stopped", "")
api.EXPECT().ContainerList(ctx, listOpts).Return([]apitypes.Container{c1, c2}, nil)
api.EXPECT().ContainerInspect(anyCancellableContext(), "123").Return(inspect1, nil)
api.EXPECT().ContainerInspect(anyCancellableContext(), "456").Return(inspect2, nil)
containers, err := tested.Ps(ctx, testProject, compose.PsOptions{All: true})
expected := []compose.ContainerSummary{
{ID: "123", Name: "123", Project: testProject, Service: "service1", State: "Running", Health: "healthy", Publishers: nil},
{ID: "456", Name: "456", Project: testProject, Service: "service1", State: "Stopped", Health: "", Publishers: nil},
}
assert.NilError(t, err)
assert.DeepEqual(t, containers, expected)
}
func containerDetails(service string, id string, status string, health string) (apitypes.Container, apitypes.ContainerJSON) {
func containerDetails(service string, id string, status string, health string, exitCode int) (apitypes.Container, apitypes.ContainerJSON) {
container := apitypes.Container{
ID: id,
Names: []string{"/" + id},
Labels: containerLabels(service),
State: status,
}
inspect := apitypes.ContainerJSON{ContainerJSONBase: &apitypes.ContainerJSONBase{State: &apitypes.ContainerState{Status: status, Health: &apitypes.Health{Status: health}}}}
inspect := apitypes.ContainerJSON{ContainerJSONBase: &apitypes.ContainerJSONBase{State: &apitypes.ContainerState{Status: status, Health: &apitypes.Health{Status: health}, ExitCode: exitCode}}}
return container, inspect
}