浏览代码

Add format to other v3 configs & remove unix dependency

Signed-off-by: Drew Romanyk <[email protected]>
Drew Romanyk 8 年之前
父节点
当前提交
6c8184d0d0

+ 1 - 1
compose/config/config_schema_v3.0.json

@@ -294,7 +294,7 @@
               "items": {
                 "type": "object",
                 "properties": {
-                  "subnet": {"type": "string"}
+                  "subnet": {"type": "string", "format": "subnet_ip_address"}
                 },
                 "additionalProperties": false
               }

+ 1 - 1
compose/config/config_schema_v3.1.json

@@ -323,7 +323,7 @@
               "items": {
                 "type": "object",
                 "properties": {
-                  "subnet": {"type": "string"}
+                  "subnet": {"type": "string", "format": "subnet_ip_address"}
                 },
                 "additionalProperties": false
               }

+ 1 - 1
compose/config/config_schema_v3.2.json

@@ -368,7 +368,7 @@
               "items": {
                 "type": "object",
                 "properties": {
-                  "subnet": {"type": "string"}
+                  "subnet": {"type": "string", "format": "subnet_ip_address"}
                 },
                 "additionalProperties": false
               }

+ 1 - 1
compose/config/config_schema_v3.3.json

@@ -412,7 +412,7 @@
               "items": {
                 "type": "object",
                 "properties": {
-                  "subnet": {"type": "string"}
+                  "subnet": {"type": "string", "format": "subnet_ip_address"}
                 },
                 "additionalProperties": false
               }

+ 1 - 1
compose/config/config_schema_v3.4.json

@@ -420,7 +420,7 @@
               "items": {
                 "type": "object",
                 "properties": {
-                  "subnet": {"type": "string"}
+                  "subnet": {"type": "string", "format": "subnet_ip_address"}
                 },
                 "additionalProperties": false
               }

+ 34 - 18
compose/config/validation.py

@@ -5,7 +5,6 @@ import json
 import logging
 import os
 import re
-import socket
 import sys
 
 import six
@@ -44,9 +43,32 @@ DOCKER_CONFIG_HINTS = {
 
 VALID_NAME_CHARS = '[a-zA-Z0-9\._\-]'
 VALID_EXPOSE_FORMAT = r'^\d+(\-\d+)?(\/[a-zA-Z]+)?$'
-VALID_IPV4_FORMAT = r'^(\d{1,3}.){3}\d{1,3}$'
-VALID_IPV4_CIDR_FORMAT = r'^(\d|[1-2]\d|3[0-2])$'
-VALID_IPV6_CIDR_FORMAT = r'^(\d|[1-9]\d|1[0-1]\d|12[0-8])$'
+
+VALID_IPV4_SEG = r'(\d{1,2}|1\d{2}|2[0-4]\d|25[0-5])'
+VALID_REGEX_IPV4_CIDR = r'^(\d|[1-2]\d|3[0-2])$'
+VALID_IPV4_ADDR = "({IPV4_SEG}\.){{3}}{IPV4_SEG}".format(IPV4_SEG=VALID_IPV4_SEG)
+VALID_REGEX_IPV4_ADDR = "^{IPV4_ADDR}$".format(IPV4_ADDR=VALID_IPV4_ADDR)
+
+VALID_IPV6_SEG = r'[0-9a-fA-F]{1,4}'
+VALID_REGEX_IPV6_CIDR = r'^(\d|[1-9]\d|1[0-1]\d|12[0-8])$'
+VALID_REGEX_IPV6_ADDR = "".join("""
+^
+(
+    (({IPV6_SEG}:){{7}}{IPV6_SEG})|
+    (({IPV6_SEG}:){{1,7}}:)|
+    (({IPV6_SEG}:){{1,6}}(:{IPV6_SEG}){{1,1}})|
+    (({IPV6_SEG}:){{1,5}}(:{IPV6_SEG}){{1,2}})|
+    (({IPV6_SEG}:){{1,4}}(:{IPV6_SEG}){{1,3}})|
+    (({IPV6_SEG}:){{1,3}}(:{IPV6_SEG}){{1,4}})|
+    (({IPV6_SEG}:){{1,2}}(:{IPV6_SEG}){{1,5}})|
+    (({IPV6_SEG}:){{1,1}}(:{IPV6_SEG}){{1,6}})|
+    (:((:{IPV6_SEG}){{1,7}}|:))|
+    (fe80:(:{IPV6_SEG}){{0,4}}%[0-9a-zA-Z]{{1,}})|
+    (::(ffff(:0{{1,4}}){{0,1}}:){{0,1}}{IPV4_ADDR})|
+    (({IPV6_SEG}:){{1,4}}:{IPV4_ADDR})
+)
+$
+""".format(IPV6_SEG=VALID_IPV6_SEG, IPV4_ADDR=VALID_IPV4_ADDR).split())
 
 
 @FormatChecker.cls_checks(format="ports", raises=ValidationError)
@@ -72,24 +94,18 @@ def format_expose(instance):
 def format_subnet_ip_address(instance):
     if isinstance(instance, six.string_types):
         if '/' not in instance:
-            raise ValidationError("'{0}' 75 should be of the format 'IP_ADDRESS/CIDR'".format(instance))
+            raise ValidationError("should be of the format 'IP_ADDRESS/CIDR'")
 
         ip_address, cidr = instance.split('/')
 
-        if re.match(VALID_IPV4_FORMAT, ip_address):
-            if not (re.match(VALID_IPV4_CIDR_FORMAT, cidr) and
-                    all(0 <= int(component) <= 255 for component in ip_address.split("."))):
-                raise ValidationError(
-                    "'{0}' 83 should be of the format 'IP_ADDRESS/CIDR'".format(instance))
-        elif re.match(VALID_IPV6_CIDR_FORMAT, cidr) and hasattr(socket, "inet_pton"):
-            try:
-                if not (socket.inet_pton(socket.AF_INET6, ip_address)):
-                    raise ValidationError(
-                        "'{0}' 88 should be of the format 'IP_ADDRESS/CIDR'".format(instance))
-            except socket.error as e:
-                raise ValidationError(six.text_type(e))
+        if re.match(VALID_REGEX_IPV4_ADDR, ip_address):
+            if not re.match(VALID_REGEX_IPV4_CIDR, cidr):
+                raise ValidationError("should be of the format 'IP_ADDRESS/CIDR'")
+        elif re.match(VALID_REGEX_IPV6_ADDR, ip_address):
+            if not re.match(VALID_REGEX_IPV6_CIDR, cidr):
+                raise ValidationError("should be of the format 'IP_ADDRESS/CIDR'")
         else:
-            raise ValidationError("'{0}' 92 should be of the format 'IP_ADDRESS/CIDR'".format(instance))
+            raise ValidationError("should be of the format 'IP_ADDRESS/CIDR'")
 
     return True
 

+ 16 - 14
tests/unit/config/config_test.py

@@ -2865,10 +2865,7 @@ class SubnetTest(unittest.TestCase):
         "fe80:0000:0000:0000:0204:61ff:fe9d:f156/129",
         "fe80:0000:0000:0000:0204:61ff:fe9d:f156/01",
         "fe80:0000:0000:0000:0204:61ff:fe9d:f156",
-    ]
-
-    ILLEGAL_SUBNET_MAPPINGS = [
-        "ge80:0000:0000:0000:0204:61ff:fe9d:f156/128"
+        "ge80:0000:0000:0000:0204:61ff:fe9d:f156/128",
     ]
 
     VALID_SUBNET_MAPPINGS = [
@@ -2876,6 +2873,21 @@ class SubnetTest(unittest.TestCase):
         "192.168.0.1/32",
         "fe80:0000:0000:0000:0204:61ff:fe9d:f156/0",
         "fe80:0000:0000:0000:0204:61ff:fe9d:f156/128",
+        "1:2:3:4:5:6:7:8/0",
+        "1::/0",
+        "1:2:3:4:5:6:7::/0",
+        "1::8/0",
+        "1:2:3:4:5:6::8/0",
+        "::/0",
+        "::8/0",
+        "::2:3:4:5:6:7:8/0",
+        "fe80::7:8%eth0/0",
+        "fe80::7:8%1/0",
+        "::255.255.255.255/0",
+        "::ffff:255.255.255.255/0",
+        "::ffff:0:255.255.255.255/0",
+        "2001:db8:3:4::192.0.2.33/0",
+        "64:ff9b::192.0.2.33/0",
     ]
 
     def test_config_invalid_subnet_type_validation(self):
@@ -2892,16 +2904,6 @@ class SubnetTest(unittest.TestCase):
 
             assert "should be of the format 'IP_ADDRESS/CIDR'" in exc.value.msg
 
-    def test_config_illegal_subnet_type_validation(self):
-        for invalid_subnet in self.ILLEGAL_SUBNET_MAPPINGS:
-            with pytest.raises(ConfigurationError) as exc:
-                self.check_config(invalid_subnet)
-            if IS_WINDOWS_PLATFORM:
-                assert "An invalid argument was supplied" in exc.value.msg or \
-                       "illegal IP address string" in exc.value.msg
-            else:
-                assert "illegal IP address string" in exc.value.msg
-
     def test_config_valid_subnet_format_validation(self):
         for valid_subnet in self.VALID_SUBNET_MAPPINGS:
             self.check_config(valid_subnet)