diff --git a/docs/Extensions.md b/docs/Extensions.md index 3244f5f3..0808d7d5 100644 --- a/docs/Extensions.md +++ b/docs/Extensions.md @@ -91,6 +91,23 @@ The options to the network modes are passed to the `--network` option of the `po as-is. +## Compatibility of default network names between docker-compose and podman-compose + +Current versions of podman-compose may produce different default external network names than +docker-compose under certain conditions. Specifically, docker-compose removes dashes (`-` character) +from project name. + +To enable compatibility between docker-compose and podman-compose, specify +`default_net_name_compat: true` under global `x-podman` key: + +``` +x-podman: + default_net_name_compat: true +``` + +By default `default_net_name_compat` is `false`. This will change to `true` at some point and the +setting will be removed. + ## Custom pods management Podman-compose can have containers in pods. This can be controlled by extension key x-podman in_pod. diff --git a/newsfragments/default_net_name_compat.feature b/newsfragments/default_net_name_compat.feature new file mode 100644 index 00000000..d64d5277 --- /dev/null +++ b/newsfragments/default_net_name_compat.feature @@ -0,0 +1 @@ +Added a way to get compatibility of default network names with docker compose. This is selected by setting `default_net_name_compat: true` on `x-podman` global dictionary. diff --git a/podman_compose.py b/podman_compose.py index 04d02afd..9c6bd3e4 100755 --- a/podman_compose.py +++ b/podman_compose.py @@ -336,9 +336,21 @@ def norm_ulimit(inner_value): return inner_value -def default_network_name_for_project(proj_name, net, is_ext): - # docker-compose removes dashes from project name when building network name - return net if is_ext else f"{proj_name}_{net}" +def get_global_x_podman_value(compose, key, default_value=None): + extension_dict = compose.get("x-podman", None) + if extension_dict is None: + return default_value + return extension_dict.get("default_net_name_compat", default_value) + + +def default_network_name_for_project(compose, proj_name, net, is_ext): + if is_ext: + return net + + default_net_name_compat = get_global_x_podman_value(compose, "default_net_name_compat", False) + if default_net_name_compat is True: + return f"{proj_name.replace('-', '')}_{net}" + return f"{proj_name}_{net}" # def tr_identity(project_name, given_containers): @@ -850,7 +862,7 @@ async def assert_cnt_nets(compose, cnt): net_desc = nets[net] or {} is_ext = net_desc.get("external", None) ext_desc = is_ext if is_dict(is_ext) else {} - default_net_name = default_network_name_for_project(proj_name, net, is_ext) + default_net_name = default_network_name_for_project(compose, proj_name, net, is_ext) net_name = ext_desc.get("name", None) or net_desc.get("name", None) or default_net_name try: await compose.podman.output([], "network", ["exists", net_name]) @@ -939,7 +951,7 @@ def get_net_args(compose, cnt): net_desc = nets[net] or {} is_ext = net_desc.get("external", None) ext_desc = is_ext if is_dict(is_ext) else {} - default_net_name = default_network_name_for_project(proj_name, net, is_ext) + default_net_name = default_network_name_for_project(compose, proj_name, net, is_ext) net_name = ext_desc.get("name", None) or net_desc.get("name", None) or default_net_name net_names.append(net_name) net_names_str = ",".join(net_names) @@ -975,7 +987,7 @@ def get_net_args(compose, cnt): net_desc = nets[net_] or {} is_ext = net_desc.get("external", None) ext_desc = is_ext if is_dict(is_ext) else {} - default_net_name = default_network_name_for_project(proj_name, net_, is_ext) + default_net_name = default_network_name_for_project(compose, proj_name, net_, is_ext) net_name = ext_desc.get("name", None) or net_desc.get("name", None) or default_net_name ipv4 = net_config_.get("ipv4_address", None) @@ -1747,13 +1759,7 @@ async def run(self): def resolve_in_pod(self, compose): if self.global_args.in_pod_bool is None: - extension_dict = compose.get("x-podman", None) - if extension_dict is not None: - in_pod_value = extension_dict.get("in_pod", None) - if in_pod_value is not None: - self.global_args.in_pod_bool = in_pod_value - else: - self.global_args.in_pod_bool = True + self.global_args.in_pod_bool = get_global_x_podman_value(compose, "in_pod", True) # otherwise use `in_pod` value provided by command line return self.global_args.in_pod_bool diff --git a/tests/unit/test_container_to_args.py b/tests/unit/test_container_to_args.py index 5294ae1c..fd34b99b 100644 --- a/tests/unit/test_container_to_args.py +++ b/tests/unit/test_container_to_args.py @@ -9,7 +9,7 @@ from podman_compose import container_to_args -def create_compose_mock(project_name="test_project_name"): +def create_compose_mock(project_name="test_project_name", extra_args=None): compose = mock.Mock() compose.project_name = project_name compose.dirname = "test_dirname" @@ -17,6 +17,15 @@ def create_compose_mock(project_name="test_project_name"): compose.prefer_volume_over_mount = False compose.default_net = None compose.networks = {} + + if extra_args is None: + extra_args = {} + compose.get = mock.Mock(side_effect=lambda key, default: extra_args.get(key, default)) + + async def podman_output(*args, **kwargs): + pass + + compose.podman.output = mock.Mock(side_effect=podman_output) return compose @@ -561,3 +570,27 @@ async def test_selinux_volume(self, prefer_volume, selinux_type, expected_additi "busybox", ], ) + + @parameterized.expand([ + ("not_compat", False, "test_project_name", "test_project_name_network1"), + ("compat_no_dash", True, "test_project_name", "test_project_name_network1"), + ("compat_dash", True, "test_project-name", "test_projectname_network1"), + ]) + async def test_network_default_name(self, name, is_compat, project_name, expected_network_name): + c = create_compose_mock(project_name, {"x-podman": {"default_net_name_compat": is_compat}}) + c.networks = {'network1': {}} + + cnt = get_minimal_container() + cnt['networks'] = ['network1'] + + args = await container_to_args(c, cnt) + self.assertEqual( + args, + [ + "--name=project_name_service_name1", + "-d", + f"--network={expected_network_name}", + "--network-alias=service_name", + "busybox", + ], + )