diff --git a/compose/config/schema.json b/compose/config/schema.json index 258f44cca..74f5edbbf 100644 --- a/compose/config/schema.json +++ b/compose/config/schema.json @@ -75,15 +75,10 @@ "pid": {"type": "string"}, "ports": { - "oneOf": [ - {"type": "string", "format": "ports"}, - { - "type": "array", - "items": {"type": "string"}, - "uniqueItems": true, - "format": "ports" - } - ] + "type": "array", + "items": {"type": "string"}, + "uniqueItems": true, + "format": "ports" }, "privileged": {"type": "string"}, diff --git a/compose/config/validation.py b/compose/config/validation.py index ba5803dec..15e0754cf 100644 --- a/compose/config/validation.py +++ b/compose/config/validation.py @@ -1,5 +1,6 @@ import os +from docker.utils.ports import split_port import json from jsonschema import Draft4Validator, FormatChecker, ValidationError @@ -26,26 +27,13 @@ DOCKER_CONFIG_HINTS = { VALID_NAME_CHARS = '[a-zA-Z0-9\._\-]' -@FormatChecker.cls_checks(format="ports", raises=ValidationError("Ports is incorrectly formatted.")) +@FormatChecker.cls_checks(format="ports", raises=ValidationError("Invalid port formatting, it should be '[[remote_ip:]remote_port:]port[/protocol]'")) def format_ports(instance): - def _is_valid(port): - if ':' in port or '/' in port: - return True - try: - int(port) - return True - except ValueError: - return False + try: + split_port(instance) + except ValueError: return False - - if isinstance(instance, list): - for port in instance: - if not _is_valid(port): - return False - return True - elif isinstance(instance, str): - return _is_valid(instance) - return False + return True def get_unsupported_config_msg(service_name, error_key): diff --git a/tests/unit/config_test.py b/tests/unit/config_test.py index 9f690f111..4e982bb49 100644 --- a/tests/unit/config_test.py +++ b/tests/unit/config_test.py @@ -76,7 +76,7 @@ class ConfigTest(unittest.TestCase): def test_config_invalid_ports_format_validation(self): with self.assertRaises(ConfigurationError): - for invalid_ports in [{"1": "8000"}, "whatport"]: + for invalid_ports in [{"1": "8000"}, "whatport", "625", "8000:8050"]: config.load( config.ConfigDetails( {'web': {'image': 'busybox', 'ports': invalid_ports}}, @@ -86,7 +86,7 @@ class ConfigTest(unittest.TestCase): ) def test_config_valid_ports_format_validation(self): - valid_ports = [["8000", "9000"], "625", "8000:8050", ["8000/8050"]] + valid_ports = [["8000", "9000"], ["8000/8050"], ["8000"]] for ports in valid_ports: config.load( config.ConfigDetails(