Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support all healthcheck options in Compose #780

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 10 additions & 11 deletions podman_compose.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -1020,10 +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([
"--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.
Expand All @@ -1032,12 +1029,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])

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think in CMD case this should be executed with /bin/sh prevents cases from working where there is no /bin/sh in the image like minimal images for Rust applications. I don't have docker to verify, but from the documentation, my understanding is that this is ran without shell.

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}],\
Expand All @@ -1046,17 +1043,19 @@ 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(["--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"]])
if "start_interval" in healthcheck:
podman_args.extend(["--health-startup-interval", healthcheck["start_interval"]])

# 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)
Expand Down
11 changes: 11 additions & 0 deletions tests/healthcheck/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -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
45 changes: 45 additions & 0 deletions tests/test_podman_compose_up_down.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"""

# pylint: disable=redefined-outer-name
import json
import os
import unittest

Expand Down Expand Up @@ -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)
Loading