|
@@ -5,6 +5,7 @@ import json
|
|
|
import logging
|
|
|
import os
|
|
|
import re
|
|
|
+import socket
|
|
|
import sys
|
|
|
|
|
|
import six
|
|
@@ -43,6 +44,9 @@ 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])$'
|
|
|
|
|
|
|
|
|
@FormatChecker.cls_checks(format="ports", raises=ValidationError)
|
|
@@ -64,6 +68,30 @@ def format_expose(instance):
|
|
|
return True
|
|
|
|
|
|
|
|
|
[email protected]_checks("subnet_ip_address", raises=ValidationError)
|
|
|
+def format_subnet_ip_address(instance):
|
|
|
+ if isinstance(instance, six.string_types):
|
|
|
+ if '/' not in 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("should be of the format 'IP_ADDRESS/CIDR'")
|
|
|
+ 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("should be of the format 'IP_ADDRESS/CIDR'")
|
|
|
+ except socket.error as e:
|
|
|
+ raise ValidationError(six.text_type(e))
|
|
|
+ else:
|
|
|
+ raise ValidationError("should be of the format 'IP_ADDRESS/CIDR'")
|
|
|
+
|
|
|
+ return True
|
|
|
+
|
|
|
+
|
|
|
def match_named_volumes(service_dict, project_volumes):
|
|
|
service_volumes = service_dict.get('volumes', [])
|
|
|
for volume_spec in service_volumes:
|
|
@@ -391,7 +419,7 @@ def process_config_schema_errors(error):
|
|
|
|
|
|
def validate_against_config_schema(config_file):
|
|
|
schema = load_jsonschema(config_file)
|
|
|
- format_checker = FormatChecker(["ports", "expose"])
|
|
|
+ format_checker = FormatChecker(["ports", "expose", "subnet_ip_address"])
|
|
|
validator = Draft4Validator(
|
|
|
schema,
|
|
|
resolver=RefResolver(get_resolver_path(), schema),
|