diff --git a/app/models.py b/app/models.py index 0c32a0b0eb71f8fb89167aac5a0308d484562ba2..8408cc60bcf14fc179aa907f7de2950c5fb79d71 100644 --- a/app/models.py +++ b/app/models.py @@ -31,6 +31,7 @@ from .plugins import FlaskUserPlugin from .validators import ( ICS_ID_RE, HOST_NAME_RE, + INTERFACE_NAME_RE, VLAN_NAME_RE, MAC_ADDRESS_RE, DEVICE_TYPE_RE, @@ -1415,8 +1416,8 @@ class Interface(CreatedMixin, db.Model): return None # Force the string to lowercase lower_string = string.lower() - if HOST_NAME_RE.fullmatch(lower_string) is None: - raise ValidationError(r"Interface name shall match [a-z0-9\-]{2,20}") + if INTERFACE_NAME_RE.fullmatch(lower_string) is None: + raise ValidationError(r"Interface name shall match [a-z0-9\-]{2,25}") if self.host and not lower_string.startswith(self.host.name): raise ValidationError( f"Interface name shall start with the host name '{self.host}'" diff --git a/app/network/forms.py b/app/network/forms.py index 5d0f9c5fe90f0870a82e95605ee9673451870b81..30743fe0aacb89aad50fcc811e614f5c7b657dbc 100644 --- a/app/network/forms.py +++ b/app/network/forms.py @@ -28,6 +28,7 @@ from ..validators import ( RegexpList, IPNetwork, HOST_NAME_RE, + INTERFACE_NAME_RE, VLAN_NAME_RE, MAC_ADDRESS_RE, NoValidateSelectField, @@ -183,10 +184,10 @@ class InterfaceForm(CSEntryForm): ) interface_name = StringField( "Interface name", - description="name must be 2-20 characters long and contain only letters, numbers and dash", + description="name must be 2-25 characters long and contain only letters, numbers and dash", validators=[ validators.InputRequired(), - validators.Regexp(HOST_NAME_RE), + validators.Regexp(INTERFACE_NAME_RE), Unique(models.Interface), starts_with_hostname, UniqueAccrossModels([models.Cname]), diff --git a/app/validators.py b/app/validators.py index 86849412e12740c6d638fd9685a953eefbe90c04..642da1dc91cf3cf297b06cac938c46a49d4acc6a 100644 --- a/app/validators.py +++ b/app/validators.py @@ -16,6 +16,7 @@ from wtforms import ValidationError, SelectField ICS_ID_RE = re.compile(r"[A-Z]{3}[0-9]{3}") HOST_NAME_RE = re.compile(r"^[a-z0-9\-]{2,20}$") +INTERFACE_NAME_RE = re.compile(r"^[a-z0-9\-]{2,25}$") VLAN_NAME_RE = re.compile(r"^[A-Za-z0-9\-]{3,25}$") MAC_ADDRESS_RE = re.compile(r"^(?:[0-9a-fA-F]{2}[:-]?){5}[0-9a-fA-F]{2}$") DEVICE_TYPE_RE = re.compile(r"^[A-Za-z0-9]{3,25}$") diff --git a/tests/functional/test_models.py b/tests/functional/test_models.py index 73d445b77ce21cdc9fafc8b4a2bd26fc7fa5ec14..c5014860fc836f950e643001545b6d3708c8a23d 100644 --- a/tests/functional/test_models.py +++ b/tests/functional/test_models.py @@ -767,3 +767,35 @@ def test_task_awx_job_url(db, task_factory): assert task4.awx_job_url is None task5 = task_factory(awx_resource="inventory_source", awx_job_id=12) assert task5.awx_job_url == "https://awx.example.org/#/jobs/inventory/12" + + +@pytest.mark.parametrize("length", (1, 21, 50)) +def test_hostname_invalid_length(db, host_factory, length): + with pytest.raises(ValidationError) as excinfo: + host_factory(name="x" * length) + assert r"Host name shall match [a-z0-9\-]{2,20}" in str(excinfo.value) + + +@pytest.mark.parametrize("name", ("my_host", "host@", "foo:bar", "U02.K02")) +def test_hostname_invalid_characters(db, host_factory, name): + with pytest.raises(ValidationError) as excinfo: + host_factory(name=name) + assert r"Host name shall match [a-z0-9\-]{2,20}" in str(excinfo.value) + + +@pytest.mark.parametrize("length", (1, 26, 50)) +def test_interface_name_invalid_length(db, interface_factory, length): + with pytest.raises(ValidationError) as excinfo: + interface_factory(name="x" * length) + assert r"Interface name shall match [a-z0-9\-]{2,25}" in str(excinfo.value) + + +def test_interface_name_length(db, host_factory, interface_factory): + hostname = "x" * 20 + interface_name = hostname + "-yyyy" + host1 = host_factory(name=hostname) + interface_factory(name=interface_name, host=host1) + assert host1.interfaces[0].name == interface_name + with pytest.raises(ValidationError) as excinfo: + interface_factory(name=interface_name + "y", host=host1) + assert r"Interface name shall match [a-z0-9\-]{2,25}" in str(excinfo.value)