From 3935cce394e0827959356e8238f03c2d30880dfb Mon Sep 17 00:00:00 2001 From: Sharp Hall Date: Fri, 15 Jun 2018 12:36:20 -0400 Subject: [PATCH] docker: Allow publishing of ports with the same number but different protocol (#38412) * Don't deduplicate docker container ports with different protocols * Test _parse_exposed_ports --- .../modules/cloud/docker/docker_container.py | 13 ++++++++++--- test/units/modules/cloud/docker/__init__.py | 0 .../cloud/docker/test_docker_container.py | 19 +++++++++++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 test/units/modules/cloud/docker/__init__.py create mode 100644 test/units/modules/cloud/docker/test_docker_container.py diff --git a/lib/ansible/modules/cloud/docker/docker_container.py b/lib/ansible/modules/cloud/docker/docker_container.py index e40f136024a..441b093d4c3 100644 --- a/lib/ansible/modules/cloud/docker/docker_container.py +++ b/lib/ansible/modules/cloud/docker/docker_container.py @@ -1038,6 +1038,8 @@ class TaskParameters(DockerBaseClass): protocol = 'tcp' port = int(publish_port) for exposed_port in exposed: + if exposed_port[1] != protocol: + continue if isinstance(exposed_port[0], string_types) and '-' in exposed_port[0]: start_port, end_port = exposed_port[0].split('-') if int(start_port) <= port <= int(end_port): @@ -1229,7 +1231,7 @@ class Container(DockerBaseClass): # "ExposedPorts": null returns None type & causes AttributeError - PR #5517 if config.get('ExposedPorts') is not None: - expected_exposed = [re.sub(r'/.+$', '', p) for p in config.get('ExposedPorts', dict()).keys()] + expected_exposed = [self._normalize_port(p) for p in config.get('ExposedPorts', dict()).keys()] else: expected_exposed = [] @@ -1644,10 +1646,10 @@ class Container(DockerBaseClass): self.log('_get_expected_exposed') image_ports = [] if image: - image_ports = [re.sub(r'/.+$', '', p) for p in (image['ContainerConfig'].get('ExposedPorts') or {}).keys()] + image_ports = [self._normalize_port(p) for p in (image['ContainerConfig'].get('ExposedPorts') or {}).keys()] param_ports = [] if self.parameters.ports: - param_ports = [str(p[0]) for p in self.parameters.ports] + param_ports = [str(p[0]) + '/' + p[1] for p in self.parameters.ports] result = list(set(image_ports + param_ports)) self.log(result, pretty_print=True) return result @@ -1688,6 +1690,11 @@ class Container(DockerBaseClass): results.append("%s%s%s" % (key, join_with, value)) return results + def _normalize_port(self, port): + if '/' not in port: + return port + '/tcp' + return port + class ContainerManager(DockerBaseClass): ''' diff --git a/test/units/modules/cloud/docker/__init__.py b/test/units/modules/cloud/docker/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/units/modules/cloud/docker/test_docker_container.py b/test/units/modules/cloud/docker/test_docker_container.py new file mode 100644 index 00000000000..ae81714799a --- /dev/null +++ b/test/units/modules/cloud/docker/test_docker_container.py @@ -0,0 +1,19 @@ +import unittest + +from ansible.modules.cloud.docker.docker_container import TaskParameters + + +class TestTaskParameters(unittest.TestCase): + """Unit tests for TaskParameters.""" + + def test_parse_exposed_ports_tcp_udp(self): + """ + Ensure _parse_exposed_ports does not cancel ports with the same + number but different protocol. + """ + task_params = TaskParameters.__new__(TaskParameters) + task_params.exposed_ports = None + result = task_params._parse_exposed_ports([80, '443', '443/udp']) + self.assertTrue((80, 'tcp') in result) + self.assertTrue((443, 'tcp') in result) + self.assertTrue((443, 'udp') in result)