Base net-virt CLI files on top of which ONOS specific changes will be done
diff --git a/cli/sdncon/rest/validators.py b/cli/sdncon/rest/validators.py
new file mode 100755
index 0000000..856038a
--- /dev/null
+++ b/cli/sdncon/rest/validators.py
@@ -0,0 +1,448 @@
+#
+# Copyright (c) 2013 Big Switch Networks, Inc.
+#
+# Licensed under the Eclipse Public License, Version 1.0 (the
+# "License"); you may not use this file except in compliance with the
+# License. You may obtain a copy of the License at
+#
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+#
+
+import re
+import os.path
+
+from django.forms import ValidationError
+from django.core.validators import RegexValidator, MinValueValidator, MaxValueValidator
+
+validate_mac_address = RegexValidator('^(([A-Fa-f\d]){2}:?){5}[A-Fa-f\d]{2}$', 'MAC address is a 48-bit quantity, expressed in hex as AA:BB:CC:DD:EE:FF', 'invalid')
+validate_dpid = RegexValidator('^([A-Fa-f\d]{2}:?){7}[A-Fa-f\d]{2}$', 'Switch DPID is a 64-bit quantity, expressed in hex as AA:BB:CC:DD:EE:FF:00:11', 'invalid')
+validate_controller_id = RegexValidator('^[A-Fa-f\d]{8}-([A-Fa-f\d]{4}-){3}[A-Fa-f\d]{12}$', 'Controller ID is a 128-bit quantity, expressed in hex as aabbccdd-eeff-0011-2233-445566778899', 'invalid')
+
+class UfwProtocolValditor(object):
+ def __init__(self):
+ pass
+
+ def __call__(self, value):
+ if not (value != "tcp" or value != "udp" or value != 'vrrp'):
+ raise ValidationError("Protocol must be either 'tcp' or 'udp' or 'vrrp'")
+
+octet = r'(?:0|[1-9][0-9]*)'
+IP_RE = re.compile("^" + octet + '[.]' + octet
+ + '[.]' + octet + '[.]' + octet + "$")
+
+class IpValidator(object):
+ def __call__(self, value):
+ if not IP_RE.match(value) or len([x for x in value.split('.') if int(x) < 256]) != 4:
+ raise ValidationError("IP must be in dotted decimal format, 234.0.59.1")
+
+class IpMaskValidator(object):
+ def __call__(self, value):
+ if not IP_RE.match(value):
+ raise ValidationError("IP must be in dotted decimal format, 255.255.128.0")
+ invalid_netmask = False
+ invalid_inverse_netmask = False
+ lookForZero = False
+ for x in value.split('.'):
+ xInt = int(x)
+ if lookForZero:
+ if xInt:
+ invalid_netmask = True
+ break # go check inverse mask
+ if xInt != 255:
+ if xInt:
+ if xInt >= 128:
+ while (xInt % 2) == 0:
+ xInt = xInt >> 1
+ if xInt & (xInt + 1) == 0:
+ continue
+ invalid_netmask = True
+ break # go check inverse mask
+ lookForZero = True
+
+ lookForOne = False
+ for x in value.split('.'):
+ xInt = int(x)
+ if lookForOne: # all bits should be 1 bits
+ if (xInt != 255):
+ invalid_inverse_netmask = True
+ break
+ else:
+ continue
+ if xInt != 0:
+ # check for contiguous 1-bits from LSb
+ lookForOne = True
+ if xInt == 255:
+ continue
+ if xInt & (xInt + 1) != 0:
+ invalid_inverse_netmask = True
+ break
+ if invalid_netmask and invalid_inverse_netmask: # no valid mask, then raise exception
+ raise ValidationError("Invalid IP Mask, should be like 255.255.128.0 or 0.0.127.255")
+
+
+class PortRangeSpecValidator(object):
+ def __init__(self):
+ self.RANGE_RE = re.compile(r'^([A-Za-z0-9-/\.:]*?)(\d+)\-(\d+)$')
+ self.SINGLE_RE = re.compile(r'^([A-Za-z0-9-/\.:]+)$')
+ def __call__(self, value):
+ values = value.split(',')
+ for v in values:
+ m = self.RANGE_RE.match(v);
+ if (m):
+ startport = int(m.group(2))
+ endport = int(m.group(3))
+ if (startport >= endport):
+ raise ValidationError("Invalid range numerals: %d-%d" % (startport, endport))
+ elif not self.SINGLE_RE.match(v):
+ raise ValidationError("Must be a list of ports or ranges, such as 'A10-15,B25,C1-13'")
+
+class VLANRangeSpecValidator(object):
+ def __init__(self):
+ self.RANGE_RE = re.compile(r'^([\d]+)\-([\d]+)$')
+ self.SINGLE_RE = re.compile(r'^[\d]+$')
+
+ def __call__(self, value):
+ values = value.split(',')
+ for v in values:
+ m = self.RANGE_RE.match(v);
+ if v == 'untagged':
+ pass
+ elif (m):
+ if (int(m.group(1)) >= int(m.group(2))):
+ raise ValidationError("Invalid range numerals in {}: {} must be less than {}".format(v, m.group(1), m.group(2)))
+ elif (int(m.group(1)) > 4095):
+ raise ValidationError("Invalid VLAN: {} must be in range 0-4095".format(m.group(1)))
+ elif (int(m.group(2)) < 0):
+ raise ValidationError("Invalid VLAN: {} must be in range 0-4095".format(m.group(2)))
+ elif not self.SINGLE_RE.match(v):
+ raise ValidationError("Must be a list of VLANs or ranges,"
+ " such as '5-20,45,4053,untagged'")
+ elif int(v) > 4095 or int(v) < 0:
+ raise ValidationError("Invalid VLAN: {} must be in range 0-4095".format(v))
+
+class TagSpecValidator(object):
+ def __init__(self):
+ self.TAG_NAME_RE = re.compile(r'^([a-zA-Z0-9_-]+(?:\.?[a-zA-Z0-9_-]+)*)=+([a-zA-Z0-9_-]+)$')
+
+ def __call__(self,value):
+ values = value.split(',')
+ for v in values:
+ v = v.strip()
+ if not self.TAG_NAME_RE.match(v):
+ raise ValidationError("Invalid tag: " +
+ '='.join(v.split('|')) +
+ "\nFormat: tag namespace.namel value1, " +
+ "where namespace may be empty or must be a-z, A-Z, 0-9, -, . or _, " +
+ "name and value must be a-z, A-Z, 0-9, - or _")
+
+class CidrValidator(object):
+ def __init__(self, mask_required=True):
+ self.mask_required = mask_required
+ self.CIDR_RE = re.compile(r'^(\d{1,3}\.){3}\d{1,3}/\d{1,2}?$')
+
+ def __call__(self, value):
+ ip_validator = IpValidator()
+ if self.CIDR_RE.match(value):
+ ip, mask = value.split('/')
+ ip_validator(ip)
+ if int(mask) < 1 or int(mask) > 32:
+ raise ValidationError("Mask should be between 1-32")
+ else:
+ if self.mask_required: # if mask was required and we didn't match above, problem!
+ raise ValidationError("Must be in dotted decimal format with a mask between 1-32")
+ else:
+ ip_validator(value)
+
+class EnumerationValidator(object):
+ def __init__(self, enumerated_values, case_sensitive=False, message=None, code=None):
+ self.case_sensitive = case_sensitive
+ if case_sensitive:
+ self.enumerated_values = enumerated_values
+ else:
+ self.enumerated_values = [s.lower() for s in enumerated_values]
+ if not message:
+ message = 'Invalid enumerated value'
+ self.message = message
+ if not code:
+ code = 'invalid'
+ self.code = code
+
+ def __call__(self, value):
+ if not self.case_sensitive:
+ value = value.lower()
+ if value not in self.enumerated_values:
+ raise ValidationError(self.message, self.code)
+
+class ChoicesValidator(EnumerationValidator):
+ def __init__(self, choices, case_sensitive=False, message=None, code=None):
+ enumerated_values = [choice[0] for choice in choices]
+ EnumerationValidator.__init__(self, enumerated_values, case_sensitive, message, code)
+
+class RangeValidator(object):
+ def __init__(self, min, max):
+ self.min_value_validator = MinValueValidator(min)
+ self.max_value_validator = MaxValueValidator(max)
+
+ def __call__(self, value):
+ try:
+ self.min_value_validator(int(value))
+ self.max_value_validator(int(value))
+ except ValidationError:
+ raise ValidationError('Ensure this value is within the range (%d-%d)' %
+ (self.min_value_validator.limit_value,
+ self.max_value_validator.limit_value))
+
+class ControllerAliaVsalidator(object):
+ def __init__(self):
+ self.CONTROLLER_ALIAS_RE = re.compile(r'^[a-zA-Z0-9_-]+$')
+
+ def __call__(self, value):
+ if not self.CONTROLLER_ALIAS_RE.match(value):
+ raise ValidationError("controller alias name must ba a-z, 0-9, _ or _")
+
+class SwitchAliasValidator(object):
+ def __init__(self):
+ self.SWITCH_ALIAS_RE = re.compile(r'^[a-zA-Z0-9_-]+$')
+
+ def __call__(self, value):
+ if not self.SWITCH_ALIAS_RE.match(value):
+ raise ValidationError("switch alias name must ba a-z, 0-9, _ or _")
+
+class PortAliasValidator(object):
+ def __init__(self):
+ self.PORT_ALIAS_RE = re.compile(r'^[a-zA-Z0-9_-]+$')
+
+ def __call__(self, value):
+ if not self.PORT_ALIAS_RE.match(value):
+ raise ValidationError("port alias name must ba a-z, 0-9, _ or _")
+
+class HostAliasValidator(object):
+ def __init__(self):
+ self.HOST_ALIAS_RE = re.compile(r'^[a-zA-Z0-9_-]+$')
+
+ def __call__(self, value):
+ if not self.HOST_ALIAS_RE.match(value):
+ raise ValidationError("host alias name must ba a-z, 0-9, _ or _")
+
+class AddressSpaceNameValidator(object):
+ def __init__(self):
+ self.ADDRESS_SPACE_NAME_RE = re.compile(r'^[a-zA-Z0-9_-]+$')
+
+ def __call__(self,value):
+ if not self.ADDRESS_SPACE_NAME_RE.match(value):
+ raise ValidationError("address-space name must be a-z, A-Z, 0-9, - or _")
+
+class TenantNameValidator(object):
+ def __init__(self):
+ self.TENANT_NAME_RE = re.compile(r'^[a-zA-Z0-9_-]+$')
+
+ def __call__(self,value):
+ if not self.TENANT_NAME_RE.match(value):
+ raise ValidationError("tenant name must be a-z, A-Z, 0-9, - or _")
+
+class GeneralNameValidator(object):
+ def __init__(self):
+ self.GENERAL_NAME_RE = re.compile(r'^[a-zA-Z0-9_-]+$')
+
+ def __call__(self,value):
+ if not self.GENERAL_NAME_RE.match(value):
+ raise ValidationError("Name must be a-z, A-Z, 0-9, - or _")
+
+class VnsNameValidator(object):
+ def __init__(self):
+ self.VNS_NAME_RE = re.compile(r'^[a-zA-Z0-9_-]+$')
+
+ def __call__(self,value):
+ if not self.VNS_NAME_RE.match(value):
+ raise ValidationError("vns name must be a-z, A-Z, 0-9, - or _")
+
+class VnsInterfaceNameValidator(object):
+ def __init__(self):
+ self.VNS_INTERFACE_RE = re.compile(r'^[a-zA-Z0-9_-]+$')
+ self.PORT_RE = re.compile(r'^([A-Za-z0-9-]*?)(\d+)$')
+ self.MAC_RE = re.compile(r'^(([A-Fa-f\d]){2}:?){5}[A-Fa-f\d]{2}$')
+
+ def __call__(self,value):
+ if not self.VNS_INTERFACE_RE.match(value):
+ items = value.split('/')
+ if len(items) == 2:
+ if not self.PORT_RE.match(items[1]) and \
+ not self.MAC_RE.match(items[1]):
+ raise ValidationError("interface name after '/' must be either a port or a mac address")
+ else:
+ raise ValidationError("invalid syntax for interface name")
+
+class VnsAclNameValidator(object):
+ def __init__(self):
+ self.VNS_ACL_NAME_RE = re.compile(r'[a-zA-Z0-9_-]+$')
+
+ def __call__(self,value):
+ if not self.VNS_ACL_NAME_RE.match(value):
+ raise ValidationError("acl name must be a-z, A-Z, 0-9, - or _")
+
+class VnsAclEntryActionValidator(object):
+ def __call__(self,value):
+ if not "permit".startswith(value.lower()) and \
+ not "deny".startswith(value.lower()):
+ raise ValidationError("acl entry action must be 'permit' or 'deny'")
+
+class VnsInterfaceAclInOutValidator(object):
+ def __call__(self,value):
+ if not "in".startswith(value.lower()) and \
+ not "out".startswith(value.lower()):
+ raise ValidationError("acl entry action must be 'permit' or 'deny'")
+
+class VnsRuleNameValidator(object):
+ def __init__(self):
+ self.IF_NAME_RE = re.compile(r'^\d*$')
+
+ def __call__(self, value):
+ if not self.IF_NAME_RE.match(value):
+ print value
+ raise ValidationError("Invalid rule name, only digits allowed")
+
+class TagNameValidator(object):
+ def __init__(self):
+ self.TAG_NAME_RE = re.compile(r'^[a-zA-Z0-9_-]+(?:\.?[a-zA-Z0-9_-]+)*(?:\|[a-zA-Z0-9_-]+)+$')
+
+ def __call__(self,value):
+ if not self.TAG_NAME_RE.match(value):
+ raise ValidationError("Invalid tag: " + value + "\nFormat: tag namespace|namel|value1, " +
+ "where namespace may be empty or must be a-z, A-Z, 0-9, -, . or _, " +
+ "name and value must be a-z, A-Z, 0-9, - or _")
+
+
+class VnsArpModeValidator(object):
+ def __init__(self):
+ self.ARP_MODES = ['flood-if-unknown', 'always-flood', 'drop-if-unknown']
+
+ def __call__(self,value):
+ if not value in self.ARP_MODES:
+ raise ValidationError("must be one of %s" % ', '.join(self.ARP_MODES))
+
+class VnsDhcpModeValidator(object):
+ def __init__(self):
+ self.DHCP_MODES = ['flood-if-unknown', 'always-flood', 'static']
+
+ def __call__(self,value):
+ if not value in self.DHCP_MODES:
+ raise ValidationError("must be one of %s" % ', '.join(self.DHCP_MODES))
+
+class VnsBroadcastModeValidator(object):
+ def __init__(self):
+ self.BROADCAST_MODES = ['drop', 'always-flood', 'forward-to-known']
+
+ def __call__(self,value):
+ if not value in self.BROADCAST_MODES:
+ raise ValidationError("must be one of %s" % ', '.join(self.BROADCAST_MODES))
+
+class IntfNameValidator(object):
+ def __init__(self):
+ self.IntfName_RE = re.compile(r'^ethernet[0-9]')
+
+ def __call__(self, value):
+ if not self.IntfName_RE.match(value):
+ raise ValidationError("Interface name must be Ethernet<num>")
+
+class DomainNameValidator(object):
+ def __init__(self):
+ self.DomainName_RE = re.compile(r'^([a-zA-Z0-9-]+.?)+$')
+ def __call__(self,value):
+ if not self.DomainName_RE.match(value):
+ raise ValidationError("Value must be a valid domain name")
+
+class IpOrDomainNameValidator(object):
+ def __init__(self):
+ self.DomainName_RE = re.compile(r'^([a-zA-Z0-9-]+.?)+$')
+
+ def __call__(self,value):
+ if not IP_RE.match(value) and not self.DomainName_RE.match(value):
+ raise ValidationError("Value must be a valid IP address or domain name")
+
+class TimeZoneValidator(object):
+ timezones = None
+ def __call__(self, value):
+ if not TimeZoneValidator.timezones:
+ import pytz
+ TimeZoneValidator.timezones = pytz.all_timezones
+ if value not in TimeZoneValidator.timezones:
+ raise ValidationError("Invalid time zone string")
+
+class VCenterMgrIdsValidator(object):
+ def __init__(self):
+ self.VCenterMgrId_RE = re.compile(r'^[a-zA-Z]([a-zA-Z0-9_-])*')
+ def __call__(self,value):
+ if not self.VCenterMgrId_RE.match(value):
+ raise ValidationError("Value must be a valid name, starts with a alphabet and can have alphabets, numbers, _ and -")
+
+class VCenterObjNamesValidator(object):
+ def __init__(self):
+ self.VCenterObjName_RE = re.compile(r'(?!.*\|.*)')
+ def __call__(self, value):
+ if not self.VCenterObjName_RE.match(value):
+ raise ValidationError("VCenter object names can contain any character except '|'")
+
+class FeatureValidator(object):
+ """Validates that a specific feature has been installed
+
+ We assume that a feature has been installed if the following file exists:
+ {sdncon.SDN_ROOT}/feature/<feature-name>
+
+ NOTE: The feature is enabled/disabled for use by updating the controller
+ object, this validator just ensures that before we enable a feature, it
+ has been actually installed.
+ """
+ def __init__(self, feature, featuredir=None):
+ self.feature = feature
+ if featuredir is None:
+ featuredir = \
+ os.path.join(os.path.sep, 'opt', 'sdnplatform', 'feature')
+ self.featurefile = os.path.join(featuredir, feature)
+
+ def __call__(self, value):
+ if value and not os.path.isfile(self.featurefile):
+ raise ValidationError(
+ 'Feature not installed, please install "%s"' %
+ self.feature)
+
+class VlanStringValidator(object):
+ def __call__(self, value):
+ self.vlan = 0
+ try:
+ self.vlan = int(value)
+ if (self.vlan < 1 or self.vlan > 4095):
+ raise ValidationError("VLAN must be in the range of 1 to 4095 with 4095 as untagged")
+ except ValueError:
+ raise ValidationError(
+ "VLAN must be in the range of 1 to 4095 with 4095 as untagged")
+
+
+class SafeForPrimaryKeyValidator(object):
+ """Validates that a string does not contain any character that would be
+ illegal for use in a primary key. Currently this is the pipe | symbol
+ """
+
+ def __call__(self, value):
+ if "|" in value:
+ raise ValidationError(
+ "The pipe symbol '|' is not a valid character")
+
+
+class IsRegexValidator(object):
+ """Validates that a given string is a valid regular expression
+ """
+
+ def __call__(self, value):
+ try:
+ value = str(value)
+ re.compile(value)
+ except re.error as e:
+ raise ValidationError(
+ "Input is not a valid regular expression: %s", e)
+