Merge pull request #1214 from mokibit/fix-cmd-healthcheck

Fix CMD healthchecks running with `/bin/sh`
This commit is contained in:
Povilas Kanapickas 2025-05-21 15:52:43 +03:00 committed by GitHub
commit c26e188991
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 74 additions and 11 deletions

View File

@ -0,0 +1 @@
Fixed support for CMD healthchecks to run using the given command directly and not using `/bin/sh -c`.

View File

@ -29,14 +29,8 @@ import urllib.parse
from asyncio import Task
from enum import Enum
try:
from shlex import quote as cmd_quote
except ImportError:
from pipes import quote as cmd_quote # pylint: disable=deprecated-module
# import fnmatch
# fnmatch.fnmatchcase(env, "*_HOST")
import yaml
from dotenv import dotenv_values
@ -1228,7 +1222,7 @@ async def container_to_args(compose, cnt, detached=True, no_deps=False):
# podman does not add shell to handle command with whitespace
podman_args.extend([
"--healthcheck-command",
"/bin/sh -c " + cmd_quote(healthcheck_test),
json.dumps(["CMD-SHELL", healthcheck_test]),
])
elif is_list(healthcheck_test):
healthcheck_test = healthcheck_test.copy()
@ -1237,13 +1231,11 @@ async def container_to_args(compose, cnt, detached=True, no_deps=False):
if healthcheck_type == "NONE":
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(["--healthcheck-command", json.dumps(healthcheck_test)])
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(["--healthcheck-command", json.dumps(healthcheck_test)])
else:
raise ValueError(
f"unknown healthcheck test type [{healthcheck_type}],\

View File

@ -694,3 +694,73 @@ class TestContainerToArgs(unittest.IsolatedAsyncioTestCase):
with self.assertRaises(ValueError):
await container_to_args(c, cnt)
async def test_heathcheck_string(self):
c = create_compose_mock()
cnt = get_minimal_container()
cnt["healthcheck"] = {
"test": "cmd arg1 arg2",
}
args = await container_to_args(c, cnt)
self.assertEqual(
args,
[
"--name=project_name_service_name1",
"-d",
"--network=bridge:alias=service_name",
"--healthcheck-command",
'["CMD-SHELL", "cmd arg1 arg2"]',
"busybox",
],
)
async def test_heathcheck_cmd_args(self):
c = create_compose_mock()
cnt = get_minimal_container()
cnt["healthcheck"] = {
"test": ["CMD", "cmd", "arg1", "arg2"],
}
args = await container_to_args(c, cnt)
self.assertEqual(
args,
[
"--name=project_name_service_name1",
"-d",
"--network=bridge:alias=service_name",
"--healthcheck-command",
'["cmd", "arg1", "arg2"]',
"busybox",
],
)
async def test_heathcheck_cmd_shell(self):
c = create_compose_mock()
cnt = get_minimal_container()
cnt["healthcheck"] = {
"test": ["CMD-SHELL", "cmd arg1 arg2"],
}
args = await container_to_args(c, cnt)
self.assertEqual(
args,
[
"--name=project_name_service_name1",
"-d",
"--network=bridge:alias=service_name",
"--healthcheck-command",
'["cmd arg1 arg2"]',
"busybox",
],
)
async def test_heathcheck_cmd_shell_error(self):
c = create_compose_mock()
cnt = get_minimal_container()
cnt["healthcheck"] = {
"test": ["CMD-SHELL", "cmd arg1", "arg2"],
}
with self.assertRaises(ValueError):
await container_to_args(c, cnt)