From 0491269f5316cdef30df67922d918b1530b0dccf Mon Sep 17 00:00:00 2001 From: Monika Kairaityte Date: Wed, 4 Jun 2025 11:45:02 +0300 Subject: [PATCH] Fix relative host path resolution for volume bind mount source e03d675b9bcd92864fd1aedc23d92f72e410a54d broke relative host path resolution by deleting os.chdir(). After this commit current working directory is not relevant anymore. Fixes e03d675b9bcd92864fd1aedc23d92f72e410a54d. Signed-off-by: Monika Kairaityte --- podman_compose.py | 1 + .../selinux/test_podman_compose_selinux.py | 10 ++- tests/unit/test_container_to_args.py | 78 ++++++++++++++++++- 3 files changed, 81 insertions(+), 8 deletions(-) diff --git a/podman_compose.py b/podman_compose.py index a54080f..6f8e28d 100755 --- a/podman_compose.py +++ b/podman_compose.py @@ -421,6 +421,7 @@ async def assert_volume(compose: PodmanCompose, mount_dict: dict[str, Any]) -> N os.makedirs(mount_src, exist_ok=True) except OSError: pass + mount_dict["source"] = mount_src return if mount_dict["type"] != "volume" or not vol or not vol.get("name"): return diff --git a/tests/integration/selinux/test_podman_compose_selinux.py b/tests/integration/selinux/test_podman_compose_selinux.py index b88f0af..9be52f1 100644 --- a/tests/integration/selinux/test_podman_compose_selinux.py +++ b/tests/integration/selinux/test_podman_compose_selinux.py @@ -36,8 +36,9 @@ class TestPodmanCompose(unittest.TestCase, RunSubprocessMixin): "selinux_container1_1", ]) inspect_out = json.loads(out) - create_command_list = inspect_out[0].get("Config", []).get("CreateCommand", {}) - self.assertIn('./host_test_text.txt:/test_text.txt:z', create_command_list) + create_command_list = inspect_out[0].get("Config", []).get("CreateCommand", []) + host_path = os.path.join(test_path(), "selinux", "host_test_text.txt") + self.assertIn(f'{host_path}:/test_text.txt:z', create_command_list) out, _ = self.run_subprocess_assert_returncode([ "podman", @@ -45,8 +46,9 @@ class TestPodmanCompose(unittest.TestCase, RunSubprocessMixin): "selinux_container2_1", ]) inspect_out = json.loads(out) - create_command_list = inspect_out[0].get("Config", []).get("CreateCommand", {}) - self.assertIn('./host_test_text.txt:/test_text.txt', create_command_list) + create_command_list = inspect_out[0].get("Config", []).get("CreateCommand", []) + host_path = os.path.join(test_path(), "selinux", "host_test_text.txt") + self.assertIn(f'{host_path}:/test_text.txt', create_command_list) finally: out, _ = self.run_subprocess_assert_returncode([ podman_compose_path(), diff --git a/tests/unit/test_container_to_args.py b/tests/unit/test_container_to_args.py index 62343ac..0825b9b 100644 --- a/tests/unit/test_container_to_args.py +++ b/tests/unit/test_container_to_args.py @@ -531,10 +531,24 @@ class TestContainerToArgs(unittest.IsolatedAsyncioTestCase): ) @parameterized.expand([ - (False, "z", ["--mount", "type=bind,source=./foo,destination=/mnt,z"]), - (False, "Z", ["--mount", "type=bind,source=./foo,destination=/mnt,Z"]), - (True, "z", ["-v", "./foo:/mnt:z"]), - (True, "Z", ["-v", "./foo:/mnt:Z"]), + ( + False, + "z", + [ + "--mount", + f"type=bind,source={get_test_file_path('test_dirname/foo')},destination=/mnt,z", + ], + ), + ( + False, + "Z", + [ + "--mount", + f"type=bind,source={get_test_file_path('test_dirname/foo')},destination=/mnt,Z", + ], + ), + (True, "z", ["-v", f"{get_test_file_path('test_dirname/foo')}:/mnt:z"]), + (True, "Z", ["-v", f"{get_test_file_path('test_dirname/foo')}:/mnt:Z"]), ]) async def test_selinux_volume( self, prefer_volume: bool, selinux_type: str, expected_additional_args: list @@ -571,6 +585,62 @@ class TestContainerToArgs(unittest.IsolatedAsyncioTestCase): ], ) + @parameterized.expand([ + ( + "absolute_path", + get_test_file_path('test_dirname/foo'), + [ + "--mount", + f"type=bind,source={get_test_file_path('test_dirname/foo')},destination=/mnt", + ], + ), + ( + "relative_path", + './foo', + [ + "--mount", + f"type=bind,source={get_test_file_path('test_dirname/foo')},destination=/mnt", + ], + ), + ( + "home_dir", + '~/test_dirname/foo', + [ + "--mount", + f"type=bind,source={os.path.expanduser('~/test_dirname/foo')},destination=/mnt", + ], + ), + ]) + async def test_volumes_bind_mount_source( + self, test_name: str, mount_source: str, expected_additional_args: list + ) -> None: + c = create_compose_mock() + cnt = get_minimal_container() + + # This is supposed to happen during `_parse_compose_file` + # but that is probably getting skipped during testing + cnt["_service"] = cnt["service_name"] + + cnt["volumes"] = [ + { + "type": "bind", + "source": f"{mount_source}", + "target": "/mnt", + } + ] + + args = await container_to_args(c, cnt) + self.assertEqual( + args, + [ + "--name=project_name_service_name1", + "-d", + *expected_additional_args, + "--network=bridge:alias=service_name", + "busybox", + ], + ) + @parameterized.expand([ ("not_compat", False, "test_project_name", "test_project_name_network1"), ("compat_no_dash", True, "test_project_name", "test_project_name_network1"),