mirror of
https://github.com/containers/podman
synced 2024-10-20 17:23:30 +00:00
93 lines
3.1 KiB
Go
93 lines
3.1 KiB
Go
|
package libpod
|
||
|
|
||
|
import (
|
||
|
"os"
|
||
|
"strings"
|
||
|
|
||
|
"github.com/pkg/errors"
|
||
|
"github.com/sirupsen/logrus"
|
||
|
)
|
||
|
|
||
|
// HealthCheckStatus represents the current state of a container
|
||
|
type HealthCheckStatus int
|
||
|
|
||
|
const (
|
||
|
// HealthCheckSuccess means the health worked
|
||
|
HealthCheckSuccess HealthCheckStatus = iota
|
||
|
// HealthCheckFailure means the health ran and failed
|
||
|
HealthCheckFailure HealthCheckStatus = iota
|
||
|
// HealthCheckContainerStopped means the health check cannot
|
||
|
// be run because the container is stopped
|
||
|
HealthCheckContainerStopped HealthCheckStatus = iota
|
||
|
// HealthCheckContainerNotFound means the container could
|
||
|
// not be found in local store
|
||
|
HealthCheckContainerNotFound HealthCheckStatus = iota
|
||
|
// HealthCheckNotDefined means the container has no health
|
||
|
// check defined in it
|
||
|
HealthCheckNotDefined HealthCheckStatus = iota
|
||
|
// HealthCheckInternalError means somes something failed obtaining or running
|
||
|
// a given health check
|
||
|
HealthCheckInternalError HealthCheckStatus = iota
|
||
|
// HealthCheckDefined means the healthcheck was found on the container
|
||
|
HealthCheckDefined HealthCheckStatus = iota
|
||
|
)
|
||
|
|
||
|
// HealthCheck verifies the state and validity of the healthcheck configuration
|
||
|
// on the container and then executes the healthcheck
|
||
|
func (r *Runtime) HealthCheck(name string) (HealthCheckStatus, error) {
|
||
|
container, err := r.LookupContainer(name)
|
||
|
if err != nil {
|
||
|
return HealthCheckContainerNotFound, errors.Wrapf(err, "unable to lookup %s to perform a health check", name)
|
||
|
}
|
||
|
hcStatus, err := checkHealthCheckCanBeRun(container)
|
||
|
if err == nil {
|
||
|
return container.RunHealthCheck()
|
||
|
}
|
||
|
return hcStatus, err
|
||
|
}
|
||
|
|
||
|
// RunHealthCheck runs the health check as defined by the container
|
||
|
func (c *Container) RunHealthCheck() (HealthCheckStatus, error) {
|
||
|
var newCommand []string
|
||
|
hcStatus, err := checkHealthCheckCanBeRun(c)
|
||
|
if err != nil {
|
||
|
return hcStatus, err
|
||
|
}
|
||
|
hcCommand := c.HealthCheckConfig().Test
|
||
|
if len(hcCommand) > 0 && hcCommand[0] == "CMD-SHELL" {
|
||
|
newCommand = []string{"sh", "-c"}
|
||
|
newCommand = append(newCommand, hcCommand[1:]...)
|
||
|
} else {
|
||
|
newCommand = hcCommand
|
||
|
}
|
||
|
// TODO when history/logging is implemented for healthcheck, we need to change the output streams
|
||
|
// so we can capture i/o
|
||
|
streams := new(AttachStreams)
|
||
|
streams.OutputStream = os.Stdout
|
||
|
streams.ErrorStream = os.Stderr
|
||
|
streams.InputStream = os.Stdin
|
||
|
streams.AttachOutput = true
|
||
|
streams.AttachError = true
|
||
|
streams.AttachInput = true
|
||
|
|
||
|
logrus.Debugf("executing health check command %s for %s", strings.Join(newCommand, " "), c.ID())
|
||
|
if err := c.Exec(false, false, []string{}, newCommand, "", "", streams, 0); err != nil {
|
||
|
return HealthCheckFailure, err
|
||
|
}
|
||
|
return HealthCheckSuccess, nil
|
||
|
}
|
||
|
|
||
|
func checkHealthCheckCanBeRun(c *Container) (HealthCheckStatus, error) {
|
||
|
cstate, err := c.State()
|
||
|
if err != nil {
|
||
|
return HealthCheckInternalError, err
|
||
|
}
|
||
|
if cstate != ContainerStateRunning {
|
||
|
return HealthCheckContainerStopped, errors.Errorf("container %s is not running", c.ID())
|
||
|
}
|
||
|
if !c.HasHealthCheck() {
|
||
|
return HealthCheckNotDefined, errors.Errorf("container %s has no defined healthcheck", c.ID())
|
||
|
}
|
||
|
return HealthCheckDefined, nil
|
||
|
}
|