api/types/container: make HealthStatus a concrete type

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn
2025-11-07 18:36:12 +01:00
parent 1fd87e9fdf
commit db71c6a914
8 changed files with 27 additions and 24 deletions

View File

@@ -7,9 +7,7 @@ import (
) )
// HealthStatus is a string representation of the container's health. // HealthStatus is a string representation of the container's health.
// type HealthStatus string
// It currently is an alias for string, but may become a distinct type in future.
type HealthStatus = string
// Health states // Health states
const ( const (
@@ -41,7 +39,10 @@ type HealthcheckResult struct {
} }
var validHealths = []string{ var validHealths = []string{
NoHealthcheck, Starting, Healthy, Unhealthy, string(NoHealthcheck),
string(Starting),
string(Healthy),
string(Unhealthy),
} }
// ValidateHealthStatus checks if the provided string is a valid // ValidateHealthStatus checks if the provided string is a valid

View File

@@ -19,7 +19,7 @@ func TestValidateHealthStatus(t *testing.T) {
} }
for _, tc := range tests { for _, tc := range tests {
t.Run(tc.health, func(t *testing.T) { t.Run(string(tc.health), func(t *testing.T) {
err := ValidateHealthStatus(tc.health) err := ValidateHealthStatus(tc.health)
if tc.expectedErr == "" { if tc.expectedErr == "" {
assert.NilError(t, err) assert.NilError(t, err)

View File

@@ -23,7 +23,7 @@ func (s *Health) String() string {
case container.Starting: case container.Starting:
return "health: starting" return "health: starting"
default: // Healthy and Unhealthy are clear on their own default: // Healthy and Unhealthy are clear on their own
return status return string(status)
} }
} }

View File

@@ -244,7 +244,7 @@ func handleProbeResult(d *Daemon, c *container.Container, result *containertypes
current := h.Status() current := h.Status()
if oldStatus != current { if oldStatus != current {
d.LogContainerEvent(c, events.Action(string(events.ActionHealthStatus)+": "+current)) d.LogContainerEvent(c, events.Action(string(events.ActionHealthStatus)+": "+string(current)))
} }
} }

View File

@@ -298,7 +298,7 @@ func (daemon *Daemon) foldFilter(ctx context.Context, view *container.View, conf
} }
err = psFilters.WalkValues("health", func(value string) error { err = psFilters.WalkValues("health", func(value string) error {
if err := containertypes.ValidateHealthStatus(value); err != nil { if err := containertypes.ValidateHealthStatus(containertypes.HealthStatus(value)); err != nil {
return errdefs.InvalidParameter(fmt.Errorf("invalid filter 'health=%s': %w", value, err)) return errdefs.InvalidParameter(fmt.Errorf("invalid filter 'health=%s': %w", value, err))
} }
return nil return nil
@@ -491,7 +491,7 @@ func includeContainerInList(container *container.Snapshot, filter *listContext)
} }
// Do not include container if its health doesn't match the filter // Do not include container if its health doesn't match the filter
if !filter.filters.ExactMatch("health", container.Health) { if !filter.filters.ExactMatch("health", string(container.Health)) {
return excludeContainer return excludeContainer
} }

View File

@@ -26,16 +26,17 @@ func (s *DockerCLIHealthSuite) OnTimeout(t *testing.T) {
s.ds.OnTimeout(t) s.ds.OnTimeout(t)
} }
func waitForHealthStatus(t *testing.T, name string, prev string, expected string) { func waitForHealthStatus(t *testing.T, name string, prev container.HealthStatus, expected container.HealthStatus) {
prev = prev + "\n"
expected = expected + "\n"
for { for {
out := cli.DockerCmd(t, "inspect", "--format={{.State.Health.Status}}", name).Stdout() out := cli.DockerCmd(t, "inspect", "--format={{.State.Health.Status}}", name).Stdout()
if out == expected { actual := container.HealthStatus(strings.TrimSpace(out))
if actual == expected {
return return
} }
assert.Equal(t, out, prev)
if out != prev { // TODO(thaJeztah): this logic seems broken? assert.Assert would make it fail, so why the "actual != prev"?
assert.Equal(t, actual, prev)
if actual != prev {
return return
} }
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
@@ -84,7 +85,7 @@ func (s *DockerCLIHealthSuite) TestHealth(c *testing.T) {
// Inspect the status // Inspect the status
out = cli.DockerCmd(c, "inspect", "--format={{.State.Health.Status}}", name).Stdout() out = cli.DockerCmd(c, "inspect", "--format={{.State.Health.Status}}", name).Stdout()
assert.Equal(c, strings.TrimSpace(out), container.Unhealthy) assert.Equal(c, container.HealthStatus(strings.TrimSpace(out)), container.Unhealthy)
// Make it healthy again // Make it healthy again
cli.DockerCmd(c, "exec", name, "touch", "/status") cli.DockerCmd(c, "exec", name, "touch", "/status")

View File

@@ -140,10 +140,11 @@ func TestHealthStartInterval(t *testing.T) {
return poll.Error(err) return poll.Error(err)
} }
if inspect.Container.State.Health.Status != containertypes.Healthy { if inspect.Container.State.Health.Status != containertypes.Healthy {
var out string
if len(inspect.Container.State.Health.Log) > 0 { if len(inspect.Container.State.Health.Log) > 0 {
t.Log(inspect.Container.State.Health.Log[len(inspect.Container.State.Health.Log)-1]) out = inspect.Container.State.Health.Log[len(inspect.Container.State.Health.Log)-1].Output
} }
return poll.Continue("waiting on container to be ready") return poll.Continue("waiting on container to be ready (%s): %s", inspect.Container.ID, out)
} }
return poll.Success() return poll.Success()
}, poll.WithTimeout(time.Until(dl))) }, poll.WithTimeout(time.Until(dl)))
@@ -169,8 +170,7 @@ func TestHealthStartInterval(t *testing.T) {
if h1.Start.Sub(h2.Start) >= inspect.Container.Config.Healthcheck.Interval { if h1.Start.Sub(h2.Start) >= inspect.Container.Config.Healthcheck.Interval {
return poll.Success() return poll.Success()
} }
t.Log(h1.Start.Sub(h2.Start)) return poll.Continue("waiting for health check interval to switch from the start interval: %s", h1.Start.Sub(h2.Start))
return poll.Continue("waiting for health check interval to switch from the start interval")
}, poll.WithDelay(time.Second), poll.WithTimeout(time.Until(dl))) }, poll.WithDelay(time.Second), poll.WithTimeout(time.Until(dl)))
} }

View File

@@ -7,9 +7,7 @@ import (
) )
// HealthStatus is a string representation of the container's health. // HealthStatus is a string representation of the container's health.
// type HealthStatus string
// It currently is an alias for string, but may become a distinct type in future.
type HealthStatus = string
// Health states // Health states
const ( const (
@@ -41,7 +39,10 @@ type HealthcheckResult struct {
} }
var validHealths = []string{ var validHealths = []string{
NoHealthcheck, Starting, Healthy, Unhealthy, string(NoHealthcheck),
string(Starting),
string(Healthy),
string(Unhealthy),
} }
// ValidateHealthStatus checks if the provided string is a valid // ValidateHealthStatus checks if the provided string is a valid