summaryrefslogtreecommitdiff
path: root/libpod/healthcheck.go
diff options
context:
space:
mode:
Diffstat (limited to 'libpod/healthcheck.go')
-rw-r--r--libpod/healthcheck.go92
1 files changed, 92 insertions, 0 deletions
diff --git a/libpod/healthcheck.go b/libpod/healthcheck.go
new file mode 100644
index 000000000..81addb9a8
--- /dev/null
+++ b/libpod/healthcheck.go
@@ -0,0 +1,92 @@
+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
+}