diff --git a/podman_compose.py b/podman_compose.py index ed61c35..6428fde 100755 --- a/podman_compose.py +++ b/podman_compose.py @@ -440,8 +440,7 @@ def mount_desc_to_mount_args(compose, mount_desc, srv_name, cnt_name): # pylint raise ValueError("unknown mount type:" + mount_type) -def container_to_ulimit_args(cnt, podman_args): - ulimit = cnt.get("ulimits", []) +def ulimit_to_ulimit_args(ulimit, podman_args): if ulimit is not None: # ulimit can be a single value, i.e. ulimit: host if is_str(ulimit): @@ -457,6 +456,17 @@ def container_to_ulimit_args(cnt, podman_args): podman_args.extend(["--ulimit", i]) +def container_to_ulimit_args(cnt, podman_args): + ulimit_to_ulimit_args(cnt.get("ulimits", []), podman_args) + + +def container_to_ulimit_build_args(cnt, podman_args): + build = cnt.get("build", None) + + if build is not None: + ulimit_to_ulimit_args(build.get("ulimits", []), podman_args) + + def mount_desc_to_volume_args(compose, mount_desc, srv_name, cnt_name): # pylint: disable=unused-argument mount_type = mount_desc["type"] if mount_type not in ("bind", "volume"): @@ -2166,7 +2176,7 @@ async def build_one(compose, args, cnt): build_args.extend(["-t", tag]) if "target" in build_desc: build_args.extend(["--target", build_desc["target"]]) - container_to_ulimit_args(cnt, build_args) + container_to_ulimit_build_args(cnt, build_args) if getattr(args, "no_cache", None): build_args.append("--no-cache") if getattr(args, "pull_always", None): diff --git a/tests/test_podman_compose_build_ulimits.py b/tests/test_podman_compose_build_ulimits.py new file mode 100644 index 0000000..389ff91 --- /dev/null +++ b/tests/test_podman_compose_build_ulimits.py @@ -0,0 +1,95 @@ +# SPDX-License-Identifier: GPL-2.0 + + +"""Test how ulimits are applied in podman-compose build.""" + +import os +import subprocess +import unittest + +from .test_podman_compose import podman_compose_path +from .test_podman_compose import test_path + + +def compose_yaml_path(): + """ "Returns the path to the compose file used for this test module""" + return os.path.join(test_path(), "ulimit_build") + + +class TestComposeBuildUlimits(unittest.TestCase): + def test_build_ulimits_ulimit1(self): + """podman build should receive and apply limits when building service ulimit1""" + + cmd = ( + "coverage", + "run", + podman_compose_path(), + "--verbose", + "-f", + os.path.join(compose_yaml_path(), "docker-compose.yaml"), + "build", + "--no-cache", + "ulimit1" + ) + p = subprocess.run( + cmd, stdout=subprocess.PIPE, check=False, stderr=subprocess.STDOUT, text=True + ) + + self.assertEqual(p.returncode, 0) + self.assertIn("--ulimit nofile=1001", p.stdout) + self.assertIn("soft process limit: 253744", p.stdout) + self.assertIn("hard process limit: 253744", p.stdout) + self.assertIn("soft nofile limit: 1001", p.stdout) + self.assertIn("hard nofile limit: 1001", p.stdout) + + def test_build_ulimits_ulimit2(self): + """podman build should receive and apply limits when building service ulimit2""" + + cmd = ( + "coverage", + "run", + podman_compose_path(), + "--verbose", + "-f", + os.path.join(compose_yaml_path(), "docker-compose.yaml"), + "build", + "--no-cache", + "ulimit2" + ) + p = subprocess.run( + cmd, stdout=subprocess.PIPE, check=False, stderr=subprocess.STDOUT, text=True + ) + + self.assertEqual(p.returncode, 0) + self.assertIn("--ulimit nofile=1002", p.stdout) + self.assertIn("--ulimit nproc=1002:2002", p.stdout) + self.assertIn("soft process limit: 1002", p.stdout) + self.assertIn("hard process limit: 2002", p.stdout) + self.assertIn("soft nofile limit: 1002", p.stdout) + self.assertIn("hard nofile limit: 1002", p.stdout) + + def test_build_ulimits_ulimit3(self): + """podman build should receive and apply limits when building service ulimit3""" + + cmd = ( + "coverage", + "run", + podman_compose_path(), + "--verbose", + "-f", + os.path.join(compose_yaml_path(), "docker-compose.yaml"), + "build", + "--no-cache", + "ulimit3" + ) + p = subprocess.run( + cmd, stdout=subprocess.PIPE, check=False, stderr=subprocess.STDOUT, text=True + ) + + self.assertEqual(p.returncode, 0) + self.assertIn("--ulimit nofile=1003", p.stdout) + self.assertIn("--ulimit nproc=1003:2003", p.stdout) + self.assertIn("soft process limit: 1003", p.stdout) + self.assertIn("hard process limit: 2003", p.stdout) + self.assertIn("soft nofile limit: 1003", p.stdout) + self.assertIn("hard nofile limit: 1003", p.stdout) diff --git a/tests/ulimit_build/Dockerfile b/tests/ulimit_build/Dockerfile new file mode 100644 index 0000000..f80774e --- /dev/null +++ b/tests/ulimit_build/Dockerfile @@ -0,0 +1,5 @@ +FROM busybox + +COPY ./ulimit.sh /bin/ulimit.sh + +RUN /bin/ulimit.sh diff --git a/tests/ulimit_build/docker-compose.yaml b/tests/ulimit_build/docker-compose.yaml new file mode 100644 index 0000000..ade949e --- /dev/null +++ b/tests/ulimit_build/docker-compose.yaml @@ -0,0 +1,26 @@ +version: "3" +services: + ulimit1: + image: ulimit_build_test + build: + context: ./ + dockerfile: Dockerfile + ulimits: nofile=1001 + ulimit2: + image: ulimit_build_test + build: + context: ./ + dockerfile: Dockerfile + ulimits: + - nproc=1002:2002 + - nofile=1002 + ulimit3: + image: ulimit_build_test + build: + context: ./ + dockerfile: Dockerfile + ulimits: + nofile: 1003 + nproc: + soft: 1003 + hard: 2003 diff --git a/tests/ulimit_build/ulimit.sh b/tests/ulimit_build/ulimit.sh new file mode 100755 index 0000000..1685b3d --- /dev/null +++ b/tests/ulimit_build/ulimit.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +echo "soft process limit:" $(ulimit -S -u) +echo "hard process limit:" $(ulimit -H -u) +echo "soft nofile limit:" $(ulimit -S -n) +echo "hard nofile limit:" $(ulimit -H -n)