From 62f1f36574059a501aaab28847f6b4083a83c1c1 Mon Sep 17 00:00:00 2001 From: fccagou Date: Sun, 19 Oct 2025 09:58:04 +0200 Subject: [PATCH 1/2] Add subpath support to volumes in `--mount` option To allow subpath mount as describes in [Compose Specs](https://github.com/compose-spec/compose-spec/blob/main/05-services.md), `refer_volume_over_mount` is changed from _True_ to **False** Compose entries exemple: - type: volume source: webservices target: /srv/www/vhosts/server1 read_only: true volume: subpath: server1 - type: volume source: webservices target: /srv/www/vhosts/server2 read_only: true volume: subpath: server2 - type: volume source: webservices target: /srv/www/vhosts/server2/uploads read_only: false volume: subpath: server2/uploads Runs podman with options --mount type=volume,source=webservices,target=/srv/www/vhosts/server1,ro --mount type=volume,source=webservices,target=/srv/www/vhosts/server2,ro,subpath=server2 --mount type=volume,source=webservices,target=/srv/www/vhosts/server2/uploads,subpath=server2/uploads Signed-off-by: fccagou --- podman_compose.py | 9 +++++++-- .../selinux/test_podman_compose_selinux.py | 19 +++++++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/podman_compose.py b/podman_compose.py index 46725ffd..fe374125 100755 --- a/podman_compose.py +++ b/podman_compose.py @@ -459,6 +459,7 @@ def mount_desc_to_mount_args(mount_desc: dict[str, Any]) -> str: vol = mount_desc.get("_vol") if mount_type == "volume" else None source = vol["name"] if vol else mount_desc.get("source") target = mount_desc["target"] + volume = mount_desc.get("volume") if mount_type == "volume" else None opts = [] if mount_desc.get(mount_type, None): # TODO: we might need to add mount_dict[mount_type]["propagation"] = "z" @@ -480,6 +481,11 @@ def mount_desc_to_mount_args(mount_desc: dict[str, Any]) -> str: selinux = bind_opts.get("selinux") if selinux is not None: opts.append(selinux) + else: + if volume is not None: + subpath = volume.get("subpath") + if subpath is not None: + opts.append(f"subpath={subpath}") opts_str = ",".join(opts) if mount_type == "bind": return f"type=bind,source={source},destination={target},{opts_str}".rstrip(",") @@ -1186,7 +1192,6 @@ async def container_to_args( podman_args.extend(["--tmpfs", i]) for volume in cnt.get("volumes", []): podman_args.extend(await get_mount_args(compose, cnt, volume)) - await assert_cnt_nets(compose, cnt) podman_args.extend(get_net_args(compose, cnt)) @@ -2064,7 +2069,7 @@ def __init__(self) -> None: self.container_by_name: dict[str, Any] self.services: dict[str, Any] self.all_services: set[Any] = set() - self.prefer_volume_over_mount = True + self.prefer_volume_over_mount = False self.x_podman: dict[PodmanCompose.XPodmanSettingKey, Any] = {} self.merged_yaml: Any self.yaml_hash = "" diff --git a/tests/integration/selinux/test_podman_compose_selinux.py b/tests/integration/selinux/test_podman_compose_selinux.py index 9be52f1b..acdc4331 100644 --- a/tests/integration/selinux/test_podman_compose_selinux.py +++ b/tests/integration/selinux/test_podman_compose_selinux.py @@ -38,7 +38,15 @@ def test_selinux(self) -> None: inspect_out = json.loads(out) 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) + try: + # podman-compose.py: prefer_volume_over_mount set to False + self.assertIn( + f'type=bind,source={host_path},destination=/test_text.txt,z', + create_command_list, + ) + except AssertionError: + # podman-compose.py: prefer_volume_over_mount set to True + self.assertIn(f'{host_path}:/test_text.txt:z', create_command_list) out, _ = self.run_subprocess_assert_returncode([ "podman", @@ -48,7 +56,14 @@ def test_selinux(self) -> None: inspect_out = json.loads(out) 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) + try: + # podman-compose.py: prefer_volume_over_mount set to False + self.assertIn( + f'type=bind,source={host_path},destination=/test_text.txt', create_command_list + ) + except AssertionError: + # podman-compose.py: prefer_volume_over_mount set to True + self.assertIn(f'{host_path}:/test_text.txt', create_command_list) finally: out, _ = self.run_subprocess_assert_returncode([ podman_compose_path(), From 3230e3c0ff567d1866bd727e99ea0d01d30f6646 Mon Sep 17 00:00:00 2001 From: fccagou Date: Mon, 20 Oct 2025 21:11:29 +0200 Subject: [PATCH 2/2] doc: add towncrier newsfragments file Signed-off-by: fccagou --- .../add-subpath-support-to-volumes-in---mount-option.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 newsfragments/add-subpath-support-to-volumes-in---mount-option.bugfix diff --git a/newsfragments/add-subpath-support-to-volumes-in---mount-option.bugfix b/newsfragments/add-subpath-support-to-volumes-in---mount-option.bugfix new file mode 100644 index 00000000..c1aa522b --- /dev/null +++ b/newsfragments/add-subpath-support-to-volumes-in---mount-option.bugfix @@ -0,0 +1 @@ +Implemented volume subpath mount option.