summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrent Baude <bbaude@redhat.com>2021-12-15 13:32:57 -0600
committerBrent Baude <bbaude@redhat.com>2022-01-06 13:56:54 -0600
commit2a524fcaec4e6f66461d7cdda1bb73ed7c50f026 (patch)
treea9aa7d871da64cb5c70b5d139bdde3cc4481184f
parent2fd6c2ee89e92ced8568d7ed3ea3f04017b154ed (diff)
downloadpodman-2a524fcaec4e6f66461d7cdda1bb73ed7c50f026.tar.gz
podman-2a524fcaec4e6f66461d7cdda1bb73ed7c50f026.tar.bz2
podman-2a524fcaec4e6f66461d7cdda1bb73ed7c50f026.zip
fix healthcheck timeouts and ut8 coercion
this commit fixes two bugs and adds regression tests. when getting healthcheck values from an image, if the image does not have a timeout defined, this resulted in a 0 value for timeout. The default as described in the man pages is 30s. when inspecting a container with a healthcheck command, a customer observed that the &, <, and > characters were being converted into a unicode escape value. It turns out json marshalling will by default coerce string values to ut8. Fixes: bz2028408 Signed-off-by: Brent Baude <bbaude@redhat.com>
-rw-r--r--cmd/podman/common/create.go8
-rw-r--r--cmd/podman/common/create_opts.go9
-rw-r--r--cmd/podman/common/default.go9
-rw-r--r--cmd/podman/inspect/inspect.go12
-rw-r--r--libpod/define/healthchecks.go13
-rw-r--r--pkg/specgen/generate/container.go8
-rw-r--r--test/e2e/healthcheck_run_test.go38
7 files changed, 75 insertions, 22 deletions
diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go
index 32d227e65..b60169990 100644
--- a/cmd/podman/common/create.go
+++ b/cmd/podman/common/create.go
@@ -257,7 +257,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
healthIntervalFlagName := "health-interval"
createFlags.StringVar(
&cf.HealthInterval,
- healthIntervalFlagName, DefaultHealthCheckInterval,
+ healthIntervalFlagName, define.DefaultHealthCheckInterval,
"set an interval for the healthchecks (a value of disable results in no automatic timer setup)",
)
_ = cmd.RegisterFlagCompletionFunc(healthIntervalFlagName, completion.AutocompleteNone)
@@ -265,7 +265,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
healthRetriesFlagName := "health-retries"
createFlags.UintVar(
&cf.HealthRetries,
- healthRetriesFlagName, DefaultHealthCheckRetries,
+ healthRetriesFlagName, define.DefaultHealthCheckRetries,
"the number of retries allowed before a healthcheck is considered to be unhealthy",
)
_ = cmd.RegisterFlagCompletionFunc(healthRetriesFlagName, completion.AutocompleteNone)
@@ -273,7 +273,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
healthStartPeriodFlagName := "health-start-period"
createFlags.StringVar(
&cf.HealthStartPeriod,
- healthStartPeriodFlagName, DefaultHealthCheckStartPeriod,
+ healthStartPeriodFlagName, define.DefaultHealthCheckStartPeriod,
"the initialization time needed for a container to bootstrap",
)
_ = cmd.RegisterFlagCompletionFunc(healthStartPeriodFlagName, completion.AutocompleteNone)
@@ -281,7 +281,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
healthTimeoutFlagName := "health-timeout"
createFlags.StringVar(
&cf.HealthTimeout,
- healthTimeoutFlagName, DefaultHealthCheckTimeout,
+ healthTimeoutFlagName, define.DefaultHealthCheckTimeout,
"the maximum time allowed to complete the healthcheck before an interval is considered failed",
)
_ = cmd.RegisterFlagCompletionFunc(healthTimeoutFlagName, completion.AutocompleteNone)
diff --git a/cmd/podman/common/create_opts.go b/cmd/podman/common/create_opts.go
index f2335a2be..297188a45 100644
--- a/cmd/podman/common/create_opts.go
+++ b/cmd/podman/common/create_opts.go
@@ -11,6 +11,7 @@ import (
"github.com/containers/common/pkg/cgroups"
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v3/cmd/podman/registry"
+ "github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/libpod/network/types"
"github.com/containers/podman/v3/pkg/api/handlers"
"github.com/containers/podman/v3/pkg/domain/entities"
@@ -304,10 +305,10 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, rtc *c
VolumesFrom: cc.HostConfig.VolumesFrom,
Workdir: cc.Config.WorkingDir,
Net: &netInfo,
- HealthInterval: DefaultHealthCheckInterval,
- HealthRetries: DefaultHealthCheckRetries,
- HealthTimeout: DefaultHealthCheckTimeout,
- HealthStartPeriod: DefaultHealthCheckStartPeriod,
+ HealthInterval: define.DefaultHealthCheckInterval,
+ HealthRetries: define.DefaultHealthCheckRetries,
+ HealthTimeout: define.DefaultHealthCheckTimeout,
+ HealthStartPeriod: define.DefaultHealthCheckStartPeriod,
}
if !rootless.IsRootless() {
var ulimits []string
diff --git a/cmd/podman/common/default.go b/cmd/podman/common/default.go
index 7e025c449..7997e761c 100644
--- a/cmd/podman/common/default.go
+++ b/cmd/podman/common/default.go
@@ -5,14 +5,7 @@ import (
)
var (
- // DefaultHealthCheckInterval default value
- DefaultHealthCheckInterval = "30s"
- // DefaultHealthCheckRetries default value
- DefaultHealthCheckRetries uint = 3
- // DefaultHealthCheckStartPeriod default value
- DefaultHealthCheckStartPeriod = "0s"
- // DefaultHealthCheckTimeout default value
- DefaultHealthCheckTimeout = "30s"
+
// DefaultImageVolume default value
DefaultImageVolume = "bind"
// Pull in configured json library
diff --git a/cmd/podman/inspect/inspect.go b/cmd/podman/inspect/inspect.go
index c982b1b7f..482b616af 100644
--- a/cmd/podman/inspect/inspect.go
+++ b/cmd/podman/inspect/inspect.go
@@ -237,12 +237,12 @@ func (i *inspector) inspect(namesOrIDs []string) error {
}
func printJSON(data []interface{}) error {
- buf, err := json.MarshalIndent(data, "", " ")
- if err != nil {
- return err
- }
- _, err = fmt.Println(string(buf))
- return err
+ enc := json.NewEncoder(os.Stdout)
+ // by default, json marshallers will force utf=8 from
+ // a string. this breaks healthchecks that use <,>, &&.
+ enc.SetEscapeHTML(false)
+ enc.SetIndent("", " ")
+ return enc.Encode(data)
}
func printTmpl(typ, row string, data []interface{}) error {
diff --git a/libpod/define/healthchecks.go b/libpod/define/healthchecks.go
index 4114262b6..bde449d30 100644
--- a/libpod/define/healthchecks.go
+++ b/libpod/define/healthchecks.go
@@ -34,3 +34,16 @@ const (
// HealthCheckDefined means the healthcheck was found on the container
HealthCheckDefined HealthCheckStatus = iota
)
+
+// Healthcheck defaults. These are used both in the cli as well in
+// libpod and were moved from cmd/podman/common
+const (
+ // DefaultHealthCheckInterval default value
+ DefaultHealthCheckInterval = "30s"
+ // DefaultHealthCheckRetries default value
+ DefaultHealthCheckRetries uint = 3
+ // DefaultHealthCheckStartPeriod default value
+ DefaultHealthCheckStartPeriod = "0s"
+ // DefaultHealthCheckTimeout default value
+ DefaultHealthCheckTimeout = "30s"
+)
diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go
index 57676db10..5ec7c7b03 100644
--- a/pkg/specgen/generate/container.go
+++ b/pkg/specgen/generate/container.go
@@ -4,6 +4,7 @@ import (
"context"
"os"
"strings"
+ "time"
"github.com/containers/common/libimage"
"github.com/containers/podman/v3/libpod"
@@ -64,6 +65,13 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat
// NOTE: the health check is only set for Docker images
// but inspect will take care of it.
s.HealthConfig = inspectData.HealthCheck
+ if s.HealthConfig != nil && s.HealthConfig.Timeout == 0 {
+ hct, err := time.ParseDuration(define.DefaultHealthCheckTimeout)
+ if err != nil {
+ return nil, err
+ }
+ s.HealthConfig.Timeout = hct
+ }
}
// Image stop signal
diff --git a/test/e2e/healthcheck_run_test.go b/test/e2e/healthcheck_run_test.go
index c2084a6fd..6a79006b6 100644
--- a/test/e2e/healthcheck_run_test.go
+++ b/test/e2e/healthcheck_run_test.go
@@ -2,7 +2,9 @@ package integration
import (
"fmt"
+ "io/ioutil"
"os"
+ "path/filepath"
"time"
define "github.com/containers/podman/v3/libpod/define"
@@ -258,4 +260,40 @@ var _ = Describe("Podman healthcheck run", func() {
Expect(startAgain.OutputToString()).To(Equal("hc"))
Expect(startAgain.ErrorToString()).To(Equal(""))
})
+
+ It("Verify default time is used and no utf-8 escapes", func() {
+ cwd, err := os.Getwd()
+ Expect(err).To(BeNil())
+
+ podmanTest.AddImageToRWStore(ALPINE)
+ // Write target and fake files
+ targetPath, err := CreateTempDirInTempDir()
+ Expect(err).To(BeNil())
+ containerfile := fmt.Sprintf(`FROM %s
+HEALTHCHECK CMD ls -l / 2>&1`, ALPINE)
+ containerfilePath := filepath.Join(targetPath, "Containerfile")
+ err = ioutil.WriteFile(containerfilePath, []byte(containerfile), 0644)
+ Expect(err).To(BeNil())
+ defer func() {
+ Expect(os.Chdir(cwd)).To(BeNil())
+ Expect(os.RemoveAll(targetPath)).To(BeNil())
+ }()
+
+ // make cwd as context root path
+ Expect(os.Chdir(targetPath)).To(BeNil())
+
+ session := podmanTest.Podman([]string{"build", "--format", "docker", "-t", "test", "."})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ run := podmanTest.Podman([]string{"run", "-dt", "--name", "hctest", "test", "ls"})
+ run.WaitWithDefaultTimeout()
+ Expect(run).Should(Exit(0))
+
+ inspect := podmanTest.InspectContainer("hctest")
+ // Check to make sure a default time value was added
+ Expect(inspect[0].Config.Healthcheck.Timeout).To(BeNumerically("==", 30000000000))
+ // Check to make sure characters were not coerced to utf8
+ Expect(inspect[0].Config.Healthcheck.Test).To(Equal([]string{"CMD-SHELL", "ls -l / 2>&1"}))
+ })
})