|
|
@ -20,24 +20,31 @@ |
|
|
# You should have received a copy of the GNU General Public License along |
|
|
# You should have received a copy of the GNU General Public License along |
|
|
# with this program; if not, write to the Free Software Foundation, Inc., |
|
|
# with this program; if not, write to the Free Software Foundation, Inc., |
|
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
|
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
|
|
|
|
|
""" |
|
|
|
|
|
Definition des modèles de l'application topologie. |
|
|
|
|
|
|
|
|
|
|
|
On défini les models suivants : |
|
|
|
|
|
|
|
|
|
|
|
- stack (id, id_min, id_max et nom) regrouppant les switches |
|
|
|
|
|
- switch : nom, nombre de port, et interface |
|
|
|
|
|
machine correspondante (mac, ip, etc) (voir machines.models.interface) |
|
|
|
|
|
- Port: relié à un switch parent par foreign_key, numero du port, |
|
|
|
|
|
relié de façon exclusive à un autre port, une machine |
|
|
|
|
|
(serveur ou borne) ou une prise murale |
|
|
|
|
|
- room : liste des prises murales, nom et commentaire de l'état de |
|
|
|
|
|
la prise |
|
|
|
|
|
""" |
|
|
|
|
|
|
|
|
from __future__ import unicode_literals |
|
|
from __future__ import unicode_literals |
|
|
|
|
|
|
|
|
from django.db import models |
|
|
from django.db import models |
|
|
from django.db.models.signals import post_delete |
|
|
from django.db.models.signals import post_delete |
|
|
from django.dispatch import receiver |
|
|
from django.dispatch import receiver |
|
|
from django.forms import ModelForm, Form |
|
|
|
|
|
from django.contrib.contenttypes.models import ContentType |
|
|
|
|
|
from django.contrib.contenttypes.fields import GenericForeignKey |
|
|
|
|
|
from django.core.exceptions import ValidationError |
|
|
from django.core.exceptions import ValidationError |
|
|
import reversion |
|
|
|
|
|
|
|
|
|
|
|
from machines.models import Vlan |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Stack(models.Model): |
|
|
class Stack(models.Model): |
|
|
""" Un objet stack. Regrouppe des switchs en foreign key |
|
|
"""Un objet stack. Regrouppe des switchs en foreign key |
|
|
, contient une id de stack, un switch id min et max dans |
|
|
,contient une id de stack, un switch id min et max dans |
|
|
le stack""" |
|
|
le stack""" |
|
|
PRETTY_NAME = "Stack de switchs" |
|
|
PRETTY_NAME = "Stack de switchs" |
|
|
|
|
|
|
|
|
@ -59,28 +66,40 @@ class Stack(models.Model): |
|
|
def clean(self): |
|
|
def clean(self): |
|
|
""" Verification que l'id_max < id_min""" |
|
|
""" Verification que l'id_max < id_min""" |
|
|
if self.member_id_max < self.member_id_min: |
|
|
if self.member_id_max < self.member_id_min: |
|
|
raise ValidationError({'member_id_max':"L'id maximale est inférieure à l'id minimale"}) |
|
|
raise ValidationError({'member_id_max':"L'id maximale est\ |
|
|
|
|
|
inférieure à l'id minimale"}) |
|
|
|
|
|
|
|
|
class Switch(models.Model): |
|
|
class Switch(models.Model): |
|
|
""" Definition d'un switch. Contient un nombre de ports (number), |
|
|
""" Definition d'un switch. Contient un nombre de ports (number), |
|
|
un emplacement (location), un stack parent (optionnel, stack) |
|
|
un emplacement (location), un stack parent (optionnel, stack) |
|
|
et un id de membre dans le stack (stack_member_id) |
|
|
et un id de membre dans le stack (stack_member_id) |
|
|
relié en onetoone à une interface |
|
|
relié en onetoone à une interface |
|
|
Pourquoi ne pas avoir fait hériter switch de interface ? |
|
|
Pourquoi ne pas avoir fait hériter switch de interface ? |
|
|
Principalement par méconnaissance de la puissance de cette façon de faire. |
|
|
Principalement par méconnaissance de la puissance de cette façon de faire. |
|
|
Ceci étant entendu, django crée en interne un onetoone, ce qui a un |
|
|
Ceci étant entendu, django crée en interne un onetoone, ce qui a un |
|
|
effet identique avec ce que l'on fait ici""" |
|
|
effet identique avec ce que l'on fait ici |
|
|
|
|
|
|
|
|
|
|
|
Validation au save que l'id du stack est bien dans le range id_min |
|
|
|
|
|
id_max de la stack parente""" |
|
|
PRETTY_NAME = "Switch / Commutateur" |
|
|
PRETTY_NAME = "Switch / Commutateur" |
|
|
|
|
|
|
|
|
switch_interface = models.OneToOneField('machines.Interface', on_delete=models.CASCADE) |
|
|
switch_interface = models.OneToOneField( |
|
|
|
|
|
'machines.Interface', |
|
|
|
|
|
on_delete=models.CASCADE |
|
|
|
|
|
) |
|
|
location = models.CharField(max_length=255) |
|
|
location = models.CharField(max_length=255) |
|
|
number = models.IntegerField() |
|
|
number = models.IntegerField() |
|
|
details = models.CharField(max_length=255, blank=True) |
|
|
details = models.CharField(max_length=255, blank=True) |
|
|
stack = models.ForeignKey(Stack, blank=True, null=True, on_delete=models.SET_NULL) |
|
|
stack = models.ForeignKey( |
|
|
|
|
|
Stack, |
|
|
|
|
|
blank=True, |
|
|
|
|
|
null=True, |
|
|
|
|
|
on_delete=models.SET_NULL |
|
|
|
|
|
) |
|
|
stack_member_id = models.IntegerField(blank=True, null=True) |
|
|
stack_member_id = models.IntegerField(blank=True, null=True) |
|
|
|
|
|
|
|
|
class Meta: |
|
|
class Meta: |
|
|
unique_together = ('stack','stack_member_id') |
|
|
unique_together = ('stack', 'stack_member_id') |
|
|
|
|
|
|
|
|
def __str__(self): |
|
|
def __str__(self): |
|
|
return str(self.location) + ' ' + str(self.switch_interface) |
|
|
return str(self.location) + ' ' + str(self.switch_interface) |
|
|
@ -89,41 +108,65 @@ class Switch(models.Model): |
|
|
""" Verifie que l'id stack est dans le bon range""" |
|
|
""" Verifie que l'id stack est dans le bon range""" |
|
|
if self.stack is not None: |
|
|
if self.stack is not None: |
|
|
if self.stack_member_id is not None: |
|
|
if self.stack_member_id is not None: |
|
|
if (self.stack_member_id > self.stack.member_id_max) or (self.stack_member_id < self.stack.member_id_min): |
|
|
if (self.stack_member_id > self.stack.member_id_max) or\ |
|
|
raise ValidationError({'stack_member_id': "L'id de ce switch est en dehors des bornes permises pas la stack"}) |
|
|
(self.stack_member_id < self.stack.member_id_min): |
|
|
|
|
|
raise ValidationError({'stack_member_id': "L'id de ce\ |
|
|
|
|
|
switch est en dehors des bornes permises pas la stack"}) |
|
|
else: |
|
|
else: |
|
|
raise ValidationError({'stack_member_id': "L'id dans la stack ne peut être nul"}) |
|
|
raise ValidationError({'stack_member_id': "L'id dans la stack\ |
|
|
|
|
|
ne peut être nul"}) |
|
|
|
|
|
|
|
|
class Port(models.Model): |
|
|
class Port(models.Model): |
|
|
""" Definition d'un port. Relié à un switch(foreign_key), |
|
|
""" Definition d'un port. Relié à un switch(foreign_key), |
|
|
un port peut etre relié de manière exclusive à : |
|
|
un port peut etre relié de manière exclusive à : |
|
|
- une chambre (room) |
|
|
- une chambre (room) |
|
|
- une machine (serveur etc) (machine_interface) |
|
|
- une machine (serveur etc) (machine_interface) |
|
|
- un autre port (uplink) (related) |
|
|
- un autre port (uplink) (related) |
|
|
Champs supplémentaires : |
|
|
Champs supplémentaires : |
|
|
- RADIUS (mode STRICT : connexion sur port uniquement si machine |
|
|
- RADIUS (mode STRICT : connexion sur port uniquement si machine |
|
|
d'un adhérent à jour de cotisation et que la chambre est également à jour de cotisation |
|
|
d'un adhérent à jour de cotisation et que la chambre est également à |
|
|
|
|
|
jour de cotisation |
|
|
mode COMMON : vérification uniquement du statut de la machine |
|
|
mode COMMON : vérification uniquement du statut de la machine |
|
|
mode NO : accepte toute demande venant du port et place sur le vlan normal |
|
|
mode NO : accepte toute demande venant du port et place sur le vlan normal |
|
|
mode BLOQ : rejet de toute authentification |
|
|
mode BLOQ : rejet de toute authentification |
|
|
- vlan_force : override la politique générale de placement vlan, permet |
|
|
- vlan_force : override la politique générale de placement vlan, permet |
|
|
de forcer un port sur un vlan particulier. S'additionne à la politique |
|
|
de forcer un port sur un vlan particulier. S'additionne à la politique |
|
|
RADIUS""" |
|
|
RADIUS""" |
|
|
PRETTY_NAME = "Port de switch" |
|
|
PRETTY_NAME = "Port de switch" |
|
|
STATES = ( |
|
|
STATES = ( |
|
|
('NO', 'NO'), |
|
|
('NO', 'NO'), |
|
|
('STRICT', 'STRICT'), |
|
|
('STRICT', 'STRICT'), |
|
|
('BLOQ', 'BLOQ'), |
|
|
('BLOQ', 'BLOQ'), |
|
|
('COMMON', 'COMMON'), |
|
|
('COMMON', 'COMMON'), |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
switch = models.ForeignKey('Switch', related_name="ports") |
|
|
switch = models.ForeignKey('Switch', related_name="ports") |
|
|
port = models.IntegerField() |
|
|
port = models.IntegerField() |
|
|
room = models.ForeignKey('Room', on_delete=models.PROTECT, blank=True, null=True) |
|
|
room = models.ForeignKey( |
|
|
machine_interface = models.ForeignKey('machines.Interface', on_delete=models.SET_NULL, blank=True, null=True) |
|
|
'Room', |
|
|
related = models.OneToOneField('self', null=True, blank=True, related_name='related_port') |
|
|
on_delete=models.PROTECT, |
|
|
|
|
|
blank=True, |
|
|
|
|
|
null=True |
|
|
|
|
|
) |
|
|
|
|
|
machine_interface = models.ForeignKey( |
|
|
|
|
|
'machines.Interface', |
|
|
|
|
|
on_delete=models.SET_NULL, |
|
|
|
|
|
blank=True, |
|
|
|
|
|
null=True |
|
|
|
|
|
) |
|
|
|
|
|
related = models.OneToOneField( |
|
|
|
|
|
'self', |
|
|
|
|
|
null=True, |
|
|
|
|
|
blank=True, |
|
|
|
|
|
related_name='related_port' |
|
|
|
|
|
) |
|
|
radius = models.CharField(max_length=32, choices=STATES, default='NO') |
|
|
radius = models.CharField(max_length=32, choices=STATES, default='NO') |
|
|
vlan_force = models.ForeignKey('machines.Vlan', on_delete=models.SET_NULL, blank=True, null=True) |
|
|
vlan_force = models.ForeignKey( |
|
|
|
|
|
'machines.Vlan', |
|
|
|
|
|
on_delete=models.SET_NULL, |
|
|
|
|
|
blank=True, |
|
|
|
|
|
null=True |
|
|
|
|
|
) |
|
|
details = models.CharField(max_length=255, blank=True) |
|
|
details = models.CharField(max_length=255, blank=True) |
|
|
|
|
|
|
|
|
class Meta: |
|
|
class Meta: |
|
|
@ -134,7 +177,7 @@ class Port(models.Model): |
|
|
related_port = self.related |
|
|
related_port = self.related |
|
|
related_port.related = self |
|
|
related_port.related = self |
|
|
related_port.save() |
|
|
related_port.save() |
|
|
|
|
|
|
|
|
def clean_port_related(self): |
|
|
def clean_port_related(self): |
|
|
""" Supprime la relation related sur self""" |
|
|
""" Supprime la relation related sur self""" |
|
|
related_port = self.related_port |
|
|
related_port = self.related_port |
|
|
@ -142,23 +185,27 @@ class Port(models.Model): |
|
|
related_port.save() |
|
|
related_port.save() |
|
|
|
|
|
|
|
|
def clean(self): |
|
|
def clean(self): |
|
|
""" Verifie que un seul de chambre, interface_parent et related_port est rempli. |
|
|
""" Verifie que un seul de chambre, interface_parent et related_port |
|
|
Verifie que le related n'est pas le port lui-même.... |
|
|
est rempli. Verifie que le related n'est pas le port lui-même.... |
|
|
Verifie que le related n'est pas déjà occupé par une machine ou une chambre. Si |
|
|
Verifie que le related n'est pas déjà occupé par une machine ou une |
|
|
ce n'est pas le cas, applique la relation related |
|
|
chambre. Si ce n'est pas le cas, applique la relation related |
|
|
Si un port related point vers self, on nettoie la relation |
|
|
Si un port related point vers self, on nettoie la relation |
|
|
A priori pas d'autre solution que de faire ça à la main. A priori tout cela est dans |
|
|
A priori pas d'autre solution que de faire ça à la main. A priori |
|
|
un bloc transaction, donc pas de problème de cohérence""" |
|
|
tout cela est dans un bloc transaction, donc pas de problème de |
|
|
|
|
|
cohérence""" |
|
|
if hasattr(self, 'switch'): |
|
|
if hasattr(self, 'switch'): |
|
|
if self.port > self.switch.number: |
|
|
if self.port > self.switch.number: |
|
|
raise ValidationError("Ce port ne peut exister, numero trop élevé") |
|
|
raise ValidationError("Ce port ne peut exister, numero trop élevé") |
|
|
if self.room and self.machine_interface or self.room and self.related or self.machine_interface and self.related: |
|
|
if self.room and self.machine_interface or self.room and\ |
|
|
raise ValidationError("Chambre, interface et related_port sont mutuellement exclusifs") |
|
|
self.related or self.machine_interface and self.related: |
|
|
if self.related==self: |
|
|
raise ValidationError("Chambre, interface et related_port sont\ |
|
|
|
|
|
mutuellement exclusifs") |
|
|
|
|
|
if self.related == self: |
|
|
raise ValidationError("On ne peut relier un port à lui même") |
|
|
raise ValidationError("On ne peut relier un port à lui même") |
|
|
if self.related and not self.related.related: |
|
|
if self.related and not self.related.related: |
|
|
if self.related.machine_interface or self.related.room: |
|
|
if self.related.machine_interface or self.related.room: |
|
|
raise ValidationError("Le port relié est déjà occupé, veuillez le libérer avant de créer une relation") |
|
|
raise ValidationError("Le port relié est déjà occupé, veuillez\ |
|
|
|
|
|
le libérer avant de créer une relation") |
|
|
else: |
|
|
else: |
|
|
self.make_port_related() |
|
|
self.make_port_related() |
|
|
elif hasattr(self, 'related_port'): |
|
|
elif hasattr(self, 'related_port'): |
|
|
@ -168,7 +215,7 @@ class Port(models.Model): |
|
|
return str(self.switch) + " - " + str(self.port) |
|
|
return str(self.switch) + " - " + str(self.port) |
|
|
|
|
|
|
|
|
class Room(models.Model): |
|
|
class Room(models.Model): |
|
|
""" Une chambre/local contenant une prise murale""" |
|
|
"""Une chambre/local contenant une prise murale""" |
|
|
PRETTY_NAME = "Chambre/ Prise murale" |
|
|
PRETTY_NAME = "Chambre/ Prise murale" |
|
|
|
|
|
|
|
|
name = models.CharField(max_length=255, unique=True) |
|
|
name = models.CharField(max_length=255, unique=True) |
|
|
@ -176,10 +223,11 @@ class Room(models.Model): |
|
|
|
|
|
|
|
|
class Meta: |
|
|
class Meta: |
|
|
ordering = ['name'] |
|
|
ordering = ['name'] |
|
|
|
|
|
|
|
|
def __str__(self): |
|
|
def __str__(self): |
|
|
return str(self.name) |
|
|
return str(self.name) |
|
|
|
|
|
|
|
|
@receiver(post_delete, sender=Stack) |
|
|
@receiver(post_delete, sender=Stack) |
|
|
def stack_post_delete(sender, **kwargs): |
|
|
def stack_post_delete(sender, **kwargs): |
|
|
Switch.objects.filter(stack=None).update(stack_member_id = None) |
|
|
"""Vide les id des switches membres d'une stack supprimée""" |
|
|
|
|
|
Switch.objects.filter(stack=None).update(stack_member_id=None) |
|
|
|