From da46ee391080036200c922c4331e3001afb95cc1 Mon Sep 17 00:00:00 2001 From: Frank Stettner Date: Fri, 4 Apr 2025 20:04:14 +0200 Subject: [PATCH 1/2] Fix port command for dynamic host ports Use `podman inspect` to get the actual host ports rather echoing the defined ports from the compose yml. Fixes #778 and #1039 Signed-off-by: Frank Stettner --- newsfragments/1039-fix-port-command.bugfix | 1 + podman_compose.py | 28 ++++------------------ 2 files changed, 6 insertions(+), 23 deletions(-) create mode 100644 newsfragments/1039-fix-port-command.bugfix diff --git a/newsfragments/1039-fix-port-command.bugfix b/newsfragments/1039-fix-port-command.bugfix new file mode 100644 index 0000000..70bbe64 --- /dev/null +++ b/newsfragments/1039-fix-port-command.bugfix @@ -0,0 +1 @@ +- Fix the port command for dynamic host ports. diff --git a/podman_compose.py b/podman_compose.py index b206d7f..224f98e 100755 --- a/podman_compose.py +++ b/podman_compose.py @@ -15,7 +15,6 @@ import asyncio.subprocess import getpass import glob import hashlib -import itertools import json import logging import os @@ -3186,30 +3185,13 @@ async def compose_config(compose, args): @cmd_run(podman_compose, "port", "Prints the public port for a port binding.") async def compose_port(compose, args): - # TODO - deal with pod index compose.assert_services(args.service) containers = compose.container_names_by_service[args.service] - container_ports = list( - itertools.chain(*(compose.container_by_name[c]["ports"] for c in containers)) - ) - - def _published_target(port_string): - published, target = port_string.split(":")[-2:] - return int(published), int(target) - - select_udp = args.protocol == "udp" - published, target = None, None - for p in container_ports: - is_udp = p[-4:] == "/udp" - - if select_udp and is_udp: - published, target = _published_target(p[-4:]) - if not select_udp and not is_udp: - published, target = _published_target(p) - - if target == args.private_port: - print(published) - return + output = await compose.podman.output([], "inspect", [containers[args.index - 1]]) + inspect_json = json.loads(output.decode("utf-8")) + private_port = str(args.private_port) + "/" + args.protocol + host_port = inspect_json[0]["NetworkSettings"]["Ports"][private_port][0]["HostPort"] + print(host_port) @cmd_run(podman_compose, "pause", "Pause all running containers") From ae41ef08c3556a93f845803b3b10ec3ef2370d0b Mon Sep 17 00:00:00 2001 From: Frank Stettner Date: Fri, 4 Apr 2025 20:10:07 +0200 Subject: [PATCH 2/2] tests/integration: Improve tests for port command Refs #778 and #1039 Signed-off-by: Frank Stettner --- tests/integration/ports/docker-compose.yml | 59 +++++++------- tests/integration/ports/test1.txt | 1 - tests/integration/ports/test2.txt | 1 - .../ports/test_podman_compose_ports.py | 81 +++++++++---------- 4 files changed, 64 insertions(+), 78 deletions(-) delete mode 100644 tests/integration/ports/test1.txt delete mode 100644 tests/integration/ports/test2.txt diff --git a/tests/integration/ports/docker-compose.yml b/tests/integration/ports/docker-compose.yml index e89bd05..71a33b0 100644 --- a/tests/integration/ports/docker-compose.yml +++ b/tests/integration/ports/docker-compose.yml @@ -1,35 +1,30 @@ version: "3" services: - web1: - image: nopush/podman-compose-test - hostname: web1 - command: ["dumb-init", "/bin/busybox", "httpd", "-f", "-h", "/var/www/html", "-p", "8001"] - working_dir: /var/www/html - ports: - - 8001:8001 - volumes: - - ./test1.txt:/var/www/html/index.txt:ro,z - web2: - image: nopush/podman-compose-test - hostname: web2 - command: ["dumb-init", "/bin/busybox", "httpd", "-f", "-h", "/var/www/html", "-p", "8002"] - working_dir: /var/www/html - ports: - - 8002:8002 - - target: 8003 - host_ip: 127.0.0.1 - published: 8003 - protocol: udp - - target: 8004 - host_ip: 127.0.0.1 - published: 8004 - protocol: tcp - - target: 8005 - published: 8005 - - target: 8006 - protocol: udp - - target: 8007 - host_ip: 127.0.0.1 - volumes: - - ./test2.txt:/var/www/html/index.txt:ro,z + web1: + image: nopush/podman-compose-test + hostname: web1 + command: ["dumb-init", "sleep", "infinity"] + ports: + - 8000:8000 + - 8001 + web2: + image: nopush/podman-compose-test + hostname: web2 + command: ["dumb-init", "sleep", "infinity"] + ports: + - 8002:8002 + - target: 8003 + host_ip: 127.0.0.1 + published: 8003 + protocol: udp + - target: 8004 + host_ip: 127.0.0.1 + published: 8004 + protocol: tcp + - target: 8005 + published: 8005 + - target: 8006 + protocol: udp + - target: 8007 + host_ip: 127.0.0.1 diff --git a/tests/integration/ports/test1.txt b/tests/integration/ports/test1.txt deleted file mode 100644 index a5bce3f..0000000 --- a/tests/integration/ports/test1.txt +++ /dev/null @@ -1 +0,0 @@ -test1 diff --git a/tests/integration/ports/test2.txt b/tests/integration/ports/test2.txt deleted file mode 100644 index 180cf83..0000000 --- a/tests/integration/ports/test2.txt +++ /dev/null @@ -1 +0,0 @@ -test2 diff --git a/tests/integration/ports/test_podman_compose_ports.py b/tests/integration/ports/test_podman_compose_ports.py index aa0b13e..3aa630d 100644 --- a/tests/integration/ports/test_podman_compose_ports.py +++ b/tests/integration/ports/test_podman_compose_ports.py @@ -1,12 +1,11 @@ # SPDX-License-Identifier: GPL-2.0 """ -test_podman_compose_up_down.py +test_podman_compose_ports.py -Tests the podman compose up and down commands used to create and remove services. +Tests the podman compose port command used to show the host port. """ -# pylint: disable=redefined-outer-name import os import unittest @@ -35,51 +34,45 @@ class TestPodmanCompose(unittest.TestCase, RunSubprocessMixin): "-f", os.path.join(test_path(), "ports", "docker-compose.yml"), "down", - "--volumes", ] + port_cmd = [ + podman_compose_path(), + "-f", + os.path.join(test_path(), "ports", "docker-compose.yml"), + "port", + ] + + udp_arg = ["--protocol", "udp"] + + tcp_arg = ["--protocol", "tcp"] + try: self.run_subprocess_assert_returncode(up_cmd) + port = self.run_subprocess_assert_returncode(port_cmd + ["web1", "8000"]) + self.assertEqual(port[0].decode().strip(), "8000") + + port = self.run_subprocess_assert_returncode(port_cmd + ["web1", "8001"]) + self.assertNotEqual(port[0].decode().strip(), "8001") + + port = self.run_subprocess_assert_returncode(port_cmd + ["web2", "8002"]) + self.assertEqual(port[0].decode().strip(), "8002") + + port = self.run_subprocess_assert_returncode(port_cmd + udp_arg + ["web2", "8003"]) + self.assertEqual(port[0].decode().strip(), "8003") + + port = self.run_subprocess_assert_returncode(port_cmd + ["web2", "8004"]) + self.assertEqual(port[0].decode().strip(), "8004") + + port = self.run_subprocess_assert_returncode(port_cmd + tcp_arg + ["web2", "8005"]) + self.assertEqual(port[0].decode().strip(), "8005") + + port = self.run_subprocess_assert_returncode(port_cmd + udp_arg + ["web2", "8006"]) + self.assertNotEqual(port[0].decode().strip(), "8006") + + port = self.run_subprocess_assert_returncode(port_cmd + ["web2", "8007"]) + self.assertNotEqual(port[0].decode().strip(), "8007") + finally: self.run_subprocess_assert_returncode(down_cmd) - - def test_down_with_orphans(self): - container_id, _ = self.run_subprocess_assert_returncode([ - "podman", - "run", - "--rm", - "-d", - "nopush/podman-compose-test", - "dumb-init", - "/bin/busybox", - "httpd", - "-f", - "-h", - "/etc/", - "-p", - "8000", - ]) - - down_cmd = [ - "coverage", - "run", - podman_compose_path(), - "-f", - os.path.join(test_path(), "ports", "docker-compose.yml"), - "down", - "--volumes", - "--remove-orphans", - ] - - self.run_subprocess_assert_returncode(down_cmd) - - self.run_subprocess_assert_returncode( - [ - "podman", - "container", - "exists", - container_id.decode("utf-8"), - ], - 1, - )