8000 Add Health attribute on the docker ps command · moby/moby@6e7a2c8 · GitHub
[go: up one dir, main page]

Skip to content

Commit 6e7a2c8

Browse files
mdaffadthaJeztah
authored andcommitted
Add Health attribute on the docker ps command
Signed-off-by: Muhammad Daffa Dinaya <muhammaddaffadinaya@gmail.com> Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
1 parent 81caaba commit 6e7a2c8

File tree

9 files changed

+133
-0
lines changed

9 files changed

+133
-0
lines changed

api/swagger.yaml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5346,6 +5346,29 @@ definitions:
53465346
List of mounts used by the container.
53475347
items:
53485348
$ref: "#/definitions/MountPoint"
5349+
Health:
5350+
type: "object"
5351+
description: |-
5352+
Summary of health status
5353+
5354+
Added in v1.52, before that version all container summary not include Health.
5355+
After this attribute introduced, it includes containers with no health checks configured,
5356+
or containers that are not running with none
5357+
properties:
5358+
Status:
5359+
type: "string"
5360+
description: |-
5361+
the health status of the container
5362+
enum:
5363+
- "none"
5364+
- "starting"
5365+
- "healthy"
5366+
- "unhealthy"
5367+
example: "healthy"
5368+
FailingStreak:
5369+
description: "FailingStreak is the number of consecutive failures"
5370+
type: "integer"
5371+
example: 0
53495372

53505373
Driver:
53515374
description: "Driver represents a driver (network, logging, secrets)."

api/types/container/container.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ type Summary struct {
128128
NetworkMode string `json:",omitempty"`
129129
Annotations map[string]string `json:",omitempty"`
130130
}
131+
Health *HealthSummary `json:",omitempty"`
131132
NetworkSettings *NetworkSettingsSummary
132133
Mounts []MountPoint
133134
}

api/types/container/health.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ type Health struct {
2626
Log []*HealthcheckResult // Log contains the last few results (oldest first)
2727
}
2828

29+
// HealthSummary stores a summary of the container's healthcheck results.
30+
type HealthSummary struct {
31+
Status HealthStatus // Status is one of [NoHealthcheck], [Starting], [Healthy] or [Unhealthy].
32+
FailingStreak int // FailingStreak is the number of consecutive failures
33+
}
34+
2935
// HealthcheckResult stores information about a single run of a healthcheck probe
3036
type HealthcheckResult struct {
3137
Start time.Time // Start is the time this check started

daemon/container/view.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,9 +296,17 @@ func (v *View) GetAllNames() map[string][]string {
296296
// A lock on the Container is not held because these are immutable deep copies.
297297
func (v *View) transform(ctr *Container) *Snapshot {
298298
health := container.NoHealthcheck
299+
failingStreak := 0
299300
if ctr.Health != nil {
300301
health = ctr.Health.Status()
302+
failingStreak = ctr.Health.FailingStreak
301303
}
304+
305+
healthSummary := &container.HealthSummary{
306+
Status: health,
307+
FailingStreak: failingStreak,
308+
}
309+
302310
snapshot := &Snapshot{
303311
Summary: container.Summary{
304312
ID: ctr.ID,
@@ -308,6 +316,7 @@ func (v *View) transform(ctr *Container) *Snapshot {
308316
Mounts: ctr.GetMountPoints(),
309317
State: ctr.State.StateString(),
310318
Status: ctr.State.String(),
319+
Health: healthSummary,
311320
Created: ctr.Created.Unix(),
312321
},
313322
CreatedAt: ctr.Created,

daemon/server/router/container/container_routes.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,12 @@ func (c *containerRouter) getContainersJSON(ctx context.Context, w http.Response
119119
}
120120
}
121121

122+
if versions.LessThan(version, "1.52") {
123+
for _, c := range containers {
124+
c.Health = nil
125+
}
126+
}
127+
122128
return httputils.WriteJSON(w, http.StatusOK, containers)
123129
}
124130

integration/container/list_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
package container
22

33
import (
4+
"context"
45
"fmt"
56
"testing"
7+
"time"
68

79
"github.com/docker/docker/integration/internal/container"
810
"github.com/docker/docker/testutil"
911
"github.com/docker/docker/testutil/request"
1012
containertypes "github.com/moby/moby/api/types/container"
1113
"github.com/moby/moby/api/types/filters"
14+
"github.com/moby/moby/api/types/versions"
1215
"github.com/moby/moby/client"
1316
"gotest.tools/v3/assert"
1417
is "gotest.tools/v3/assert/cmp"
18+
"gotest.tools/v3/poll"
1519
"gotest.tools/v3/skip"
1620
)
1721

@@ -143,3 +147,57 @@ func TestContainerList_ImageManifestPlatform(t *testing.T) {
143147
assert.Check(t, ctr.ImageManifestDescriptor.Platform.Architecture != "")
144148
}
145149
}
150+
151+
func pollForHealthStatusSummary(ctx context.Context, client client.APIClient, containerID string, healthStatus containertypes.HealthStatus) func(log poll.LogT) poll.Result {
152+
return func(log poll.LogT) poll.Result {
153+
containers, err := client.ContainerList(ctx, containertypes.ListOptions{
154+
All: true,
155+
Filters: filters.NewArgs(filters.Arg("id", containerID)),
156+
})
157+
if err != nil {
158+
return poll.Error(err)
159+
}
160+
total := 0
161+
version := client.ClientVersion()
162+
for _, ctr := range containers {
163+
if ctr.Health == nil && versions.LessThan(version, "1.52") {
164+
total++
165+
} else if ctr.Health != nil && ctr.Health.Status == healthStatus && versions.GreaterThanOrEqualTo(version, "1.52") {
166+
total++
167+
}
168+
}
169+
170+
if total == len(containers) {
171+
return poll.Success()
172+
}
173+
174+
return poll.Continue("waiting for container to become %s", healthStatus)
175+
}
176+
}
177+
178+
func TestContainerList_HealthSummary(t *testing.T) {
179+
skip.If(t, testEnv.DaemonInfo.OSType == "windows", "FIXME")
180+
ctx := setupTest(t)
181+
testcases := []struct {
182+
apiVersion string
183+
}{
184+
{apiVersion: "1.51"},
185+
{apiVersion: "1.52"},
186+
}
187+
188+
for _, tc := range testcases {
189+
t.Run(fmt.Sprintf("run with version v%s", tc.apiVersion), func(t *testing.T) {
190+
apiClient := request.NewAPIClient(t, client.WithVersion(tc.apiVersion))
191+
192+
cID := container.Run(ctx, t, apiClient, container.WithTty(true), container.WithWorkingDir("/foo"), func(c *container.TestContainerConfig) {
193+
c.Config.Healthcheck = &containertypes.HealthConfig{
194+
Test: []string{"CMD-SHELL", "if [ \"$PWD\" = \"/foo\" ]; then exit 0; else exit 1; fi;"},
195+
Interval: 50 * time.Millisecond,
196+
Retries: 3,
197+
}
198+
})
199+
200+
poll.WaitOn(t, pollForHealthStatusSummary(ctx, apiClient, cID, containertypes.Healthy))
201+
})
202+
}
203+
}

vendor/github.com/moby/moby/api/swagger.yaml

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/moby/moby/api/types/container/container.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/moby/moby/api/types/container/health.go

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)
0