From a49e002c1399d69c5506e3360b9abab06deec965 Mon Sep 17 00:00:00 2001
From: Benjamin Bertrand <benjamin.bertrand@esss.se>
Date: Tue, 19 Dec 2017 23:36:04 +0100
Subject: [PATCH] Add cnames field to interface form

Allow to create/delete cnames when creating/deleting interfaces
---
 app/models.py                               |  2 +-
 app/network/forms.py                        |  7 ++++-
 app/network/views.py                        | 33 ++++++++++++++++-----
 app/templates/network/create_host.html      |  1 +
 app/templates/network/create_interface.html |  1 +
 app/templates/network/edit_interface.html   |  1 +
 6 files changed, 35 insertions(+), 10 deletions(-)

diff --git a/app/models.py b/app/models.py
index 6577077..4eb7af5 100644
--- a/app/models.py
+++ b/app/models.py
@@ -564,7 +564,7 @@ class Mac(db.Model):
 class Cname(db.Model):
     id = db.Column(db.Integer, primary_key=True)
     name = db.Column(db.Text, nullable=False, unique=True)
-    interface_id = db.Column(db.Integer, db.ForeignKey('interface.id'), nullable=False, unique=True)
+    interface_id = db.Column(db.Integer, db.ForeignKey('interface.id'), nullable=False)
 
     def __str__(self):
         return str(self.name)
diff --git a/app/network/forms.py b/app/network/forms.py
index 7f563fe..8457381 100644
--- a/app/network/forms.py
+++ b/app/network/forms.py
@@ -13,7 +13,7 @@ from flask_login import current_user
 from wtforms import (SelectField, StringField, TextAreaField,
                      SelectMultipleField, BooleanField, validators)
 from ..helpers import CSEntryForm
-from ..validators import Unique, HOST_NAME_RE, VLAN_NAME_RE
+from ..validators import Unique, RegexpList, HOST_NAME_RE, VLAN_NAME_RE
 from .. import utils, models
 
 
@@ -90,6 +90,11 @@ class InterfaceForm(CSEntryForm):
                     Unique(models.Interface)],
         filters=[utils.lowercase_field])
     mac_id = SelectField('MAC', coerce=utils.coerce_to_str_or_none)
+    cnames_string = StringField(
+        'Cnames',
+        description='space separated list of cnames (must be 2-20 characters long and contain only letters, numbers and dash)',
+        validators=[validators.Optional(),
+                    RegexpList(HOST_NAME_RE)])
     tags = SelectMultipleField('Tags', coerce=utils.coerce_to_str_or_none,
                                validators=[validate_tags])
 
diff --git a/app/network/views.py b/app/network/views.py
index 3ffb830..0caaa91 100644
--- a/app/network/views.py
+++ b/app/network/views.py
@@ -54,13 +54,13 @@ def create_host():
         # and do the filtering here
         all_tags = models.Tag.query.all()
         tags = [tag for tag in all_tags if str(tag.id) in form.tags.data]
-        host.interfaces = [
-            models.Interface(name=form.interface_name.data,
-                             ip=form.ip.data,
-                             network_id=network_id,
-                             mac_id=form.mac_id.data,
-                             tags=tags)
-        ]
+        interface = models.Interface(name=form.interface_name.data,
+                                     ip=form.ip.data,
+                                     network_id=network_id,
+                                     mac_id=form.mac_id.data,
+                                     tags=tags)
+        interface.cnames = [models.Cname(name=name) for name in form.cnames_string.data.split()]
+        host.interfaces = [interface]
         current_app.logger.debug(f'Trying to create: {host!r}')
         db.session.add(host)
         try:
@@ -124,6 +124,7 @@ def create_interface(hostname):
                                      network_id=form.network_id.data,
                                      mac_id=form.mac_id.data,
                                      tags=tags)
+        interface.cnames = [models.Cname(name=name) for name in form.cnames_string.data.split()]
         current_app.logger.debug(f'Trying to create: {interface!r}')
         db.session.add(interface)
         try:
@@ -142,7 +143,10 @@ def create_interface(hostname):
 @login_groups_accepted('admin', 'create')
 def edit_interface(name):
     interface = models.Interface.query.filter_by(name=name).first_or_404()
-    form = InterfaceForm(request.form, obj=interface, interface_name=interface.name)
+    cnames_string = ' '.join([str(cname) for cname in interface.cnames])
+    form = InterfaceForm(request.form, obj=interface,
+                         interface_name=interface.name,
+                         cnames_string=cnames_string)
     ips = [interface.ip]
     ips.extend([str(address) for address in interface.network.available_ips()])
     form.ip.choices = utils.get_choices(ips)
@@ -151,6 +155,19 @@ def edit_interface(name):
         interface.ip = form.ip.data
         interface.network_id = form.network_id.data
         interface.mac_id = form.mac_id.data
+        # Delete the cnames that have been removed
+        new_cnames_string = form.cnames_string.data.split()
+        for (index, cname) in enumerate(interface.cnames):
+            if cname.name not in new_cnames_string:
+                current_app.logger.debug(f'Deleting cname: {cname}')
+                interface.cnames.pop(index)
+                db.session.delete(cname)
+        # Add new cnames
+        for name in new_cnames_string:
+            if name not in cnames_string:
+                cname = models.Cname(name=name)
+                current_app.logger.debug(f'Creating cname: {cname}')
+                interface.cnames.append(cname)
         all_tags = models.Tag.query.all()
         tags = [tag for tag in all_tags if str(tag.id) in form.tags.data]
         interface.tags = tags
diff --git a/app/templates/network/create_host.html b/app/templates/network/create_host.html
index a89e989..b2b0548 100644
--- a/app/templates/network/create_host.html
+++ b/app/templates/network/create_host.html
@@ -14,6 +14,7 @@
     {{ render_field(form.ip) }}
     {{ render_field(form.interface_name, class_="text-lowercase") }}
     {{ render_field(form.mac_id) }}
+    {{ render_field(form.cnames_string) }}
     {{ render_field(form.tags) }}
     <div class="form-group row">
       <div class="col-sm-10">
diff --git a/app/templates/network/create_interface.html b/app/templates/network/create_interface.html
index 5fadfb9..01f4688 100644
--- a/app/templates/network/create_interface.html
+++ b/app/templates/network/create_interface.html
@@ -24,6 +24,7 @@
     {{ render_field(form.network_id) }}
     {{ render_field(form.ip) }}
     {{ render_field(form.mac_id) }}
+    {{ render_field(form.cnames_string) }}
     {{ render_field(form.tags) }}
     <div class="form-group row">
       <div class="col-sm-10">
diff --git a/app/templates/network/edit_interface.html b/app/templates/network/edit_interface.html
index a7cfe3e..621feb7 100644
--- a/app/templates/network/edit_interface.html
+++ b/app/templates/network/edit_interface.html
@@ -27,6 +27,7 @@
     {{ render_field(form.network_id) }}
     {{ render_field(form.ip) }}
     {{ render_field(form.mac_id) }}
+    {{ render_field(form.cnames_string) }}
     {{ render_field(form.tags) }}
     <div class="form-group row">
       <div class="col-sm-10">
-- 
GitLab