From 4f7cbc3812655f45d939ddf0ebd1417341aca388 Mon Sep 17 00:00:00 2001 From: Mark Steve Samson Date: Wed, 25 Jun 2014 18:49:54 +0800 Subject: [PATCH] Support for host address in port bindings (Closes #267) --- fig/service.py | 25 +++++++++++++++++++------ tests/integration/service_test.py | 21 +++++++++++++++++++++ tests/unit/service_test.py | 17 ++++++++++++++++- 3 files changed, 56 insertions(+), 7 deletions(-) diff --git a/fig/service.py b/fig/service.py index a6e4971b0..613a79c0b 100644 --- a/fig/service.py +++ b/fig/service.py @@ -214,12 +214,7 @@ class Service(object): if options.get('ports', None) is not None: for port in options['ports']: - port = str(port) - if ':' in port: - external_port, internal_port = port.split(':', 1) - else: - external_port, internal_port = (None, port) - + internal_port, external_port = split_port(port) port_bindings[internal_port] = external_port volume_bindings = {} @@ -407,3 +402,21 @@ def split_volume(v): return v.split(':', 1) else: return (None, v) + + +def split_port(port): + port = str(port) + external_ip = None + if ':' in port: + external_port, internal_port = port.rsplit(':', 1) + if ':' in external_port: + external_ip, external_port = external_port.split(':', 1) + else: + external_port, internal_port = (None, port) + if external_ip: + if external_port: + external_port = (external_ip, external_port) + else: + external_port = (external_ip,) + return internal_port, external_port + diff --git a/tests/integration/service_test.py b/tests/integration/service_test.py index aaefbd403..1b0f80fcb 100644 --- a/tests/integration/service_test.py +++ b/tests/integration/service_test.py @@ -231,6 +231,27 @@ class ServiceTest(DockerClientTestCase): self.assertIn('8000/tcp', container['NetworkSettings']['Ports']) self.assertEqual(container['NetworkSettings']['Ports']['8000/tcp'][0]['HostPort'], '8001') + def test_port_with_explicit_interface(self): + service = self.create_service('web', ports=[ + '127.0.0.1:8001:8000', + '0.0.0.0:9001:9000', + ]) + container = service.start_container().inspect() + self.assertEqual(container['NetworkSettings']['Ports'], { + '8000/tcp': [ + { + 'HostIp': '127.0.0.1', + 'HostPort': '8001', + }, + ], + '9000/tcp': [ + { + 'HostIp': '0.0.0.0', + 'HostPort': '9001', + }, + ], + }) + def test_scale(self): service = self.create_service('web') service.scale(1) diff --git a/tests/unit/service_test.py b/tests/unit/service_test.py index 490cb60d6..8acdc056b 100644 --- a/tests/unit/service_test.py +++ b/tests/unit/service_test.py @@ -2,7 +2,7 @@ from __future__ import unicode_literals from __future__ import absolute_import from .. import unittest from fig import Service -from fig.service import ConfigError +from fig.service import ConfigError, split_port class ServiceTest(unittest.TestCase): def test_name_validations(self): @@ -27,3 +27,18 @@ class ServiceTest(unittest.TestCase): def test_config_validation(self): self.assertRaises(ConfigError, lambda: Service(name='foo', port=['8000'])) Service(name='foo', ports=['8000']) + + def test_split_port(self): + internal_port, external_port = split_port("127.0.0.1:1000:2000") + self.assertEqual(internal_port, "2000") + self.assertEqual(external_port, ("127.0.0.1", "1000")) + + internal_port, external_port = split_port("127.0.0.1::2000") + self.assertEqual(internal_port, "2000") + self.assertEqual(external_port, ("127.0.0.1",)) + + internal_port, external_port = split_port("1000:2000") + self.assertEqual(internal_port, "2000") + self.assertEqual(external_port, "1000") + +