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. ...@@ -9,7 +9,10 @@ This module implements helpers functions for the models.
:license: BSD 2-Clause, see LICENSE for more details. :license: BSD 2-Clause, see LICENSE for more details.
""" """
import sqlalchemy as sa
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from .extensions import db
from . import models
class CSEntryForm(FlaskForm): class CSEntryForm(FlaskForm):
...@@ -25,3 +28,21 @@ class CSEntryForm(FlaskForm): ...@@ -25,3 +28,21 @@ class CSEntryForm(FlaskForm):
super().__init__(obj=obj, **kwargs) super().__init__(obj=obj, **kwargs)
else: else:
super().__init__(formdata=formdata, obj=obj, **kwargs) 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 ...@@ -13,7 +13,8 @@ from flask_login import current_user
from wtforms import (SelectField, StringField, TextAreaField, IntegerField, from wtforms import (SelectField, StringField, TextAreaField, IntegerField,
SelectMultipleField, BooleanField, validators) SelectMultipleField, BooleanField, validators)
from ..helpers import CSEntryForm 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 from .. import utils, models
...@@ -103,7 +104,10 @@ class InterfaceForm(CSEntryForm): ...@@ -103,7 +104,10 @@ class InterfaceForm(CSEntryForm):
validators.Regexp(HOST_NAME_RE), validators.Regexp(HOST_NAME_RE),
Unique(models.Interface)], Unique(models.Interface)],
filters=[utils.lowercase_field]) 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_string = StringField(
'Cnames', 'Cnames',
description='space separated list of cnames (must be 2-20 characters long and contain only letters, numbers and dash)', 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): ...@@ -121,7 +125,6 @@ class InterfaceForm(CSEntryForm):
network_query = models.Network.query.filter(models.Network.admin_only.is_(False)) 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, self.network_id.choices = utils.get_model_choices(models.Network, allow_none=False,
attr='vlan_name', query=network_query) 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') 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, ...@@ -18,7 +18,7 @@ from .forms import (HostForm, InterfaceForm, HostInterfaceForm, NetworkForm,
NetworkScopeForm) NetworkScopeForm)
from ..extensions import db from ..extensions import db
from ..decorators import login_groups_accepted from ..decorators import login_groups_accepted
from .. import models, utils from .. import models, utils, helpers
bp = Blueprint('network', __name__) bp = Blueprint('network', __name__)
...@@ -58,9 +58,9 @@ def create_host(): ...@@ -58,9 +58,9 @@ def create_host():
interface = models.Interface(name=form.interface_name.data, interface = models.Interface(name=form.interface_name.data,
ip=form.ip.data, ip=form.ip.data,
network_id=network_id, network_id=network_id,
mac_id=form.mac_id.data,
tags=tags) tags=tags)
interface.cnames = [models.Cname(name=name) for name in form.cnames_string.data.split()] 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] host.interfaces = [interface]
current_app.logger.debug(f'Trying to create: {host!r}') current_app.logger.debug(f'Trying to create: {host!r}')
db.session.add(host) db.session.add(host)
...@@ -123,9 +123,9 @@ def create_interface(hostname): ...@@ -123,9 +123,9 @@ def create_interface(hostname):
name=form.interface_name.data, name=form.interface_name.data,
ip=form.ip.data, ip=form.ip.data,
network_id=form.network_id.data, network_id=form.network_id.data,
mac_id=form.mac_id.data,
tags=tags) tags=tags)
interface.cnames = [models.Cname(name=name) for name in form.cnames_string.data.split()] 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}') current_app.logger.debug(f'Trying to create: {interface!r}')
db.session.add(interface) db.session.add(interface)
try: try:
...@@ -145,8 +145,13 @@ def create_interface(hostname): ...@@ -145,8 +145,13 @@ def create_interface(hostname):
def edit_interface(name): def edit_interface(name):
interface = models.Interface.query.filter_by(name=name).first_or_404() interface = models.Interface.query.filter_by(name=name).first_or_404()
cnames_string = ' '.join([str(cname) for cname in interface.cnames]) 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, form = InterfaceForm(request.form, obj=interface,
interface_name=interface.name, interface_name=interface.name,
mac_address=mac_address,
cnames_string=cnames_string) cnames_string=cnames_string)
ips = [interface.ip] ips = [interface.ip]
ips.extend([str(address) for address in interface.network.available_ips()]) ips.extend([str(address) for address in interface.network.available_ips()])
...@@ -155,7 +160,15 @@ def edit_interface(name): ...@@ -155,7 +160,15 @@ def edit_interface(name):
interface.name = form.interface_name.data interface.name = form.interface_name.data
interface.ip = form.ip.data interface.ip = form.ip.data
interface.network_id = form.network_id.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 # Delete the cnames that have been removed
new_cnames_string = form.cnames_string.data.split() new_cnames_string = form.cnames_string.data.split()
for (index, cname) in enumerate(interface.cnames): for (index, cname) in enumerate(interface.cnames):
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
{{ render_field(form.network_id) }} {{ render_field(form.network_id) }}
{{ render_field(form.ip) }} {{ render_field(form.ip) }}
{{ render_field(form.interface_name, class_="text-lowercase") }} {{ 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.cnames_string) }}
{{ render_field(form.tags) }} {{ render_field(form.tags) }}
<div class="form-group row"> <div class="form-group row">
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
{{ render_field(form.interface_name, class_="text-lowercase") }} {{ render_field(form.interface_name, class_="text-lowercase") }}
{{ render_field(form.network_id) }} {{ render_field(form.network_id) }}
{{ render_field(form.ip) }} {{ render_field(form.ip) }}
{{ render_field(form.mac_id) }} {{ render_field(form.mac_address) }}
{{ render_field(form.cnames_string) }} {{ render_field(form.cnames_string) }}
{{ render_field(form.tags) }} {{ render_field(form.tags) }}
<div class="form-group row"> <div class="form-group row">
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
{{ render_field(form.interface_name, class_="text-lowercase") }} {{ render_field(form.interface_name, class_="text-lowercase") }}
{{ render_field(form.network_id) }} {{ render_field(form.network_id) }}
{{ render_field(form.ip) }} {{ render_field(form.ip) }}
{{ render_field(form.mac_id) }} {{ render_field(form.mac_address) }}
{{ render_field(form.cnames_string) }} {{ render_field(form.cnames_string) }}
{{ render_field(form.tags) }} {{ render_field(form.tags) }}
<div class="form-group row"> <div class="form-group row">
......
...@@ -17,7 +17,7 @@ from wtforms import ValidationError ...@@ -17,7 +17,7 @@ from wtforms import ValidationError
ICS_ID_RE = re.compile('[A-Z]{3}[0-9]{3}') 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}$')
class IPNetwork: 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