diff --git a/docs/Extensions.md b/docs/Extensions.md index d99467a5..0d064e1b 100644 --- a/docs/Extensions.md +++ b/docs/Extensions.md @@ -12,7 +12,8 @@ The following extension keys are available under container configuration: * `x-podman.gidmaps` - Run the container in a new user namespace using the supplied GID mapping. * `x-podman.rootfs` - Run the container without requiring any image management; the rootfs of the -container is assumed to be managed externally. + +* `x-podman.no_hosts` - Run the container without creating /etc/hosts file For example, the following docker-compose.yml allows running a podman container with externally managed rootfs. ```yml diff --git a/newsfragments/container-no-hosts.feature b/newsfragments/container-no-hosts.feature new file mode 100644 index 00000000..27125fb3 --- /dev/null +++ b/newsfragments/container-no-hosts.feature @@ -0,0 +1 @@ +Add x-podman.no_hosts setting to pass --no-hosts to podman run diff --git a/podman_compose.py b/podman_compose.py index 6b974f54..07fc882f 100755 --- a/podman_compose.py +++ b/podman_compose.py @@ -1254,6 +1254,8 @@ async def container_to_args(compose, cnt, detached=True): podman_args.extend(["--uidmap", uidmap]) for gidmap in cnt.get('x-podman.gidmaps', []): podman_args.extend(["--gidmap", gidmap]) + if cnt.get("x-podman.no_hosts", False): + podman_args.extend(["--no-hosts"]) rootfs = cnt.get('x-podman.rootfs', None) if rootfs is not None: rootfs_mode = True diff --git a/tests/unit/test_container_to_args.py b/tests/unit/test_container_to_args.py index bd0fbdc2..b4f9fb91 100644 --- a/tests/unit/test_container_to_args.py +++ b/tests/unit/test_container_to_args.py @@ -180,7 +180,7 @@ async def test_uidmaps_extension_old_path(self): c = create_compose_mock() cnt = get_minimal_container() - cnt['x-podman'] = {'uidmaps': ['1000:1000:1']} + cnt["x-podman"] = {"uidmaps": ["1000:1000:1"]} with self.assertRaises(ValueError): await container_to_args(c, cnt) @@ -189,7 +189,7 @@ async def test_uidmaps_extension(self): c = create_compose_mock() cnt = get_minimal_container() - cnt['x-podman.uidmaps'] = ['1000:1000:1', '1001:1001:2'] + cnt["x-podman.uidmaps"] = ["1000:1000:1", "1001:1001:2"] args = await container_to_args(c, cnt) self.assertEqual( @@ -199,10 +199,10 @@ async def test_uidmaps_extension(self): "-d", "--network=bridge", "--network-alias=service_name", - '--uidmap', - '1000:1000:1', - '--uidmap', - '1001:1001:2', + "--uidmap", + "1000:1000:1", + "--uidmap", + "1001:1001:2", "busybox", ], ) @@ -211,7 +211,7 @@ async def test_gidmaps_extension(self): c = create_compose_mock() cnt = get_minimal_container() - cnt['x-podman.gidmaps'] = ['1000:1000:1', '1001:1001:2'] + cnt["x-podman.gidmaps"] = ["1000:1000:1", "1001:1001:2"] args = await container_to_args(c, cnt) self.assertEqual( @@ -221,10 +221,10 @@ async def test_gidmaps_extension(self): "-d", "--network=bridge", "--network-alias=service_name", - '--gidmap', - '1000:1000:1', - '--gidmap', - '1001:1001:2', + "--gidmap", + "1000:1000:1", + "--gidmap", + "1001:1001:2", "busybox", ], ) @@ -249,12 +249,33 @@ async def test_rootfs_extension(self): ], ) + async def test_no_hosts_extension(self): + c = create_compose_mock() + + cnt = get_minimal_container() + cnt["x-podman.no_hosts"] = True + + args = await container_to_args(c, cnt) + self.assertEqual( + args, + [ + "--name=project_name_service_name1", + "-d", + "--network=bridge", + "--network-alias=service_name", + "--no-hosts", + "busybox", + ], + ) + async def test_env_file_str(self): c = create_compose_mock() cnt = get_minimal_container() - env_file = get_test_file_path('tests/integration/env-file-tests/env-files/project-1.env') - cnt['env_file'] = env_file + env_file = get_test_file_path( + "tests/integration/env-file-tests/env-files/project-1.env" + ) + cnt["env_file"] = env_file args = await container_to_args(c, cnt) self.assertEqual( @@ -278,7 +299,7 @@ async def test_env_file_str_not_exists(self): c = create_compose_mock() cnt = get_minimal_container() - cnt['env_file'] = 'notexists' + cnt["env_file"] = "notexists" with self.assertRaises(ValueError): await container_to_args(c, cnt) @@ -287,8 +308,10 @@ async def test_env_file_str_array_one_path(self): c = create_compose_mock() cnt = get_minimal_container() - env_file = get_test_file_path('tests/integration/env-file-tests/env-files/project-1.env') - cnt['env_file'] = [env_file] + env_file = get_test_file_path( + "tests/integration/env-file-tests/env-files/project-1.env" + ) + cnt["env_file"] = [env_file] args = await container_to_args(c, cnt) self.assertEqual( @@ -312,9 +335,13 @@ async def test_env_file_str_array_two_paths(self): c = create_compose_mock() cnt = get_minimal_container() - env_file = get_test_file_path('tests/integration/env-file-tests/env-files/project-1.env') - env_file_2 = get_test_file_path('tests/integration/env-file-tests/env-files/project-2.env') - cnt['env_file'] = [env_file, env_file_2] + env_file = get_test_file_path( + "tests/integration/env-file-tests/env-files/project-1.env" + ) + env_file_2 = get_test_file_path( + "tests/integration/env-file-tests/env-files/project-2.env" + ) + cnt["env_file"] = [env_file, env_file_2] args = await container_to_args(c, cnt) self.assertEqual( @@ -342,8 +369,10 @@ async def test_env_file_obj_required(self): c = create_compose_mock() cnt = get_minimal_container() - env_file = get_test_file_path('tests/integration/env-file-tests/env-files/project-1.env') - cnt['env_file'] = {'path': env_file, 'required': True} + env_file = get_test_file_path( + "tests/integration/env-file-tests/env-files/project-1.env" + ) + cnt["env_file"] = {"path": env_file, "required": True} args = await container_to_args(c, cnt) self.assertEqual( @@ -367,7 +396,7 @@ async def test_env_file_obj_required_non_existent_path(self): c = create_compose_mock() cnt = get_minimal_container() - cnt['env_file'] = {'path': 'not-exists', 'required': True} + cnt["env_file"] = {"path": "not-exists", "required": True} with self.assertRaises(ValueError): await container_to_args(c, cnt) @@ -376,7 +405,7 @@ async def test_env_file_obj_optional(self): c = create_compose_mock() cnt = get_minimal_container() - cnt['env_file'] = {'path': 'not-exists', 'required': False} + cnt["env_file"] = {"path": "not-exists", "required": False} args = await container_to_args(c, cnt) self.assertEqual( @@ -528,13 +557,17 @@ async def test_gpu_device_ids_specific(self): ], ) - @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"]), - ]) - async def test_selinux_volume(self, prefer_volume, selinux_type, expected_additional_args): + @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"]), + ] + ) + async def test_selinux_volume( + self, prefer_volume, selinux_type, expected_additional_args + ): c = create_compose_mock() c.prefer_volume_over_mount = prefer_volume @@ -568,18 +601,22 @@ async def test_selinux_volume(self, prefer_volume, selinux_type, expected_additi ], ) - @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): + @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) c.x_podman = {"default_net_name_compat": is_compat} - c.networks = {'network1': {}} + c.networks = {"network1": {}} cnt = get_minimal_container() - cnt['networks'] = ['network1'] + cnt["networks"] = ["network1"] args = await container_to_args(c, cnt) self.assertEqual(