diff options
author | baude <bbaude@redhat.com> | 2019-03-06 12:12:35 -0600 |
---|---|---|
committer | baude <bbaude@redhat.com> | 2019-03-12 14:29:18 -0500 |
commit | 03716cf7f331fa5b5ffab23dcc863bedd66b5dfc (patch) | |
tree | 866b063270455a6cd0dc91d95e91cf1d3ca7b53d /cmd/podman/shared/create.go | |
parent | 7038cac53c4c93cd088fdbb097eee8d45494c3b8 (diff) | |
download | podman-03716cf7f331fa5b5ffab23dcc863bedd66b5dfc.tar.gz podman-03716cf7f331fa5b5ffab23dcc863bedd66b5dfc.tar.bz2 podman-03716cf7f331fa5b5ffab23dcc863bedd66b5dfc.zip |
healtcheck phase 2
integration of healthcheck into create and run as well as inspect.
healthcheck enhancements are as follows:
* add the following options to create|run so that non-docker images can
define healthchecks at the container level.
* --healthcheck-command
* --healthcheck-retries
* --healthcheck-interval
* --healthcheck-start-period
* podman create|run --healthcheck-command=none disables healthcheck as
described by an image.
* the healthcheck itself and the healthcheck "history" can now be
observed in podman inspect
* added the wiring for healthcheck history which logs the health history
of the container, the current failed streak attempts, and log entries
for the last five attempts which themselves have start and stop times,
result, and a 500 character truncated (if needed) log of stderr/stdout.
The timings themselves are not implemented in this PR but will be in
future enablement (i.e. next).
Signed-off-by: baude <bbaude@redhat.com>
Diffstat (limited to 'cmd/podman/shared/create.go')
-rw-r--r-- | cmd/podman/shared/create.go | 98 |
1 files changed, 83 insertions, 15 deletions
diff --git a/cmd/podman/shared/create.go b/cmd/podman/shared/create.go index bfd05d53e..32a80e9f9 100644 --- a/cmd/podman/shared/create.go +++ b/cmd/podman/shared/create.go @@ -11,6 +11,7 @@ import ( "strconv" "strings" "syscall" + "time" "github.com/containers/image/manifest" "github.com/containers/libpod/cmd/podman/cliconfig" @@ -26,6 +27,7 @@ import ( "github.com/docker/docker/pkg/signal" "github.com/docker/go-connections/nat" "github.com/docker/go-units" + "github.com/google/shlex" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/selinux/go-selinux/label" "github.com/opentracing/opentracing-go" @@ -40,8 +42,7 @@ func getContext() context.Context { func CreateContainer(ctx context.Context, c *cliconfig.PodmanCommand, runtime *libpod.Runtime) (*libpod.Container, *cc.CreateConfig, error) { var ( - hasHealthCheck bool - healthCheck *manifest.Schema2HealthConfig + healthCheck *manifest.Schema2HealthConfig ) if c.Bool("trace") { span, _ := opentracing.StartSpanFromContext(ctx, "createContainer") @@ -89,18 +90,31 @@ func CreateContainer(ctx context.Context, c *cliconfig.PodmanCommand, runtime *l imageName = newImage.ID() } - // add healthcheck if it exists AND is correct mediatype - _, mediaType, err := newImage.Manifest(ctx) - if err != nil { - return nil, nil, errors.Wrapf(err, "unable to determine mediatype of image %s", newImage.ID()) - } - if mediaType == manifest.DockerV2Schema2MediaType { - healthCheck, err = newImage.GetHealthCheck(ctx) - if err != nil { - return nil, nil, errors.Wrapf(err, "unable to get healthcheck for %s", c.InputArgs[0]) - } - if healthCheck != nil { - hasHealthCheck = true + var healthCheckCommandInput string + // if the user disabled the healthcheck with "none", we skip adding it + healthCheckCommandInput = c.String("healthcheck-command") + + // the user didnt disable the healthcheck but did pass in a healthcheck command + // now we need to make a healthcheck from the commandline input + if healthCheckCommandInput != "none" { + if len(healthCheckCommandInput) > 0 { + healthCheck, err = makeHealthCheckFromCli(c) + if err != nil { + return nil, nil, errors.Wrapf(err, "unable to create healthcheck") + } + } else { + // the user did not disable the health check and did not pass in a healthcheck + // command as input. so now we add healthcheck if it exists AND is correct mediatype + _, mediaType, err := newImage.Manifest(ctx) + if err != nil { + return nil, nil, errors.Wrapf(err, "unable to determine mediatype of image %s", newImage.ID()) + } + if mediaType == manifest.DockerV2Schema2MediaType { + healthCheck, err = newImage.GetHealthCheck(ctx) + if err != nil { + return nil, nil, errors.Wrapf(err, "unable to get healthcheck for %s", c.InputArgs[0]) + } + } } } } @@ -111,7 +125,6 @@ func CreateContainer(ctx context.Context, c *cliconfig.PodmanCommand, runtime *l // Because parseCreateOpts does derive anything from the image, we add health check // at this point. The rest is done by WithOptions. - createConfig.HasHealthCheck = hasHealthCheck createConfig.HealthCheck = healthCheck ctr, err := CreateContainerFromCreateConfig(runtime, createConfig, ctx, nil) @@ -835,3 +848,58 @@ var defaultEnvVariables = map[string]string{ "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "TERM": "xterm", } + +func makeHealthCheckFromCli(c *cliconfig.PodmanCommand) (*manifest.Schema2HealthConfig, error) { + inCommand := c.String("healthcheck-command") + inInterval := c.String("healthcheck-interval") + inRetries := c.Uint("healthcheck-retries") + inTimeout := c.String("healthcheck-timeout") + inStartPeriod := c.String("healthcheck-start-period") + + // Every healthcheck requires a command + if len(inCommand) == 0 { + return nil, errors.New("Must define a healthcheck command for all healthchecks") + } + + cmd, err := shlex.Split(inCommand) + if err != nil { + return nil, errors.Wrap(err, "failed to parse healthcheck command") + } + hc := manifest.Schema2HealthConfig{ + Test: cmd, + } + intervalDuration, err := time.ParseDuration(inInterval) + if err != nil { + return nil, errors.Wrapf(err, "invalid healthcheck-interval %s ", inInterval) + } + + if intervalDuration < time.Duration(time.Second*1) { + return nil, errors.New("healthcheck-interval must be at least 1 second") + } + + hc.Interval = intervalDuration + + if inRetries < 1 { + return nil, errors.New("healthcheck-retries must be greater than 0.") + } + + timeoutDuration, err := time.ParseDuration(inTimeout) + if err != nil { + return nil, errors.Wrapf(err, "invalid healthcheck-timeout %s", inTimeout) + } + if timeoutDuration < time.Duration(time.Second*1) { + return nil, errors.New("healthcheck-timeout must be at least 1 second") + } + hc.Timeout = timeoutDuration + + startPeriodDuration, err := time.ParseDuration(inStartPeriod) + if err != nil { + return nil, errors.Wrapf(err, "invalid healthcheck-start-period %s", inStartPeriod) + } + if startPeriodDuration < time.Duration(0) { + return nil, errors.New("healthcheck-start-period must be a 0 seconds or greater") + } + hc.StartPeriod = startPeriodDuration + + return &hc, nil +} |