Return nil health when inspecting containers without healthchecks

When inspecting a container that does not define any health check, the health field should return nil. This matches docker behavior.

Signed-off-by: Ashley Cui <acui@redhat.com>
This commit is contained in:
Ashley Cui 2024-01-26 14:03:57 -05:00
parent 4bef65240e
commit a1c47f0299
4 changed files with 54 additions and 43 deletions

View File

@ -189,15 +189,20 @@ func (c *Container) getContainerInspectData(size bool, driverData *define.Driver
data.OCIConfigPath = c.state.ConfigPath data.OCIConfigPath = c.state.ConfigPath
} }
if c.config.HealthCheckConfig != nil { // Check if healthcheck is not nil and --no-healthcheck option is not set.
// If --no-healthcheck is set Test will be always set to `[NONE]`, so the
// inspect status should be set to nil.
if c.config.HealthCheckConfig != nil && !(len(c.config.HealthCheckConfig.Test) == 1 && c.config.HealthCheckConfig.Test[0] == "NONE") {
// This container has a healthcheck defined in it; we need to add its state // This container has a healthcheck defined in it; we need to add its state
healthCheckState, err := c.getHealthCheckLog() healthCheckState, err := c.getHealthCheckLog()
if err != nil { if err != nil {
// An error here is not considered fatal; no health state will be displayed // An error here is not considered fatal; no health state will be displayed
logrus.Error(err) logrus.Error(err)
} else { } else {
data.State.Health = healthCheckState data.State.Health = &healthCheckState
} }
} else {
data.State.Health = nil
} }
networkConfig, err := c.getContainerNetworkInfo() networkConfig, err := c.getContainerNetworkInfo()

View File

@ -206,34 +206,34 @@ type InspectMount struct {
// Docker, but here we see more fields that are unused (nonsensical in the // Docker, but here we see more fields that are unused (nonsensical in the
// context of Libpod). // context of Libpod).
type InspectContainerState struct { type InspectContainerState struct {
OciVersion string `json:"OciVersion"` OciVersion string `json:"OciVersion"`
Status string `json:"Status"` Status string `json:"Status"`
Running bool `json:"Running"` Running bool `json:"Running"`
Paused bool `json:"Paused"` Paused bool `json:"Paused"`
Restarting bool `json:"Restarting"` // TODO Restarting bool `json:"Restarting"` // TODO
OOMKilled bool `json:"OOMKilled"` OOMKilled bool `json:"OOMKilled"`
Dead bool `json:"Dead"` Dead bool `json:"Dead"`
Pid int `json:"Pid"` Pid int `json:"Pid"`
ConmonPid int `json:"ConmonPid,omitempty"` ConmonPid int `json:"ConmonPid,omitempty"`
ExitCode int32 `json:"ExitCode"` ExitCode int32 `json:"ExitCode"`
Error string `json:"Error"` // TODO Error string `json:"Error"` // TODO
StartedAt time.Time `json:"StartedAt"` StartedAt time.Time `json:"StartedAt"`
FinishedAt time.Time `json:"FinishedAt"` FinishedAt time.Time `json:"FinishedAt"`
Health HealthCheckResults `json:"Health,omitempty"` Health *HealthCheckResults `json:"Health,omitempty"`
Checkpointed bool `json:"Checkpointed,omitempty"` Checkpointed bool `json:"Checkpointed,omitempty"`
CgroupPath string `json:"CgroupPath,omitempty"` CgroupPath string `json:"CgroupPath,omitempty"`
CheckpointedAt time.Time `json:"CheckpointedAt,omitempty"` CheckpointedAt time.Time `json:"CheckpointedAt,omitempty"`
RestoredAt time.Time `json:"RestoredAt,omitempty"` RestoredAt time.Time `json:"RestoredAt,omitempty"`
CheckpointLog string `json:"CheckpointLog,omitempty"` CheckpointLog string `json:"CheckpointLog,omitempty"`
CheckpointPath string `json:"CheckpointPath,omitempty"` CheckpointPath string `json:"CheckpointPath,omitempty"`
RestoreLog string `json:"RestoreLog,omitempty"` RestoreLog string `json:"RestoreLog,omitempty"`
Restored bool `json:"Restored,omitempty"` Restored bool `json:"Restored,omitempty"`
StoppedByUser bool `json:"StoppedByUser,omitempty"` StoppedByUser bool `json:"StoppedByUser,omitempty"`
} }
// Healthcheck returns the HealthCheckResults. This is used for old podman compat // Healthcheck returns the HealthCheckResults. This is used for old podman compat
// to make the "Healthcheck" key available in the go template. // to make the "Healthcheck" key available in the go template.
func (s *InspectContainerState) Healthcheck() HealthCheckResults { func (s *InspectContainerState) Healthcheck() *HealthCheckResults {
return s.Health return s.Health
} }

View File

@ -442,22 +442,28 @@ func LibpodToContainerJSON(l *libpod.Container, sz bool) (*types.ContainerJSON,
} }
if l.HasHealthCheck() && state.Status != "created" { if l.HasHealthCheck() && state.Status != "created" {
state.Health = &types.Health{ state.Health = &types.Health{}
Status: inspect.State.Health.Status, if inspect.State.Health != nil {
FailingStreak: inspect.State.Health.FailingStreak, state.Health.Status = inspect.State.Health.Status
} state.Health.FailingStreak = inspect.State.Health.FailingStreak
log := inspect.State.Health.Log
log := inspect.State.Health.Log for _, item := range log {
res := &types.HealthcheckResult{}
for _, item := range log { s, err := time.Parse(time.RFC3339Nano, item.Start)
res := &types.HealthcheckResult{} if err != nil {
s, _ := time.Parse(time.RFC3339Nano, item.Start) return nil, err
e, _ := time.Parse(time.RFC3339Nano, item.End) }
res.Start = s e, err := time.Parse(time.RFC3339Nano, item.End)
res.End = e if err != nil {
res.ExitCode = item.ExitCode return nil, err
res.Output = item.Output }
state.Health.Log = append(state.Health.Log, res) res.Start = s
res.End = e
res.ExitCode = item.ExitCode
res.Output = item.Output
state.Health.Log = append(state.Health.Log, res)
}
} }
} }

View File

@ -34,10 +34,10 @@ var _ = Describe("Podman healthcheck run", func() {
session := podmanTest.Podman([]string{"run", "-dt", "--no-healthcheck", "--name", "hc", HEALTHCHECK_IMAGE}) session := podmanTest.Podman([]string{"run", "-dt", "--no-healthcheck", "--name", "hc", HEALTHCHECK_IMAGE})
session.WaitWithDefaultTimeout() session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly()) Expect(session).Should(ExitCleanly())
hc := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.State.Health.Status}}", "hc"}) hc := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.State.Health}}", "hc"})
hc.WaitWithDefaultTimeout() hc.WaitWithDefaultTimeout()
Expect(hc).Should(ExitCleanly()) Expect(hc).Should(ExitCleanly())
Expect(hc.OutputToString()).To(Not(ContainSubstring("starting"))) Expect(hc.OutputToString()).To(Equal("<nil>"))
}) })
It("podman run healthcheck and logs should contain healthcheck output", func() { It("podman run healthcheck and logs should contain healthcheck output", func() {