Skip to content

Commit 8f55227

Browse files
committed
add name_separator_compat
Signed-off-by: Uosis <[email protected]>
1 parent 9cde399 commit 8f55227

File tree

7 files changed

+109
-9
lines changed

7 files changed

+109
-9
lines changed

docs/Extensions.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,26 @@ The options to the network modes are passed to the `--network` option of the `po
139139
as-is.
140140

141141

142+
## Compatibility of name separators between docker-compose and podman-compose
143+
144+
Currently, podman-compose is using underscores (`_` character) as a separator in names of
145+
containers, images, etc., while docker-compose has switched to hyphens (`-` character). This setting
146+
allows to switch podman-compose to use hyphens as well.
147+
148+
To enable compatibility between docker-compose and podman-compose, specify
149+
`name_separator_compat: true` under global `x-podman` key:
150+
151+
```
152+
x-podman:
153+
name_separator_compat: true
154+
```
155+
156+
By default `name_separator_compat` is `false`. This will change to `true` at some point and the
157+
setting will be removed.
158+
159+
This setting can also be changed by setting `PODMAN_COMPOSE_NAME_SEPARATOR_COMPAT` environment
160+
variable.
161+
142162
## Compatibility of default network names between docker-compose and podman-compose
143163

144164
Current versions of podman-compose may produce different default external network names than
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Add new name_separator_compat x-podman setting to change name separator to hyphen, same as Docker Compose

podman_compose.py

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -223,11 +223,10 @@ def fix_mount_dict(
223223
# handle anonymous or implied volume
224224
if not source:
225225
# missing source
226-
vol["name"] = "_".join([
227-
compose.project_name,
226+
vol["name"] = compose.format_name(
228227
srv_name,
229228
hashlib.sha256(mount_dict["target"].encode("utf-8")).hexdigest(),
230-
])
229+
)
231230
elif not name:
232231
external = vol.get("external")
233232
if isinstance(external, dict):
@@ -374,9 +373,8 @@ def default_network_name_for_project(compose: PodmanCompose, net: str, is_ext: A
374373
PodmanCompose.XPodmanSettingKey.DEFAULT_NET_NAME_COMPAT, False
375374
)
376375
if default_net_name_compat is True:
377-
return f"{compose.project_name.replace('-', '')}_{net}"
378-
return f"{compose.project_name}_{net}"
379-
376+
return compose.join_name_parts(compose.project_name.replace('-', ''), net)
377+
return compose.format_name(net)
380378

381379
# def tr_identity(project_name, given_containers):
382380
# pod_name = f'pod_{project_name}'
@@ -1973,6 +1971,7 @@ class PodmanCompose:
19731971
class XPodmanSettingKey(Enum):
19741972
DEFAULT_NET_NAME_COMPAT = "default_net_name_compat"
19751973
DEFAULT_NET_BEHAVIOR_COMPAT = "default_net_behavior_compat"
1974+
NAME_SEPARATOR_COMPAT = "name_separator_compat"
19761975
IN_POD = "in_pod"
19771976
POD_ARGS = "pod_args"
19781977

@@ -2082,6 +2081,17 @@ def resolve_pod_args(self) -> list[str]:
20822081
PodmanCompose.XPodmanSettingKey.POD_ARGS, ["--infra=false", "--share="]
20832082
)
20842083

2084+
def join_name_parts(self, *parts: str) -> str:
2085+
if self.x_podman.get(PodmanCompose.XPodmanSettingKey.NAME_SEPARATOR_COMPAT, False):
2086+
sep = "-"
2087+
else:
2088+
sep = "_"
2089+
2090+
return sep.join(parts)
2091+
2092+
def format_name(self, *parts: str) -> str:
2093+
return self.join_name_parts(self.project_name, *parts)
2094+
20852095
def _parse_x_podman_settings(self, compose: dict[str, Any], environ: dict[str, str]) -> None:
20862096
known_keys = {s.value: s for s in PodmanCompose.XPodmanSettingKey}
20872097

@@ -2352,7 +2362,7 @@ def _parse_compose_file(self) -> None:
23522362

23532363
container_names_by_service[service_name] = []
23542364
for num in range(1, replicas + 1):
2355-
name0 = f"{project_name}_{service_name}_{num}"
2365+
name0 = self.format_name(service_name, str(num))
23562366
if num == 1:
23572367
name = service_desc.get("container_name", name0)
23582368
else:
@@ -2368,7 +2378,7 @@ def _parse_compose_file(self) -> None:
23682378
x_podman = service_desc.get("x-podman")
23692379
rootfs_mode = x_podman is not None and x_podman.get("rootfs") is not None
23702380
if "image" not in cnt and not rootfs_mode:
2371-
cnt["image"] = f"{project_name}_{service_name}"
2381+
cnt["image"] = self.format_name(service_name)
23722382
labels = norm_as_list(cnt.get("labels"))
23732383
cnt["ports"] = norm_ports(cnt.get("ports"))
23742384
labels.extend(podman_compose_labels)
@@ -3363,7 +3373,7 @@ def compose_run_update_container_from_args(
33633373
compose: PodmanCompose, cnt: dict, args: argparse.Namespace
33643374
) -> None:
33653375
# adjust one-off container options
3366-
name0 = "{}_{}_tmp{}".format(compose.project_name, args.service, random.randrange(0, 65536))
3376+
name0 = compose.format_name(args.service, str(random.randrange(0, 65536)))
33673377
cnt["name"] = args.name or name0
33683378
if args.entrypoint:
33693379
cnt["entrypoint"] = args.entrypoint
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
services:
2+
web:
3+
image: busybox
4+
command: httpd -f -p 8123 -h /tmp/
5+
6+
x-podman:
7+
name_separator_compat: true
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
services:
2+
web:
3+
image: busybox
4+
command: httpd -f -p 8123 -h /tmp/
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
3+
import os
4+
import unittest
5+
6+
from parameterized import parameterized
7+
8+
from tests.integration.test_utils import RunSubprocessMixin
9+
from tests.integration.test_utils import podman_compose_path
10+
from tests.integration.test_utils import test_path
11+
12+
13+
class TestComposeNameSeparatorCompat(unittest.TestCase, RunSubprocessMixin):
14+
@parameterized.expand([
15+
('default', { }, '_'),
16+
('default', { 'PODMAN_COMPOSE_NAME_SEPARATOR_COMPAT': '1' }, '-'),
17+
('compat', { }, '-'),
18+
('compat', { 'PODMAN_COMPOSE_NAME_SEPARATOR_COMPAT': '1' }, '-'),
19+
('compat', { 'PODMAN_COMPOSE_NAME_SEPARATOR_COMPAT': '0' }, '_'),
20+
])
21+
def test_container_name(self, file: str, env: dict[str, str], expected_sep: str) -> None:
22+
compose_yaml_path = os.path.join(
23+
test_path(),
24+
"name_separator_compat",
25+
f"docker-compose_{file}.yaml")
26+
27+
try:
28+
self.run_subprocess_assert_returncode(
29+
[podman_compose_path(), "-f", compose_yaml_path, "up", "-d"],
30+
env=env,
31+
)
32+
33+
container_name_out, _ = self.run_subprocess_assert_returncode(
34+
[
35+
podman_compose_path(),
36+
"-f",
37+
compose_yaml_path,
38+
"ps",
39+
"--format",
40+
'{{.Names}}',
41+
],
42+
env=env,
43+
)
44+
container_name = container_name_out.decode('utf-8').strip()
45+
46+
expected_container_name = f'name_separator_compat{expected_sep}web{expected_sep}1'
47+
48+
self.assertEqual(container_name, expected_container_name)
49+
finally:
50+
self.run_subprocess_assert_returncode([
51+
podman_compose_path(),
52+
"-f",
53+
compose_yaml_path,
54+
"down",
55+
"-t",
56+
"0",
57+
], env=env)

0 commit comments

Comments
 (0)