From 43a2f1d01fb35b23c47c310638ced9689d02c511 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Fri, 7 Feb 2025 00:42:14 +0100 Subject: [PATCH] Implement x-podman.pod_args to override --pod-args default Allow setting an argument list as x-podman.pod_args to override the default value `--infra=false --share=`. `--pod-args` passed on the command line takes precedence over the value set in docker-compose.yml; the values are not merged. Fixes #1057. Signed-off-by: Matthias Schiffer --- docs/Extensions.md | 14 ++ newsfragments/x-podman.pod-args.feature | 1 + podman_compose.py | 16 +- tests/integration/pod_args/__init__.py | 1 + .../custom_pod_args_empty/docker-compose.yml | 7 + .../custom_pod_args_set/docker-compose.yml | 7 + .../custom_pod_args_unset/docker-compose.yml | 5 + .../pod_args/test_podman_compose_pod_args.py | 180 ++++++++++++++++++ tests/unit/test_can_merge_build.py | 1 + tests/unit/test_normalize_final_build.py | 1 + 10 files changed, 229 insertions(+), 4 deletions(-) create mode 100644 newsfragments/x-podman.pod-args.feature create mode 100644 tests/integration/pod_args/__init__.py create mode 100644 tests/integration/pod_args/custom_pod_args_empty/docker-compose.yml create mode 100644 tests/integration/pod_args/custom_pod_args_set/docker-compose.yml create mode 100644 tests/integration/pod_args/custom_pod_args_unset/docker-compose.yml create mode 100644 tests/integration/pod_args/test_podman_compose_pod_args.py diff --git a/docs/Extensions.md b/docs/Extensions.md index fd7941f..12b85b2 100644 --- a/docs/Extensions.md +++ b/docs/Extensions.md @@ -174,3 +174,17 @@ services: x-podman: in_pod: false ``` + +It is also possible to override the default arguments for pod creation that are +used when --pod-args is not passed on the command line: +```yml +version: "3" +services: + cont: + image: nopush/podman-compose-test + command: ["dumb-init", "/bin/busybox", "httpd", "-f", "-p", "8080"] +x-podman: + pod_args: ["--infra=false", "--share=", "--cpus=1"] +``` +When not set in docker-compose.yml or on the command line, the pod args default +to `["--infra=false", "--share="]`. diff --git a/newsfragments/x-podman.pod-args.feature b/newsfragments/x-podman.pod-args.feature new file mode 100644 index 0000000..eef3f50 --- /dev/null +++ b/newsfragments/x-podman.pod-args.feature @@ -0,0 +1 @@ +- Add support for 'x-podman.pod-args' to override the default --pod-args diff --git a/podman_compose.py b/podman_compose.py index 3d1500d..447bb97 100755 --- a/podman_compose.py +++ b/podman_compose.py @@ -1875,6 +1875,15 @@ class PodmanCompose: # otherwise use `in_pod` value provided by command line return self.global_args.in_pod_bool + def resolve_pod_args(self): + # Priorities: + # - Command line --pod-args + # - docker-compose.yml x-podman.pod_args + # - Default value + if self.global_args.pod_args is not None: + return shlex.split(self.global_args.pod_args) + return self.x_podman.get("pod_args", ["--infra=false", "--share="]) + def _parse_compose_file(self): args = self.global_args # cmd = args.command @@ -2133,6 +2142,7 @@ class PodmanCompose: self.x_podman = compose.get("x-podman", {}) args.in_pod_bool = self.resolve_in_pod() + args.pod_arg_list = self.resolve_pod_args() pods, containers = transform(args, project_name, given_containers) self.pods = pods self.containers = containers @@ -2211,7 +2221,7 @@ class PodmanCompose: help="custom arguments to be passed to `podman pod`", metavar="pod_args", type=str, - default="--infra=false --share=", + default=None, ) parser.add_argument( "--env-file", @@ -2616,9 +2626,7 @@ async def create_pods(compose, args): # pylint: disable=unused-argument podman_args = [ "create", "--name=" + pod["name"], - ] - if args.pod_args: - podman_args.extend(shlex.split(args.pod_args)) + ] + args.pod_arg_list # if compose.podman_version and not strverscmp_lt(compose.podman_version, "3.4.0"): # podman_args.append("--infra-name={}_infra".format(pod["name"])) ports = pod.get("ports", []) diff --git a/tests/integration/pod_args/__init__.py b/tests/integration/pod_args/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tests/integration/pod_args/__init__.py @@ -0,0 +1 @@ + diff --git a/tests/integration/pod_args/custom_pod_args_empty/docker-compose.yml b/tests/integration/pod_args/custom_pod_args_empty/docker-compose.yml new file mode 100644 index 0000000..1e4f5e3 --- /dev/null +++ b/tests/integration/pod_args/custom_pod_args_empty/docker-compose.yml @@ -0,0 +1,7 @@ +version: "3" +services: + cont: + image: nopush/podman-compose-test + command: ["dumb-init", "/bin/busybox", "httpd", "-f", "-p", "8080"] +x-podman: + pod_args: [] diff --git a/tests/integration/pod_args/custom_pod_args_set/docker-compose.yml b/tests/integration/pod_args/custom_pod_args_set/docker-compose.yml new file mode 100644 index 0000000..b348ea9 --- /dev/null +++ b/tests/integration/pod_args/custom_pod_args_set/docker-compose.yml @@ -0,0 +1,7 @@ +version: "3" +services: + cont: + image: nopush/podman-compose-test + command: ["dumb-init", "/bin/busybox", "httpd", "-f", "-p", "8080"] +x-podman: + pod_args: ["--infra=false", "--share=", "--cpus=2"] diff --git a/tests/integration/pod_args/custom_pod_args_unset/docker-compose.yml b/tests/integration/pod_args/custom_pod_args_unset/docker-compose.yml new file mode 100644 index 0000000..0f86bca --- /dev/null +++ b/tests/integration/pod_args/custom_pod_args_unset/docker-compose.yml @@ -0,0 +1,5 @@ +version: "3" +services: + cont: + image: nopush/podman-compose-test + command: ["dumb-init", "/bin/busybox", "httpd", "-f", "-p", "8080"] diff --git a/tests/integration/pod_args/test_podman_compose_pod_args.py b/tests/integration/pod_args/test_podman_compose_pod_args.py new file mode 100644 index 0000000..77facd1 --- /dev/null +++ b/tests/integration/pod_args/test_podman_compose_pod_args.py @@ -0,0 +1,180 @@ +# SPDX-License-Identifier: GPL-2.0 + +import json +import os +import unittest + +from tests.integration.test_utils import RunSubprocessMixin + + +def base_path(): + """Returns the base path for the project""" + return os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))) + + +def test_path(): + """Returns the path to the tests directory""" + return os.path.join(base_path(), "tests/integration") + + +def podman_compose_path(): + """Returns the path to the podman compose script""" + return os.path.join(base_path(), "podman_compose.py") + + +class TestPodmanComposePodArgs(unittest.TestCase, RunSubprocessMixin): + def load_pod_info(self, pod_name): + output, _ = self.run_subprocess_assert_returncode([ + "podman", + "pod", + "inspect", + pod_name, + ]) + pod_info = json.loads(output.decode('utf-8')) + # Podman 5.0 changed pod inspect to always output a list. + # Check type to support both old and new version. + if isinstance(pod_info, list): + return pod_info[0] + return pod_info + + def run_pod_args_test(self, config, args, expected): + """ + Helper to run podman up with a docker-compose.yml config, additional + (--pod-args) arguments and compare the CreateCommand of the resulting + pod with an expected value + """ + pod_name = "pod_" + config + command_up = ( + [ + "python3", + os.path.join(base_path(), "podman_compose.py"), + "-f", + os.path.join( + base_path(), + "tests", + "integration", + "pod_args", + config, + "docker-compose.yml", + ), + ] + + args + + [ + "up", + "--no-start", + ] + ) + + try: + self.run_subprocess_assert_returncode(command_up) + + pod_info = self.load_pod_info(pod_name) + self.assertEqual( + pod_info['CreateCommand'], + ["podman", "pod", "create", "--name=" + pod_name] + expected, + ) + + finally: + command_rm_pod = ["podman", "pod", "rm", pod_name] + self.run_subprocess_assert_returncode(command_rm_pod) + + def test_x_podman_pod_args_unset_unset(self): + """ + Test that podman-compose will use the default pod-args when unset in + both docker-compose.yml and command line + """ + self.run_pod_args_test( + "custom_pod_args_unset", + [], + ["--infra=false", "--share="], + ) + + def test_x_podman_pod_args_unset_empty(self): + """ + Test that podman-compose will use empty pod-args when unset in + docker-compose.yml and passing an empty value on the command line + """ + self.run_pod_args_test( + "custom_pod_args_unset", + ["--pod-args="], + [], + ) + + def test_x_podman_pod_args_unset_set(self): + """ + Test that podman-compose will use the passed pod-args when unset in + docker-compose.yml and passing a non-empty value on the command line + """ + self.run_pod_args_test( + "custom_pod_args_unset", + ["--pod-args=--infra=false --share= --cpus=1"], + ["--infra=false", "--share=", "--cpus=1"], + ) + + def test_x_podman_pod_args_empty_unset(self): + """ + Test that podman-compose will use empty pod-args when set to an + empty value in docker-compose.yml and unset on the command line + """ + self.run_pod_args_test( + "custom_pod_args_empty", + [], + [], + ) + + def test_x_podman_pod_args_empty_empty(self): + """ + Test that podman-compose will use empty pod-args when set to an + empty value in both docker-compose.yml and command line + """ + self.run_pod_args_test( + "custom_pod_args_empty", + ["--pod-args="], + [], + ) + + def test_x_podman_pod_args_empty_set(self): + """ + Test that podman-compose will use the passed pod-args when set to an + empty value in docker-compose.yml and passing a non-empty value on the + command line + """ + self.run_pod_args_test( + "custom_pod_args_empty", + ["--pod-args=--infra=false --share= --cpus=1"], + ["--infra=false", "--share=", "--cpus=1"], + ) + + def test_x_podman_pod_args_set_unset(self): + """ + Test that podman-compose will use the set pod-args when set to a + non-empty value in docker-compose.yml and unset on the command line + """ + self.run_pod_args_test( + "custom_pod_args_set", + [], + ["--infra=false", "--share=", "--cpus=2"], + ) + + def test_x_podman_pod_args_set_empty(self): + """ + Test that podman-compose will use empty pod-args when set to a + non-empty value in docker-compose.yml and passing an empty value on + the command line + """ + self.run_pod_args_test( + "custom_pod_args_set", + ["--pod-args="], + [], + ) + + def test_x_podman_pod_args_set_set(self): + """ + Test that podman-compose will use the passed pod-args when set to a + non-empty value in both docker-compose.yml and command line + """ + self.run_pod_args_test( + "custom_pod_args_set", + ["--pod-args=--infra=false --share= --cpus=1"], + ["--infra=false", "--share=", "--cpus=1"], + ) diff --git a/tests/unit/test_can_merge_build.py b/tests/unit/test_can_merge_build.py index 91f3fdd..8fce6e1 100644 --- a/tests/unit/test_can_merge_build.py +++ b/tests/unit/test_can_merge_build.py @@ -140,6 +140,7 @@ def set_args(podman_compose: PodmanCompose, file_names: list[str]) -> None: podman_compose.global_args.env_file = None podman_compose.global_args.profile = [] podman_compose.global_args.in_pod_bool = True + podman_compose.global_args.pod_args = None podman_compose.global_args.no_normalize = True diff --git a/tests/unit/test_normalize_final_build.py b/tests/unit/test_normalize_final_build.py index 34ba0ea..40e81aa 100644 --- a/tests/unit/test_normalize_final_build.py +++ b/tests/unit/test_normalize_final_build.py @@ -250,6 +250,7 @@ def set_args(podman_compose: PodmanCompose, file_names: list[str], no_normalize: podman_compose.global_args.env_file = None podman_compose.global_args.profile = [] podman_compose.global_args.in_pod_bool = True + podman_compose.global_args.pod_args = None podman_compose.global_args.no_normalize = no_normalize