Skip to content
Snippets Groups Projects
Commit 871e5757 authored by Benjamin Bertrand's avatar Benjamin Bertrand
Browse files

Add tag and device type validation

Tags and device_types are used as key in Ansible roles.
They shouldn't contain any spaces to avoid issues.

JIRA INFRA-334
parent 4d7126e1
No related branches found
No related tags found
No related merge requests found
...@@ -21,8 +21,8 @@ defaults = [ ...@@ -21,8 +21,8 @@ defaults = [
models.Action(name='Set as parent'), models.Action(name='Set as parent'),
models.Action(name='Update'), models.Action(name='Update'),
models.DeviceType(name='Physical Machine'), models.DeviceType(name='PhysicalMachine'),
models.DeviceType(name='Virtual Machine'), models.DeviceType(name='VirtualMachine'),
models.DeviceType(name='Network'), models.DeviceType(name='Network'),
models.DeviceType(name='MicroTCA'), models.DeviceType(name='MicroTCA'),
models.DeviceType(name='VME'), models.DeviceType(name='VME'),
......
...@@ -23,7 +23,8 @@ from flask_login import UserMixin ...@@ -23,7 +23,8 @@ from flask_login import UserMixin
from wtforms import ValidationError from wtforms import ValidationError
from .extensions import db, login_manager, ldap_manager, cache from .extensions import db, login_manager, ldap_manager, cache
from .plugins import FlaskUserPlugin from .plugins import FlaskUserPlugin
from .validators import ICS_ID_RE, HOST_NAME_RE, VLAN_NAME_RE, MAC_ADDRESS_RE from .validators import (ICS_ID_RE, HOST_NAME_RE, VLAN_NAME_RE, MAC_ADDRESS_RE,
DEVICE_TYPE_RE, TAG_RE)
from . import utils from . import utils
...@@ -594,6 +595,14 @@ interfacetags_table = db.Table( ...@@ -594,6 +595,14 @@ interfacetags_table = db.Table(
class Tag(QRCodeMixin, db.Model): class Tag(QRCodeMixin, db.Model):
admin_only = db.Column(db.Boolean, nullable=False, default=False) admin_only = db.Column(db.Boolean, nullable=False, default=False)
@validates('name')
def validate_name(self, key, string):
"""Ensure the name field matches the required format"""
if string is not None:
if TAG_RE.fullmatch(string) is None:
raise ValidationError(f"'{string}' is an invalid tag name")
return string
class DeviceType(db.Model): class DeviceType(db.Model):
__tablename__ = 'device_type' __tablename__ = 'device_type'
...@@ -602,6 +611,14 @@ class DeviceType(db.Model): ...@@ -602,6 +611,14 @@ class DeviceType(db.Model):
hosts = db.relationship('Host', backref='device_type') hosts = db.relationship('Host', backref='device_type')
@validates('name')
def validate_name(self, key, string):
"""Ensure the name field matches the required format"""
if string is not None:
if DEVICE_TYPE_RE.fullmatch(string) is None:
raise ValidationError(f"'{string}' is an invalid device type name")
return string
def __str__(self): def __str__(self):
return self.name return self.name
......
...@@ -18,6 +18,8 @@ ICS_ID_RE = re.compile('[A-Z]{3}[0-9]{3}') ...@@ -18,6 +18,8 @@ ICS_ID_RE = re.compile('[A-Z]{3}[0-9]{3}')
HOST_NAME_RE = re.compile('^[a-z0-9\-]{2,20}$') HOST_NAME_RE = re.compile('^[a-z0-9\-]{2,20}$')
VLAN_NAME_RE = re.compile('^[A-Za-z0-9\-]{3,25}$') VLAN_NAME_RE = re.compile('^[A-Za-z0-9\-]{3,25}$')
MAC_ADDRESS_RE = re.compile('^(?:[0-9a-fA-F]{2}[:-]?){5}[0-9a-fA-F]{2}$') MAC_ADDRESS_RE = re.compile('^(?:[0-9a-fA-F]{2}[:-]?){5}[0-9a-fA-F]{2}$')
DEVICE_TYPE_RE = re.compile('^[A-Za-z0-9]{3,25}$')
TAG_RE = DEVICE_TYPE_RE
class NoValidateSelectField(SelectField): class NoValidateSelectField(SelectField):
......
"""remove spaces from device_type
Revision ID: f5a605c0c835
Revises: ea606be23b95
Create Date: 2018-05-22 13:41:28.137611
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'f5a605c0c835'
down_revision = 'ea606be23b95'
branch_labels = None
depends_on = None
def upgrade():
device_type = sa.sql.table('device_type', sa.sql.column('id'), sa.sql.column('name'))
op.execute(device_type.update().where(device_type.c.name == 'Physical Machine').values(name='PhysicalMachine'))
op.execute(device_type.update().where(device_type.c.name == 'Virtual Machine').values(name='VirtualMachine'))
def downgrade():
device_type = sa.sql.table('device_type', sa.sql.column('id'), sa.sql.column('name'))
op.execute(device_type.update().where(device_type.c.name == 'PhysicalMachine').values(name='Physical Machine'))
op.execute(device_type.update().where(device_type.c.name == 'VirtualMachine').values(name='Virtual Machine'))
...@@ -32,6 +32,7 @@ register(factories.HostFactory) ...@@ -32,6 +32,7 @@ register(factories.HostFactory)
register(factories.MacFactory) register(factories.MacFactory)
register(factories.DomainFactory) register(factories.DomainFactory)
register(factories.CnameFactory) register(factories.CnameFactory)
register(factories.TagFactory)
@pytest.fixture(scope='session') @pytest.fixture(scope='session')
......
...@@ -189,3 +189,12 @@ class CnameFactory(factory.alchemy.SQLAlchemyModelFactory): ...@@ -189,3 +189,12 @@ class CnameFactory(factory.alchemy.SQLAlchemyModelFactory):
name = factory.Sequence(lambda n: f'host{n}') name = factory.Sequence(lambda n: f'host{n}')
interface = factory.SubFactory(InterfaceFactory) interface = factory.SubFactory(InterfaceFactory)
user = factory.SubFactory(UserFactory) user = factory.SubFactory(UserFactory)
class TagFactory(factory.alchemy.SQLAlchemyModelFactory):
class Meta:
model = models.Tag
sqlalchemy_session = common.Session
sqlalchemy_session_persistence = 'commit'
name = factory.Sequence(lambda n: f'Tag{n}')
...@@ -121,3 +121,19 @@ def test_manufacturer_favorite_users(user_factory, manufacturer_factory): ...@@ -121,3 +121,19 @@ def test_manufacturer_favorite_users(user_factory, manufacturer_factory):
assert user2 in manufacturer2.favorite_users assert user2 in manufacturer2.favorite_users
assert user2 not in manufacturer1.favorite_users assert user2 not in manufacturer1.favorite_users
assert user3 in manufacturer1.favorite_users assert user3 in manufacturer1.favorite_users
def test_device_type_validation(device_type_factory):
device_type = device_type_factory(name='PhysicalMachine')
assert device_type.name == 'PhysicalMachine'
with pytest.raises(ValidationError) as excinfo:
device_type = device_type_factory(name='Physical Machine')
assert "'Physical Machine' is an invalid device type name" in str(excinfo.value)
def test_tag_validation(tag_factory):
tag = tag_factory(name='IOC')
assert tag.name == 'IOC'
with pytest.raises(ValidationError) as excinfo:
tag = tag_factory(name='My tag')
assert "'My tag' is an invalid tag name" in str(excinfo.value)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment