From 44885b7e0c7db3c93c744841bb72adee6053a270 Mon Sep 17 00:00:00 2001 From: Robin Syl Date: Sat, 23 Sep 2023 12:04:17 +0200 Subject: [PATCH 1/4] Use new Podman flags for healthcheck Signed-off-by: Robin Syl --- podman_compose.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/podman_compose.py b/podman_compose.py index 52434ff1..bba7fe98 100755 --- a/podman_compose.py +++ b/podman_compose.py @@ -1020,10 +1020,9 @@ async def container_to_args(compose, cnt, detached=True): # If it's a string, it's equivalent to specifying CMD-SHELL if is_str(healthcheck_test): # podman does not add shell to handle command with whitespace - podman_args.extend([ - "--healthcheck-command", - "/bin/sh -c " + cmd_quote(healthcheck_test), - ]) + podman_args.extend( + ["--health-cmd", "/bin/sh -c " + cmd_quote(healthcheck_test)] + ) elif is_list(healthcheck_test): healthcheck_test = healthcheck_test.copy() # If it's a list, first item is either NONE, CMD or CMD-SHELL. @@ -1032,12 +1031,12 @@ async def container_to_args(compose, cnt, detached=True): podman_args.append("--no-healthcheck") elif healthcheck_type == "CMD": cmd_q = "' '".join([cmd_quote(i) for i in healthcheck_test]) - podman_args.extend(["--healthcheck-command", "/bin/sh -c " + cmd_q]) + podman_args.extend(["--health-cmd", "/bin/sh -c " + cmd_q]) elif healthcheck_type == "CMD-SHELL": if len(healthcheck_test) != 1: raise ValueError("'CMD_SHELL' takes a single string after it") cmd_q = cmd_quote(healthcheck_test[0]) - podman_args.extend(["--healthcheck-command", "/bin/sh -c " + cmd_q]) + podman_args.extend(["--health-cmd", "/bin/sh -c " + cmd_q]) else: raise ValueError( f"unknown healthcheck test type [{healthcheck_type}],\ @@ -1048,15 +1047,15 @@ async def container_to_args(compose, cnt, detached=True): # interval, timeout and start_period are specified as durations. if "interval" in healthcheck: - podman_args.extend(["--healthcheck-interval", healthcheck["interval"]]) + podman_args.extend(["--health-interval", healthcheck["interval"]]) if "timeout" in healthcheck: - podman_args.extend(["--healthcheck-timeout", healthcheck["timeout"]]) + podman_args.extend(["--health-timeout", healthcheck["timeout"]]) if "start_period" in healthcheck: - podman_args.extend(["--healthcheck-start-period", healthcheck["start_period"]]) + podman_args.extend(["--health-start-period", healthcheck["start_period"]]) # convert other parameters to string if "retries" in healthcheck: - podman_args.extend(["--healthcheck-retries", str(healthcheck["retries"])]) + podman_args.extend(["--health-retries", str(healthcheck["retries"])]) # handle podman extension x_podman = cnt.get("x-podman", None) From 64ec99c7fb094357af78402d915e1c2c54937c2c Mon Sep 17 00:00:00 2001 From: Robin Syl Date: Sat, 23 Sep 2023 12:34:54 +0200 Subject: [PATCH 2/4] Support start_interval in healthcheck block Signed-off-by: Robin Syl --- podman_compose.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/podman_compose.py b/podman_compose.py index bba7fe98..b7bd3ca8 100755 --- a/podman_compose.py +++ b/podman_compose.py @@ -1045,13 +1045,15 @@ async def container_to_args(compose, cnt, detached=True): else: raise ValueError("'healthcheck.test' either a string or a list") - # interval, timeout and start_period are specified as durations. + # interval, timeout, start_period, and start_interval are specified as durations. if "interval" in healthcheck: podman_args.extend(["--health-interval", healthcheck["interval"]]) if "timeout" in healthcheck: podman_args.extend(["--health-timeout", healthcheck["timeout"]]) if "start_period" in healthcheck: podman_args.extend(["--health-start-period", healthcheck["start_period"]]) + if "start_interval" in healthcheck: + podman_args.extend(["--health-startup-interval", healthcheck["start_interval"]]) # convert other parameters to string if "retries" in healthcheck: From efccf15a55057efbe88c574531df7c315ca97d3e Mon Sep 17 00:00:00 2001 From: Robin Syl Date: Mon, 11 Mar 2024 23:26:10 +0100 Subject: [PATCH 3/4] Unit test for healthcheck block Signed-off-by: Robin Syl --- tests/healthcheck/docker-compose.yml | 11 +++++++ tests/test_podman_compose_up_down.py | 45 ++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 tests/healthcheck/docker-compose.yml diff --git a/tests/healthcheck/docker-compose.yml b/tests/healthcheck/docker-compose.yml new file mode 100644 index 00000000..5c12b3c3 --- /dev/null +++ b/tests/healthcheck/docker-compose.yml @@ -0,0 +1,11 @@ +version: "3" +services: + healthcheck: + image: nopush/podman-compose-test + healthcheck: + test: [ "CMD-SHELL", "curl -f http://localhost || exit 1" ] + interval: 1m + timeout: 10s + retries: 3 + start_period: 10s + start_interval: 5s diff --git a/tests/test_podman_compose_up_down.py b/tests/test_podman_compose_up_down.py index 93b92fdd..d91cb3a5 100644 --- a/tests/test_podman_compose_up_down.py +++ b/tests/test_podman_compose_up_down.py @@ -7,6 +7,7 @@ """ # pylint: disable=redefined-outer-name +import json import os import unittest @@ -89,3 +90,47 @@ def test_up(self, profiles, expected_services): actual_services[service] = service in actual_output self.assertEqual(expected_services, actual_services) + + def test_healthcheck(self): + up_cmd = [ + "coverage", + "run", + podman_compose_path(), + "-f", + os.path.join(test_path(), "healthcheck", "docker-compose.yml"), + "up", + "-d", + ] + self.run_subprocess_assert_returncode(up_cmd) + + command_container_id = [ + "podman", + "ps", + "-a", + "--filter", + "label=io.podman.compose.project=healthcheck", + "--format", + '"{{.ID}}"', + ] + out, _ = self.run_subprocess_assert_returncode(command_container_id) + self.assertNotEqual(out, b"") + container_id = out.decode("utf-8").strip().replace('"', "") + + command_inspect = ["podman", "container", "inspect", container_id] + + out, _ = self.run_subprocess_assert_returncode(command_inspect) + out_string = out.decode("utf-8") + inspect = json.loads(out_string) + healthcheck_obj = inspect[0]["Config"]["Healthcheck"] + expected = { + "Test": ["CMD-SHELL", "/bin/sh -c 'curl -f http://localhost || exit 1'"], + "StartPeriod": 10000000000, + "Interval": 60000000000, + "Timeout": 10000000000, + "Retries": 3, + } + self.assertEqual(healthcheck_obj, expected) + + # StartInterval is not available in the config object + create_obj = inspect[0]["Config"]["CreateCommand"] + self.assertIn("--health-startup-interval", create_obj) From f512566759a8a9c65dc9b0f21d46a6dd0c20e588 Mon Sep 17 00:00:00 2001 From: Robin Syl Date: Mon, 11 Mar 2024 23:49:44 +0100 Subject: [PATCH 4/4] run formatter Signed-off-by: Robin Syl --- podman_compose.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) mode change 100755 => 100644 podman_compose.py diff --git a/podman_compose.py b/podman_compose.py old mode 100755 new mode 100644 index b7bd3ca8..9f597bcc --- a/podman_compose.py +++ b/podman_compose.py @@ -1020,9 +1020,7 @@ async def container_to_args(compose, cnt, detached=True): # If it's a string, it's equivalent to specifying CMD-SHELL if is_str(healthcheck_test): # podman does not add shell to handle command with whitespace - podman_args.extend( - ["--health-cmd", "/bin/sh -c " + cmd_quote(healthcheck_test)] - ) + podman_args.extend(["--health-cmd", "/bin/sh -c " + cmd_quote(healthcheck_test)]) elif is_list(healthcheck_test): healthcheck_test = healthcheck_test.copy() # If it's a list, first item is either NONE, CMD or CMD-SHELL.