diff --git a/compose/config/types.py b/compose/config/types.py index 548f2c1cd..d3b3cfc53 100644 --- a/compose/config/types.py +++ b/compose/config/types.py @@ -319,11 +319,19 @@ class ServicePort(namedtuple('_ServicePort', 'target published protocol mode ext except ValueError: raise ConfigurationError('Invalid target port: {}'.format(target)) - try: - if published: - published = int(published) - except ValueError: - raise ConfigurationError('Invalid published port: {}'.format(published)) + if published: + if isinstance(published, six.string_types) and '-' in published: # "x-y:z" format + a, b = published.split('-', 1) + try: + int(a) + int(b) + except ValueError: + raise ConfigurationError('Invalid published port: {}'.format(published)) + else: + try: + published = int(published) + except ValueError: + raise ConfigurationError('Invalid published port: {}'.format(published)) return super(ServicePort, cls).__new__( cls, target, published, *args, **kwargs diff --git a/tests/unit/config/types_test.py b/tests/unit/config/types_test.py index 3a43f727b..e7cc67b04 100644 --- a/tests/unit/config/types_test.py +++ b/tests/unit/config/types_test.py @@ -100,11 +100,37 @@ class TestServicePort(object): 'published': 25001 } in reprs + def test_parse_port_publish_range(self): + ports = ServicePort.parse('4440-4450:4000') + assert len(ports) == 1 + reprs = [p.repr() for p in ports] + assert { + 'target': 4000, + 'published': '4440-4450' + } in reprs + def test_parse_invalid_port(self): port_def = '4000p' with pytest.raises(ConfigurationError): ServicePort.parse(port_def) + def test_parse_invalid_publish_range(self): + port_def = '-4000:4000' + with pytest.raises(ConfigurationError): + ServicePort.parse(port_def) + + port_def = 'asdf:4000' + with pytest.raises(ConfigurationError): + ServicePort.parse(port_def) + + port_def = '1234-12f:4000' + with pytest.raises(ConfigurationError): + ServicePort.parse(port_def) + + port_def = '1234-1235-1239:4000' + with pytest.raises(ConfigurationError): + ServicePort.parse(port_def) + class TestVolumeSpec(object):