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

Change interface mac select field to string field

One should be able to enter a MAC when creating/editing an interface.
parent 8e5f1894
No related branches found
No related tags found
No related merge requests found
......@@ -9,7 +9,10 @@ This module implements helpers functions for the models.
:license: BSD 2-Clause, see LICENSE for more details.
"""
import sqlalchemy as sa
from flask_wtf import FlaskForm
from .extensions import db
from . import models
class CSEntryForm(FlaskForm):
......@@ -25,3 +28,21 @@ class CSEntryForm(FlaskForm):
super().__init__(obj=obj, **kwargs)
else:
super().__init__(formdata=formdata, obj=obj, **kwargs)
def associate_mac_to_interface(address, interface):
"""Associate the given address to an interface
The Mac is retrieved if it exists or created otherwise
:param address: Mac address string
:param interface: Interface instance
"""
if not address:
return
try:
mac = models.Mac.query.filter_by(address=address).one()
except sa.orm.exc.NoResultFound:
mac = models.Mac(address=address)
db.session.add(mac)
mac.interfaces.append(interface)
......@@ -13,7 +13,8 @@ from flask_login import current_user
from wtforms import (SelectField, StringField, TextAreaField, IntegerField,
SelectMultipleField, BooleanField, validators)
from ..helpers import CSEntryForm
from ..validators import Unique, RegexpList, IPNetwork, HOST_NAME_RE, VLAN_NAME_RE
from ..validators import (Unique, RegexpList, IPNetwork, HOST_NAME_RE,
VLAN_NAME_RE, MAC_ADDRESS_RE)
from .. import utils, models
......@@ -103,7 +104,10 @@ class InterfaceForm(CSEntryForm):
validators.Regexp(HOST_NAME_RE),
Unique(models.Interface)],
filters=[utils.lowercase_field])
mac_id = SelectField('MAC', coerce=utils.coerce_to_str_or_none)
mac_address = StringField(
'MAC',
validators=[validators.Optional(),
validators.Regexp(MAC_ADDRESS_RE, message='Invalid MAC address')])
cnames_string = StringField(
'Cnames',
description='space separated list of cnames (must be 2-20 characters long and contain only letters, numbers and dash)',
......@@ -121,7 +125,6 @@ class InterfaceForm(CSEntryForm):
network_query = models.Network.query.filter(models.Network.admin_only.is_(False))
self.network_id.choices = utils.get_model_choices(models.Network, allow_none=False,
attr='vlan_name', query=network_query)
self.mac_id.choices = utils.get_model_choices(models.Mac, allow_none=True, attr='address')
self.tags.choices = utils.get_model_choices(models.Tag, allow_none=True, attr='name')
......
......@@ -18,7 +18,7 @@ from .forms import (HostForm, InterfaceForm, HostInterfaceForm, NetworkForm,
NetworkScopeForm)
from ..extensions import db
from ..decorators import login_groups_accepted
from .. import models, utils
from .. import models, utils, helpers
bp = Blueprint('network', __name__)
......@@ -58,9 +58,9 @@ def create_host():
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()]
helpers.associate_mac_to_interface(form.mac_address.data, interface)
host.interfaces = [interface]
current_app.logger.debug(f'Trying to create: {host!r}')
db.session.add(host)
......@@ -123,9 +123,9 @@ def create_interface(hostname):
name=form.interface_name.data,
ip=form.ip.data,
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()]
helpers.associate_mac_to_interface(form.mac_address.data, interface)
current_app.logger.debug(f'Trying to create: {interface!r}')
db.session.add(interface)
try:
......@@ -145,8 +145,13 @@ def create_interface(hostname):
def edit_interface(name):
interface = models.Interface.query.filter_by(name=name).first_or_404()
cnames_string = ' '.join([str(cname) for cname in interface.cnames])
try:
mac_address = interface.mac.address
except AttributeError:
mac_address = ''
form = InterfaceForm(request.form, obj=interface,
interface_name=interface.name,
mac_address=mac_address,
cnames_string=cnames_string)
ips = [interface.ip]
ips.extend([str(address) for address in interface.network.available_ips()])
......@@ -155,7 +160,15 @@ def edit_interface(name):
interface.name = form.interface_name.data
interface.ip = form.ip.data
interface.network_id = form.network_id.data
interface.mac_id = form.mac_id.data
if form.mac_address.data:
if form.mac_address.data != mac_address:
# The MAC changed - add the new one to the interface
# that will remove the association to the previous one
helpers.associate_mac_to_interface(form.mac_address.data, interface)
# else: nothing to do (address didn't change)
else:
# No MAC associated
interface.mac_id = None
# Delete the cnames that have been removed
new_cnames_string = form.cnames_string.data.split()
for (index, cname) in enumerate(interface.cnames):
......
......@@ -13,7 +13,7 @@
{{ render_field(form.network_id) }}
{{ render_field(form.ip) }}
{{ render_field(form.interface_name, class_="text-lowercase") }}
{{ render_field(form.mac_id) }}
{{ render_field(form.mac_address) }}
{{ render_field(form.cnames_string) }}
{{ render_field(form.tags) }}
<div class="form-group row">
......
......@@ -23,7 +23,7 @@
{{ render_field(form.interface_name, class_="text-lowercase") }}
{{ render_field(form.network_id) }}
{{ render_field(form.ip) }}
{{ render_field(form.mac_id) }}
{{ render_field(form.mac_address) }}
{{ render_field(form.cnames_string) }}
{{ render_field(form.tags) }}
<div class="form-group row">
......
......@@ -26,7 +26,7 @@
{{ render_field(form.interface_name, class_="text-lowercase") }}
{{ render_field(form.network_id) }}
{{ render_field(form.ip) }}
{{ render_field(form.mac_id) }}
{{ render_field(form.mac_address) }}
{{ render_field(form.cnames_string) }}
{{ render_field(form.tags) }}
<div class="form-group row">
......
......@@ -17,7 +17,7 @@ from wtforms import ValidationError
ICS_ID_RE = re.compile('[A-Z]{3}[0-9]{3}')
HOST_NAME_RE = re.compile('^[a-z0-9\-]{2,20}$')
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}$')
class IPNetwork:
......
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