From fd1f57b3a667f69bb2ae424ec7a7735ef8f1fda4 Mon Sep 17 00:00:00 2001
From: cdoern <cbdoer23@g.holycross.edu>
Date: Mon, 26 Jul 2021 09:05:05 -0400
Subject: Fixed Healthcheck formatting, string to []string

Compat healthcheck tests are of the format []string but podman's were of
the format string. Converted podman's to []string at the specgen level since it has the same effect
and removed the incorrect parsing of compat healthchecks.

fixes #10617

Signed-off-by: cdoern <cdoern@redhat.com>
---
 test/apiv2/python/rest_api/test_v2_0_0_container.py | 10 +++++++++-
 test/e2e/run_test.go                                |  6 +++---
 2 files changed, 12 insertions(+), 4 deletions(-)

(limited to 'test')

diff --git a/test/apiv2/python/rest_api/test_v2_0_0_container.py b/test/apiv2/python/rest_api/test_v2_0_0_container.py
index f252bd401..30d902d8c 100644
--- a/test/apiv2/python/rest_api/test_v2_0_0_container.py
+++ b/test/apiv2/python/rest_api/test_v2_0_0_container.py
@@ -33,9 +33,10 @@ class ContainerTestCase(APITestCase):
         self.assertId(r.content)
         _ = parse(r.json()["Created"])
 
+
         r = requests.post(
             self.podman_url + "/v1.40/containers/create?name=topcontainer",
-            json={"Cmd": ["top"], "Image": "alpine:latest"},
+            json={"Healthcheck": {"Test": ["CMD-SHELL", "exit 0"], "Interval":1000, "Timeout":1000, "Retries": 5}, "Cmd": ["top"], "Image": "alpine:latest"},
         )
         self.assertEqual(r.status_code, 201, r.text)
         payload = r.json()
@@ -49,6 +50,13 @@ class ContainerTestCase(APITestCase):
         state = out["State"]["Health"]
         self.assertIsInstance(state, dict)
 
+        r = requests.get(self.uri(f"/containers/{payload['Id']}/json"))
+        self.assertEqual(r.status_code, 200, r.text)
+        self.assertId(r.content)
+        out = r.json()
+        hc  = out["Config"]["Healthcheck"]["Test"]
+        self.assertListEqual(["CMD-SHELL", "exit 0"], hc)
+
     def test_stats(self):
         r = requests.get(self.uri(self.resolve_container("/containers/{}/stats?stream=false")))
         self.assertIn(r.status_code, (200, 409), r.text)
diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go
index e71e7a248..c9f7cb6a9 100644
--- a/test/e2e/run_test.go
+++ b/test/e2e/run_test.go
@@ -1205,21 +1205,21 @@ USER mail`, BB)
 	})
 
 	It("podman run with bad healthcheck retries", func() {
-		session := podmanTest.Podman([]string{"run", "-dt", "--health-cmd", "[\"foo\"]", "--health-retries", "0", ALPINE, "top"})
+		session := podmanTest.Podman([]string{"run", "-dt", "--health-cmd", "foo", "--health-retries", "0", ALPINE, "top"})
 		session.Wait()
 		Expect(session).To(ExitWithError())
 		Expect(session.ErrorToString()).To(ContainSubstring("healthcheck-retries must be greater than 0"))
 	})
 
 	It("podman run with bad healthcheck timeout", func() {
-		session := podmanTest.Podman([]string{"run", "-dt", "--health-cmd", "[\"foo\"]", "--health-timeout", "0s", ALPINE, "top"})
+		session := podmanTest.Podman([]string{"run", "-dt", "--health-cmd", "foo", "--health-timeout", "0s", ALPINE, "top"})
 		session.WaitWithDefaultTimeout()
 		Expect(session).To(ExitWithError())
 		Expect(session.ErrorToString()).To(ContainSubstring("healthcheck-timeout must be at least 1 second"))
 	})
 
 	It("podman run with bad healthcheck start-period", func() {
-		session := podmanTest.Podman([]string{"run", "-dt", "--health-cmd", "[\"foo\"]", "--health-start-period", "-1s", ALPINE, "top"})
+		session := podmanTest.Podman([]string{"run", "-dt", "--health-cmd", "foo", "--health-start-period", "-1s", ALPINE, "top"})
 		session.WaitWithDefaultTimeout()
 		Expect(session).To(ExitWithError())
 		Expect(session.ErrorToString()).To(ContainSubstring("healthcheck-start-period must be 0 seconds or greater"))
-- 
cgit v1.2.3-54-g00ecf


From a9f6592af6646d3692e8a7260df98dd606aa4d9b Mon Sep 17 00:00:00 2001
From: cdoern <cbdoer23@g.holycross.edu>
Date: Mon, 26 Jul 2021 09:05:05 -0400
Subject: Fixed Healthcheck formatting, string to []string

Compat healthcheck tests are of the format []string but podman's were of
the format string. Converted podman's to []string at the specgen level since it has the same effect
and removed the incorrect parsing of compat healthchecks.

fixes #10617

Signed-off-by: cdoern <cdoern@redhat.com>
---
 cmd/podman/common/create_opts.go |  4 +++-
 cmd/podman/common/specgen.go     | 33 ++++++++++++++++++++++-----------
 test/e2e/healthcheck_run_test.go | 10 ++++++++++
 test/e2e/run_test.go             |  2 +-
 4 files changed, 36 insertions(+), 13 deletions(-)

(limited to 'test')

diff --git a/cmd/podman/common/create_opts.go b/cmd/podman/common/create_opts.go
index cca6399b7..42e0efe5d 100644
--- a/cmd/podman/common/create_opts.go
+++ b/cmd/podman/common/create_opts.go
@@ -521,7 +521,9 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, rtc *c
 		for _, str := range cc.Config.Healthcheck.Test {
 			finCmd = finCmd + str + " "
 		}
-		finCmd = finCmd[:len(finCmd)-1]
+		if len(finCmd) > 1 {
+			finCmd = finCmd[:len(finCmd)-1]
+		}
 		cliOpts.HealthCmd = finCmd
 		cliOpts.HealthInterval = cc.Config.Healthcheck.Interval.String()
 		cliOpts.HealthRetries = uint(cc.Config.Healthcheck.Retries)
diff --git a/cmd/podman/common/specgen.go b/cmd/podman/common/specgen.go
index c0cc7d17b..149869237 100644
--- a/cmd/podman/common/specgen.go
+++ b/cmd/podman/common/specgen.go
@@ -516,7 +516,6 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
 			if len(con) != 2 {
 				return fmt.Errorf("invalid --security-opt 1: %q", opt)
 			}
-
 			switch con[0] {
 			case "apparmor":
 				s.ContainerSecurityConfig.ApparmorProfile = con[1]
@@ -655,21 +654,33 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
 	return nil
 }
 
-func makeHealthCheckFromCli(inCmd string, interval string, retries uint, timeout, startPeriod string) (*manifest.Schema2HealthConfig, error) {
-	var cmdArr []string
-	cmdSplitPrelim := strings.SplitN(inCmd, " ", 2)
-	if cmdSplitPrelim[0] == "CMD-SHELL" {
-		cmdArr = cmdSplitPrelim
-	} else if cmdSplitPrelim[0] != "CMD" && cmdSplitPrelim[0] != "none" { // if it isnt a cmd-shell or a cmd, it is a command
-		cmdArr = []string{"CMD-SHELL"}
-		cmdArr = append(cmdArr, inCmd)
-	} else {
-		cmdArr = strings.Fields(inCmd)
+func makeHealthCheckFromCli(inCmd, interval string, retries uint, timeout, startPeriod string) (*manifest.Schema2HealthConfig, error) {
+	cmdArr := []string{}
+	isArr := true
+	err := json.Unmarshal([]byte(inCmd), &cmdArr) // array unmarshalling
+	if err != nil {
+		cmdArr = strings.SplitN(inCmd, " ", 2) // default for compat
+		isArr = false
 	}
 	// Every healthcheck requires a command
 	if len(cmdArr) == 0 {
 		return nil, errors.New("Must define a healthcheck command for all healthchecks")
 	}
+	concat := ""
+	if cmdArr[0] == "CMD" || cmdArr[0] == "none" { // this is for compat, we are already split properly for most compat cases
+		cmdArr = strings.Fields(inCmd)
+	} else if cmdArr[0] != "CMD-SHELL" { // this is for podman side of things, wont contain the keywords
+		if isArr && len(cmdArr) > 1 { // an array of consecutive commands
+			cmdArr = append([]string{"CMD"}, cmdArr...)
+		} else { // one singular command
+			if len(cmdArr) == 1 {
+				concat = cmdArr[0]
+			} else {
+				concat = strings.Join(cmdArr[0:], " ")
+			}
+			cmdArr = append([]string{"CMD-SHELL"}, concat)
+		}
+	}
 
 	if cmdArr[0] == "none" { // if specified to remove healtcheck
 		cmdArr = []string{"NONE"}
diff --git a/test/e2e/healthcheck_run_test.go b/test/e2e/healthcheck_run_test.go
index ed7958323..bea22ea85 100644
--- a/test/e2e/healthcheck_run_test.go
+++ b/test/e2e/healthcheck_run_test.go
@@ -173,6 +173,16 @@ var _ = Describe("Podman healthcheck run", func() {
 		Expect(inspect[0].State.Healthcheck.Status).To(Equal("healthy"))
 	})
 
+	It("podman healthcheck unhealthy but valid arguments check", func() {
+		session := podmanTest.Podman([]string{"run", "-dt", "--name", "hc", "--health-retries", "2", "--health-cmd", "[\"ls\", \"/foo\"]", ALPINE, "top"})
+		session.WaitWithDefaultTimeout()
+		Expect(session.ExitCode()).To(Equal(0))
+
+		hc := podmanTest.Podman([]string{"healthcheck", "run", "hc"})
+		hc.WaitWithDefaultTimeout()
+		Expect(hc.ExitCode()).To(Equal(1))
+	})
+
 	It("podman healthcheck single healthy result changes failed to healthy", func() {
 		session := podmanTest.Podman([]string{"run", "-dt", "--name", "hc", "--health-retries", "2", "--health-cmd", "ls /foo || exit 1", ALPINE, "top"})
 		session.WaitWithDefaultTimeout()
diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go
index c9f7cb6a9..5a29b035b 100644
--- a/test/e2e/run_test.go
+++ b/test/e2e/run_test.go
@@ -1205,7 +1205,7 @@ USER mail`, BB)
 	})
 
 	It("podman run with bad healthcheck retries", func() {
-		session := podmanTest.Podman([]string{"run", "-dt", "--health-cmd", "foo", "--health-retries", "0", ALPINE, "top"})
+		session := podmanTest.Podman([]string{"run", "-dt", "--health-cmd", "[\"foo\"]", "--health-retries", "0", ALPINE, "top"})
 		session.Wait()
 		Expect(session).To(ExitWithError())
 		Expect(session.ErrorToString()).To(ContainSubstring("healthcheck-retries must be greater than 0"))
-- 
cgit v1.2.3-54-g00ecf