Skip to content

Commit

Permalink
Merge pull request containers#180 from moham-jem/bugfix/allow_bind_mu…
Browse files Browse the repository at this point in the history
…ltiple_host_ports_to_a_single_container

Bugfix/allow bind multiple host ports to a single container
  • Loading branch information
openshift-ci[bot] authored Jun 22, 2022
2 parents 1998169 + 475e54f commit 09617be
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 6 deletions.
24 changes: 18 additions & 6 deletions podman/domain/containers_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,9 @@ def create(
For example: {'2222/tcp': None}.
- A tuple of (address, port) if you want to specify the host interface.
For example: {'1111/tcp': ('127.0.0.1', 1111)}.
- A list of integers, if you want to bind multiple host ports to a single container
port.
For example: {'1111/tcp': [1234, 4567]}.
- A list of integers or tuples of (address, port), if you want to bind
multiple host ports to a single container port.
For example: {'1111/tcp': [1234, ("127.0.0.1", 4567)]}.
For example: {'9090': 7878, '10932/tcp': '8781',
"8989/tcp": ("127.0.0.1", 9091)}
Expand Down Expand Up @@ -489,9 +489,21 @@ def to_bytes(size: Union[int, str, None]) -> Union[int, None]:
port_map["host_ip"] = host[0]
port_map["host_port"] = int(host[1])
elif isinstance(host, list):
raise ValueError(
"Podman API does not support multiple port bound to a single host port."
)
for host_list in host:
port_map = {"container_port": int(container_port), "protocol": protocol}
if (
isinstance(host_list, int)
or isinstance(host_list, str)
and host_list.isdigit()
):
port_map["host_port"] = int(host_list)
elif isinstance(host_list, tuple):
port_map["host_ip"] = host_list[0]
port_map["host_port"] = int(host_list[1])
else:
raise ValueError(f"'ports' value of '{host_list}' is not supported.")
params["portmappings"].append(port_map)
continue
else:
raise ValueError(f"'ports' value of '{host}' is not supported.")

Expand Down
47 changes: 47 additions & 0 deletions podman/tests/integration/test_container_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,53 @@ def _test_memory_limit(self, parameter_name, host_config_name, set_mem_limit=Fal
test['expected_value'],
)

def test_container_ports(self):
"""Test ports binding"""
port_tests = {
'97/tcp': '43',
'2/udp': ('127.0.0.1', '939'),
'11123/tcp': [[('127.0.0.1', '11123'), ('127.0.0.1', '112')], ['1123', '159']],
}
for container_port, host_port in port_tests.items():
if isinstance(host_port, str) or isinstance(host_port, tuple):
self._test_container_ports(container_port, host_port)
else:
for port_option in host_port:
self._test_container_ports(container_port, port_option)

def _test_container_ports(self, container_port, host_port):
""" "Base for tests to check port binding is configured correctly"""

def __get_expected_value(container_p, host_p):
"""Generate the expected value based on the input"""
if isinstance(host_p, str):
return {container_p: [{'HostIp': '', 'HostPort': host_p}]}
elif isinstance(host_p, tuple):
return {container_p: [{'HostIp': host_p[0], 'HostPort': host_p[1]}]}
else:
host_ports = []
for host_port in host_p:
if isinstance(host_port, tuple):
host_ports.append({'HostIp': host_port[0], 'HostPort': host_port[1]})
elif isinstance(host_port, str):
host_ports.append({'HostIp': '', 'HostPort': host_port})
return {container_p: host_ports}

expected_value = __get_expected_value(container_port, host_port)
container = self.client.containers.create(
self.alpine_image, ports={container_port: host_port}
)
self.containers.append(container)

self.assertTrue(
all(
[
x in expected_value
for x in container.attrs.get('HostConfig', dict()).get('PortBindings')
]
)
)

def test_container_mem_limit(self):
"""Test passing memory limit"""
self._test_memory_limit('mem_limit', 'Memory')
Expand Down

0 comments on commit 09617be

Please sign in to comment.