Adds Hostname Validator 57/68157/2
authorParker Berberian <pberberian@iol.unh.edu>
Fri, 28 Jun 2019 13:58:54 +0000 (09:58 -0400)
committerParker Berberian <pberberian@iol.unh.edu>
Fri, 28 Jun 2019 14:28:53 +0000 (10:28 -0400)
Creates a single place to validate hostnames, with public
fields for regex that can be copied to the frontend.

We do hostname validation inconsistently all over the place,
we should move to using this single validator.

Change-Id: I7b71fd89843a7e5b7f9d93dcb23f4645abe71dd0
Signed-off-by: Parker Berberian <pberberian@iol.unh.edu>
src/resource_inventory/resource_manager.py
src/resource_inventory/tests/test_managers.py

index 652e4e3..28bed20 100644 (file)
@@ -6,7 +6,7 @@
 # which accompanies this distribution, and is available at
 # http://www.apache.org/licenses/LICENSE-2.0
 ##############################################################################
-
+import re
 
 from dashboard.exceptions import (
     ResourceExistenceException,
@@ -172,3 +172,13 @@ class ResourceManager:
         self.releaseNetworks(grb, vlan_manager, vlans)
         for host in hosts:
             self.releaseHost(host)
+
+
+class HostNameValidator(object):
+    regex = r'^[A-Za-z0-9][A-Za-z0-9-]*$'
+    message = "Hostnames can only contain alphanumeric characters and hyphens (-). Hostnames must start with a letter"
+    pattern = re.compile(regex)
+
+    @classmethod
+    def is_valid_hostname(cls, hostname):
+        return len(hostname) < 65 and cls.pattern.fullmatch(hostname) is not None
index 0e7c673..46cee5a 100644 (file)
@@ -11,7 +11,7 @@ from django.test import TestCase
 from django.contrib.auth.models import User
 
 from resource.inventory_manager import InventoryManager
-from resource.resource_manager import ResourceManager
+from resource.resource_manager import ResourceManager, HostNameValidator
 from account.models import Lab
 from resource.models import (
     Host,
@@ -247,3 +247,55 @@ class ResourceManagerTestCase(TestCase):
     def test_convert_bundle(self):
         ResourceManager.getInstance().convertResoureBundle(self.genericBundle, self.lab.name)
         # verify bundle configuration
+
+
+class HostNameValidatorTestCase(TestCase):
+
+    def test_valid_hostnames(self):
+        self.assertTrue(HostNameValidator.is_valid_hostname("localhost"))
+        self.assertTrue(HostNameValidator.is_valid_hostname("Localhost"))
+        self.assertTrue(HostNameValidator.is_valid_hostname("localHost"))
+        self.assertTrue(HostNameValidator.is_valid_hostname("LOCALHOST"))
+        self.assertTrue(HostNameValidator.is_valid_hostname("f"))
+        self.assertTrue(HostNameValidator.is_valid_hostname("abc123doreyme"))
+        self.assertTrue(HostNameValidator.is_valid_hostname("F9999999"))
+        self.assertTrue(HostNameValidator.is_valid_hostname("my-host"))
+        self.assertTrue(HostNameValidator.is_valid_hostname("My-Host"))
+        self.assertTrue(HostNameValidator.is_valid_hostname("MY-HOST"))
+        self.assertTrue(HostNameValidator.is_valid_hostname("a-long-name-for-my-host"))
+
+    def test_invalid_hostnames(self):
+        self.assertFalse(HostNameValidator.is_valid_hostname("-long-name-for-my-host"))
+        self.assertFalse(HostNameValidator.is_valid_hostname("546"))
+        self.assertFalse(HostNameValidator.is_valid_hostname("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
+
+    def test_invalid_chars(self):
+        self.assertFalse(HostNameValidator.is_valid_hostname("contains!char"))
+        self.assertFalse(HostNameValidator.is_valid_hostname("contains@char"))
+        self.assertFalse(HostNameValidator.is_valid_hostname("contains#char"))
+        self.assertFalse(HostNameValidator.is_valid_hostname("contains$char"))
+        self.assertFalse(HostNameValidator.is_valid_hostname("contains%char"))
+        self.assertFalse(HostNameValidator.is_valid_hostname("contains^char"))
+        self.assertFalse(HostNameValidator.is_valid_hostname("contains&char"))
+        self.assertFalse(HostNameValidator.is_valid_hostname("contains*char"))
+        self.assertFalse(HostNameValidator.is_valid_hostname("contains(char"))
+        self.assertFalse(HostNameValidator.is_valid_hostname("contains)char"))
+        self.assertFalse(HostNameValidator.is_valid_hostname("contains_char"))
+        self.assertFalse(HostNameValidator.is_valid_hostname("contains=char"))
+        self.assertFalse(HostNameValidator.is_valid_hostname("contains+char"))
+        self.assertFalse(HostNameValidator.is_valid_hostname("contains|char"))
+        self.assertFalse(HostNameValidator.is_valid_hostname("contains\\char"))
+        self.assertFalse(HostNameValidator.is_valid_hostname("contains[char"))
+        self.assertFalse(HostNameValidator.is_valid_hostname("contains]char"))
+        self.assertFalse(HostNameValidator.is_valid_hostname("contains;char"))
+        self.assertFalse(HostNameValidator.is_valid_hostname("contains:char"))
+        self.assertFalse(HostNameValidator.is_valid_hostname("contains'char"))
+        self.assertFalse(HostNameValidator.is_valid_hostname('contains"char'))
+        self.assertFalse(HostNameValidator.is_valid_hostname("contains'char"))
+        self.assertFalse(HostNameValidator.is_valid_hostname("contains<char"))
+        self.assertFalse(HostNameValidator.is_valid_hostname("contains>char"))
+        self.assertFalse(HostNameValidator.is_valid_hostname("contains,char"))
+        self.assertFalse(HostNameValidator.is_valid_hostname("contains?char"))
+        self.assertFalse(HostNameValidator.is_valid_hostname("contains/char"))
+        self.assertFalse(HostNameValidator.is_valid_hostname("contains`char"))
+        self.assertFalse(HostNameValidator.is_valid_hostname("contains~char"))