mirror of
https://gitlab2.federez.net/re2o/re2o
synced 2024-09-12 01:03:09 +00:00
Pep8 et nettoyage
This commit is contained in:
parent
643c8235b0
commit
a9dcc6d9c4
1 changed files with 286 additions and 106 deletions
|
@ -23,44 +23,59 @@
|
|||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from datetime import timedelta
|
||||
import re
|
||||
from netaddr import mac_bare, EUI, IPSet, IPRange, IPNetwork, IPAddress
|
||||
|
||||
from django.db import models
|
||||
from django.db.models.signals import post_save, pre_delete, post_delete
|
||||
from django.db.models.signals import post_save, post_delete
|
||||
from django.dispatch import receiver
|
||||
from django.forms import ValidationError
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils import timezone
|
||||
from django.core.validators import MaxValueValidator
|
||||
|
||||
from macaddress.fields import MACAddressField
|
||||
from netaddr import mac_bare, EUI, IPSet, IPRange, IPNetwork, IPAddress
|
||||
from django.core.validators import MinValueValidator,MaxValueValidator
|
||||
import re
|
||||
from reversion import revisions as reversion
|
||||
from datetime import timedelta
|
||||
|
||||
|
||||
class Machine(models.Model):
|
||||
""" Class définissant une machine, object parent user, objets fils interfaces"""
|
||||
""" Class définissant une machine, object parent user, objets fils
|
||||
interfaces"""
|
||||
PRETTY_NAME = "Machine"
|
||||
|
||||
|
||||
user = models.ForeignKey('users.User', on_delete=models.PROTECT)
|
||||
name = models.CharField(max_length=255, help_text="Optionnel", blank=True, null=True)
|
||||
name = models.CharField(
|
||||
max_length=255,
|
||||
help_text="Optionnel",
|
||||
blank=True,
|
||||
null=True
|
||||
)
|
||||
active = models.BooleanField(default=True)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.user) + ' - ' + str(self.id) + ' - ' + str(self.name)
|
||||
return str(self.user) + ' - ' + str(self.id) + ' - ' + str(self.name)
|
||||
|
||||
|
||||
class MachineType(models.Model):
|
||||
""" Type de machine, relié à un type d'ip, affecté aux interfaces"""
|
||||
PRETTY_NAME = "Type de machine"
|
||||
|
||||
type = models.CharField(max_length=255)
|
||||
ip_type = models.ForeignKey('IpType', on_delete=models.PROTECT, blank=True, null=True)
|
||||
ip_type = models.ForeignKey(
|
||||
'IpType',
|
||||
on_delete=models.PROTECT,
|
||||
blank=True,
|
||||
null=True
|
||||
)
|
||||
|
||||
def all_interfaces(self):
|
||||
""" Renvoie toutes les interfaces (cartes réseaux) de type machinetype"""
|
||||
""" Renvoie toutes les interfaces (cartes réseaux) de type
|
||||
machinetype"""
|
||||
return Interface.objects.filter(type=self)
|
||||
|
||||
def __str__(self):
|
||||
return self.type
|
||||
return self.type
|
||||
|
||||
|
||||
class IpType(models.Model):
|
||||
""" Type d'ip, définissant un range d'ip, affecté aux machine types"""
|
||||
|
@ -71,14 +86,27 @@ class IpType(models.Model):
|
|||
need_infra = models.BooleanField(default=False)
|
||||
domaine_ip_start = models.GenericIPAddressField(protocol='IPv4')
|
||||
domaine_ip_stop = models.GenericIPAddressField(protocol='IPv4')
|
||||
prefix_v6 = models.GenericIPAddressField(protocol='IPv6', null=True, blank=True)
|
||||
vlan = models.ForeignKey('Vlan', on_delete=models.PROTECT, blank=True, null=True)
|
||||
ouverture_ports = models.ForeignKey('OuverturePortList', blank=True, null=True)
|
||||
prefix_v6 = models.GenericIPAddressField(
|
||||
protocol='IPv6',
|
||||
null=True,
|
||||
blank=True
|
||||
)
|
||||
vlan = models.ForeignKey(
|
||||
'Vlan',
|
||||
on_delete=models.PROTECT,
|
||||
blank=True,
|
||||
null=True
|
||||
)
|
||||
ouverture_ports = models.ForeignKey(
|
||||
'OuverturePortList',
|
||||
blank=True,
|
||||
null=True
|
||||
)
|
||||
|
||||
@cached_property
|
||||
def ip_range(self):
|
||||
""" Renvoie un objet IPRange à partir de l'objet IpType"""
|
||||
return IPRange(self.domaine_ip_start, end=self.domaine_ip_stop)
|
||||
""" Renvoie un objet IPRange à partir de l'objet IpType"""
|
||||
return IPRange(self.domaine_ip_start, end=self.domaine_ip_stop)
|
||||
|
||||
@cached_property
|
||||
def ip_set(self):
|
||||
|
@ -96,18 +124,22 @@ class IpType(models.Model):
|
|||
|
||||
def free_ip(self):
|
||||
""" Renvoie toutes les ip libres associées au type donné (self)"""
|
||||
return IpList.objects.filter(interface__isnull=True).filter(ip_type=self)
|
||||
return IpList.objects.filter(
|
||||
interface__isnull=True
|
||||
).filter(ip_type=self)
|
||||
|
||||
def gen_ip_range(self):
|
||||
""" Cree les IpList associées au type self. Parcours pédestrement et crée
|
||||
les ip une par une. Si elles existent déjà, met à jour le type associé
|
||||
à l'ip"""
|
||||
""" Cree les IpList associées au type self. Parcours pédestrement et
|
||||
crée les ip une par une. Si elles existent déjà, met à jour le type
|
||||
associé à l'ip"""
|
||||
# Creation du range d'ip dans les objets iplist
|
||||
networks = []
|
||||
for net in self.ip_range.cidrs():
|
||||
networks += net.iter_hosts()
|
||||
ip_obj = [IpList(ip_type=self, ipv4=str(ip)) for ip in networks]
|
||||
listes_ip = IpList.objects.filter(ipv4__in=[str(ip) for ip in networks])
|
||||
listes_ip = IpList.objects.filter(
|
||||
ipv4__in=[str(ip) for ip in networks]
|
||||
)
|
||||
# Si il n'y a pas d'ip, on les crée
|
||||
if not listes_ip:
|
||||
IpList.objects.bulk_create(ip_obj)
|
||||
|
@ -117,9 +149,11 @@ class IpType(models.Model):
|
|||
return
|
||||
|
||||
def del_ip_range(self):
|
||||
""" Methode dépréciée, IpList est en mode cascade et supprimé automatiquement"""
|
||||
""" Methode dépréciée, IpList est en mode cascade et supprimé
|
||||
automatiquement"""
|
||||
if Interface.objects.filter(ipv4__in=self.ip_objects()):
|
||||
raise ValidationError("Une ou plusieurs ip du range sont affectées, impossible de supprimer le range")
|
||||
raise ValidationError("Une ou plusieurs ip du range sont\
|
||||
affectées, impossible de supprimer le range")
|
||||
for ip in self.ip_objects():
|
||||
ip.delete()
|
||||
|
||||
|
@ -133,11 +167,13 @@ class IpType(models.Model):
|
|||
raise ValidationError("Domaine end doit être après start...")
|
||||
# On ne crée pas plus grand qu'un /16
|
||||
if self.ip_range.size > 65536:
|
||||
raise ValidationError("Le range est trop gros, vous ne devez pas créer plus grand qu'un /16")
|
||||
raise ValidationError("Le range est trop gros, vous ne devez\
|
||||
pas créer plus grand qu'un /16")
|
||||
# On check que les / ne se recoupent pas
|
||||
for element in IpType.objects.all().exclude(pk=self.pk):
|
||||
if not self.ip_set.isdisjoint(element.ip_set):
|
||||
raise ValidationError("Le range indiqué n'est pas disjoint des ranges existants")
|
||||
raise ValidationError("Le range indiqué n'est pas disjoint\
|
||||
des ranges existants")
|
||||
# On formate le prefix v6
|
||||
if self.prefix_v6:
|
||||
self.prefix_v6 = str(IPNetwork(self.prefix_v6 + '/64').network)
|
||||
|
@ -150,6 +186,7 @@ class IpType(models.Model):
|
|||
def __str__(self):
|
||||
return self.type
|
||||
|
||||
|
||||
class Vlan(models.Model):
|
||||
""" Un vlan : vlan_id et nom
|
||||
On limite le vlan id entre 0 et 4096, comme défini par la norme"""
|
||||
|
@ -162,8 +199,9 @@ class Vlan(models.Model):
|
|||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class Nas(models.Model):
|
||||
""" Les nas. Associé à un machine_type.
|
||||
""" Les nas. Associé à un machine_type.
|
||||
Permet aussi de régler le port_access_mode (802.1X ou mac-address) pour
|
||||
le radius. Champ autocapture de la mac à true ou false"""
|
||||
PRETTY_NAME = "Correspondance entre les nas et les machines connectées"
|
||||
|
@ -175,33 +213,53 @@ class Nas(models.Model):
|
|||
)
|
||||
|
||||
name = models.CharField(max_length=255, unique=True)
|
||||
nas_type = models.ForeignKey('MachineType', on_delete=models.PROTECT, related_name='nas_type')
|
||||
machine_type = models.ForeignKey('MachineType', on_delete=models.PROTECT, related_name='machinetype_on_nas')
|
||||
port_access_mode = models.CharField(choices=AUTH, default=default_mode, max_length=32)
|
||||
nas_type = models.ForeignKey(
|
||||
'MachineType',
|
||||
on_delete=models.PROTECT,
|
||||
related_name='nas_type'
|
||||
)
|
||||
machine_type = models.ForeignKey(
|
||||
'MachineType',
|
||||
on_delete=models.PROTECT,
|
||||
related_name='machinetype_on_nas'
|
||||
)
|
||||
port_access_mode = models.CharField(
|
||||
choices=AUTH,
|
||||
default=default_mode,
|
||||
max_length=32
|
||||
)
|
||||
autocapture_mac = models.BooleanField(default=False)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class Extension(models.Model):
|
||||
""" Extension dns type example.org. Précise si tout le monde peut l'utiliser,
|
||||
associé à un origin (ip d'origine)"""
|
||||
""" Extension dns type example.org. Précise si tout le monde peut
|
||||
l'utiliser, associé à un origin (ip d'origine)"""
|
||||
PRETTY_NAME = "Extensions dns"
|
||||
|
||||
name = models.CharField(max_length=255, unique=True)
|
||||
need_infra = models.BooleanField(default=False)
|
||||
origin = models.OneToOneField('IpList', on_delete=models.PROTECT, blank=True, null=True)
|
||||
origin = models.OneToOneField(
|
||||
'IpList',
|
||||
on_delete=models.PROTECT,
|
||||
blank=True,
|
||||
null=True
|
||||
)
|
||||
|
||||
@cached_property
|
||||
def dns_entry(self):
|
||||
""" Une entrée DNS A"""
|
||||
return "@ IN A " + str(self.origin)
|
||||
return "@ IN A " + str(self.origin)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class Mx(models.Model):
|
||||
""" Entrées des MX. Enregistre la zone (extension) associée et la priorité
|
||||
""" Entrées des MX. Enregistre la zone (extension) associée et la
|
||||
priorité
|
||||
Todo : pouvoir associer un MX à une interface """
|
||||
PRETTY_NAME = "Enregistrements MX"
|
||||
|
||||
|
@ -211,12 +269,16 @@ class Mx(models.Model):
|
|||
|
||||
@cached_property
|
||||
def dns_entry(self):
|
||||
return "@ IN MX " + str(self.priority) + " " + str(self.name)
|
||||
"""Renvoie l'entrée DNS complète pour un MX à mettre dans les
|
||||
fichiers de zones"""
|
||||
return "@ IN MX " + str(self.priority) + " " + str(self.name)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.zone) + ' ' + str(self.priority) + ' ' + str(self.name)
|
||||
|
||||
|
||||
class Ns(models.Model):
|
||||
"""Liste des enregistrements name servers par zone considéérée"""
|
||||
PRETTY_NAME = "Enregistrements NS"
|
||||
|
||||
zone = models.ForeignKey('Extension', on_delete=models.PROTECT)
|
||||
|
@ -224,11 +286,13 @@ class Ns(models.Model):
|
|||
|
||||
@cached_property
|
||||
def dns_entry(self):
|
||||
return "@ IN NS " + str(self.ns)
|
||||
"""Renvoie un enregistrement NS complet pour les filezones"""
|
||||
return "@ IN NS " + str(self.ns)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.zone) + ' ' + str(self.ns)
|
||||
|
||||
|
||||
class Text(models.Model):
|
||||
""" Un enregistrement TXT associé à une extension"""
|
||||
PRETTY_NAME = "Enregistrement text"
|
||||
|
@ -236,24 +300,33 @@ class Text(models.Model):
|
|||
zone = models.ForeignKey('Extension', on_delete=models.PROTECT)
|
||||
field1 = models.CharField(max_length=255)
|
||||
field2 = models.CharField(max_length=255)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return str(self.zone) + " : " + str(self.field1) + " " + str(self.field2)
|
||||
return str(self.zone) + " : " + str(self.field1) + " " +\
|
||||
str(self.field2)
|
||||
|
||||
@cached_property
|
||||
def dns_entry(self):
|
||||
"""Renvoie l'enregistrement TXT complet pour le fichier de zone"""
|
||||
return str(self.field1) + " IN TXT " + str(self.field2)
|
||||
|
||||
|
||||
class Interface(models.Model):
|
||||
""" Une interface. Objet clef de l'application machine :
|
||||
- une address mac unique. Possibilité de la rendre unique avec le typemachine
|
||||
""" Une interface. Objet clef de l'application machine :
|
||||
- une address mac unique. Possibilité de la rendre unique avec le
|
||||
typemachine
|
||||
- une onetoone vers IpList pour attribution ipv4
|
||||
- le type parent associé au range ip et à l'extension
|
||||
- un objet domain associé contenant son nom
|
||||
- la liste des ports oiuvert"""
|
||||
PRETTY_NAME = "Interface"
|
||||
|
||||
ipv4 = models.OneToOneField('IpList', on_delete=models.PROTECT, blank=True, null=True)
|
||||
ipv4 = models.OneToOneField(
|
||||
'IpList',
|
||||
on_delete=models.PROTECT,
|
||||
blank=True,
|
||||
null=True
|
||||
)
|
||||
mac_address = MACAddressField(integer=False, unique=True)
|
||||
machine = models.ForeignKey('Machine', on_delete=models.CASCADE)
|
||||
type = models.ForeignKey('MachineType', on_delete=models.PROTECT)
|
||||
|
@ -267,12 +340,14 @@ class Interface(models.Model):
|
|||
user = self.machine.user
|
||||
return machine.active and user.has_access()
|
||||
|
||||
|
||||
@cached_property
|
||||
def ipv6_object(self):
|
||||
""" Renvoie un objet type ipv6 à partir du prefix associé à l'iptype parent"""
|
||||
""" Renvoie un objet type ipv6 à partir du prefix associé à
|
||||
l'iptype parent"""
|
||||
if self.type.ip_type.prefix_v6:
|
||||
return EUI(self.mac_address).ipv6(IPNetwork(self.type.ip_type.prefix_v6).network)
|
||||
return EUI(self.mac_address).ipv6(
|
||||
IPNetwork(self.type.ip_type.prefix_v6).network
|
||||
)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
@ -286,10 +361,11 @@ class Interface(models.Model):
|
|||
return str(EUI(self.mac_address, dialect=mac_bare)).lower()
|
||||
|
||||
def filter_macaddress(self):
|
||||
""" Tente un formatage mac_bare, si échoue, lève une erreur de validation"""
|
||||
""" Tente un formatage mac_bare, si échoue, lève une erreur de
|
||||
validation"""
|
||||
try:
|
||||
self.mac_address = str(EUI(self.mac_address))
|
||||
except :
|
||||
except:
|
||||
raise ValidationError("La mac donnée est invalide")
|
||||
|
||||
def clean(self, *args, **kwargs):
|
||||
|
@ -307,7 +383,8 @@ class Interface(models.Model):
|
|||
if free_ips:
|
||||
self.ipv4 = free_ips[0]
|
||||
else:
|
||||
raise ValidationError("Il n'y a plus d'ip disponibles dans le slash")
|
||||
raise ValidationError("Il n'y a plus d'ip disponibles\
|
||||
dans le slash")
|
||||
return
|
||||
|
||||
def unassign_ipv4(self):
|
||||
|
@ -323,7 +400,8 @@ class Interface(models.Model):
|
|||
self.filter_macaddress()
|
||||
# On verifie la cohérence en forçant l'extension par la méthode
|
||||
if self.type.ip_type != self.ipv4.ip_type:
|
||||
raise ValidationError("L'ipv4 et le type de la machine ne correspondent pas")
|
||||
raise ValidationError("L'ipv4 et le type de la machine ne\
|
||||
correspondent pas")
|
||||
super(Interface, self).save(*args, **kwargs)
|
||||
|
||||
def __str__(self):
|
||||
|
@ -342,18 +420,34 @@ class Interface(models.Model):
|
|||
|
||||
def may_have_port_open(self):
|
||||
""" True si l'interface a une ip et une ip publique.
|
||||
Permet de ne pas exporter des ouvertures sur des ip privées (useless)"""
|
||||
Permet de ne pas exporter des ouvertures sur des ip privées
|
||||
(useless)"""
|
||||
return self.ipv4 and not self.has_private_ip()
|
||||
|
||||
|
||||
class Domain(models.Model):
|
||||
""" Objet domain. Enregistrement A et CNAME en même temps : permet de stocker les
|
||||
alias et les nom de machines, suivant si interface_parent ou cname sont remplis"""
|
||||
""" Objet domain. Enregistrement A et CNAME en même temps : permet de
|
||||
stocker les alias et les nom de machines, suivant si interface_parent
|
||||
ou cname sont remplis"""
|
||||
PRETTY_NAME = "Domaine dns"
|
||||
|
||||
interface_parent = models.OneToOneField('Interface', on_delete=models.CASCADE, blank=True, null=True)
|
||||
name = models.CharField(help_text="Obligatoire et unique, ne doit pas comporter de points", max_length=255)
|
||||
interface_parent = models.OneToOneField(
|
||||
'Interface',
|
||||
on_delete=models.CASCADE,
|
||||
blank=True,
|
||||
null=True
|
||||
)
|
||||
name = models.CharField(
|
||||
help_text="Obligatoire et unique, ne doit pas comporter de points",
|
||||
max_length=255
|
||||
)
|
||||
extension = models.ForeignKey('Extension', on_delete=models.PROTECT)
|
||||
cname = models.ForeignKey('self', null=True, blank=True, related_name='related_domain')
|
||||
cname = models.ForeignKey(
|
||||
'self',
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name='related_domain'
|
||||
)
|
||||
|
||||
class Meta:
|
||||
unique_together = (("name", "extension"),)
|
||||
|
@ -363,30 +457,35 @@ class Domain(models.Model):
|
|||
Retourne l'extension propre si c'est un cname, renvoie None sinon"""
|
||||
if self.interface_parent:
|
||||
return self.interface_parent.type.ip_type.extension
|
||||
elif hasattr(self,'extension'):
|
||||
elif hasattr(self, 'extension'):
|
||||
return self.extension
|
||||
else:
|
||||
return None
|
||||
|
||||
def clean(self):
|
||||
""" Validation :
|
||||
""" Validation :
|
||||
- l'objet est bien soit A soit CNAME
|
||||
- le cname est pas pointé sur lui-même
|
||||
- le nom contient bien les caractères autorisés par la norme dns et moins de 63 caractères au total
|
||||
- le nom contient bien les caractères autorisés par la norme
|
||||
dns et moins de 63 caractères au total
|
||||
- le couple nom/extension est bien unique"""
|
||||
if self.get_extension():
|
||||
self.extension=self.get_extension()
|
||||
""" Validation du nom de domaine, extensions dans type de machine, prefixe pas plus long que 63 caractères """
|
||||
self.extension = self.get_extension()
|
||||
if self.interface_parent and self.cname:
|
||||
raise ValidationError("On ne peut créer à la fois A et CNAME")
|
||||
if self.cname==self:
|
||||
if self.cname == self:
|
||||
raise ValidationError("On ne peut créer un cname sur lui même")
|
||||
HOSTNAME_LABEL_PATTERN = re.compile("(?!-)[A-Z\d-]+(?<!-)$", re.IGNORECASE)
|
||||
HOSTNAME_LABEL_PATTERN = re.compile(
|
||||
"(?!-)[A-Z\d-]+(?<!-)$",
|
||||
re.IGNORECASE
|
||||
)
|
||||
dns = self.name.lower()
|
||||
if len(dns) > 63:
|
||||
raise ValidationError("Le nom de domaine %s est trop long (maximum de 63 caractères)." % dns)
|
||||
raise ValidationError("Le nom de domaine %s est trop long\
|
||||
(maximum de 63 caractères)." % dns)
|
||||
if not HOSTNAME_LABEL_PATTERN.match(dns):
|
||||
raise ValidationError("Ce nom de domaine %s contient des carractères interdits." % dns)
|
||||
raise ValidationError("Ce nom de domaine %s contient des\
|
||||
carractères interdits." % dns)
|
||||
self.validate_unique()
|
||||
super(Domain, self).clean()
|
||||
|
||||
|
@ -394,10 +493,11 @@ class Domain(models.Model):
|
|||
def dns_entry(self):
|
||||
""" Une entrée DNS"""
|
||||
if self.cname:
|
||||
return str(self.name) + " IN CNAME " + str(self.cname) + "."
|
||||
return str(self.name) + " IN CNAME " + str(self.cname) + "."
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
""" Empèche le save sans extension valide. Force à avoir appellé clean avant"""
|
||||
""" Empèche le save sans extension valide.
|
||||
Force à avoir appellé clean avant"""
|
||||
if not self.get_extension():
|
||||
raise ValidationError("Extension invalide")
|
||||
self.full_clean()
|
||||
|
@ -406,6 +506,7 @@ class Domain(models.Model):
|
|||
def __str__(self):
|
||||
return str(self.name) + str(self.extension)
|
||||
|
||||
|
||||
class IpList(models.Model):
|
||||
PRETTY_NAME = "Addresses ipv4"
|
||||
|
||||
|
@ -414,13 +515,15 @@ class IpList(models.Model):
|
|||
|
||||
@cached_property
|
||||
def need_infra(self):
|
||||
""" Permet de savoir si un user basique peut assigner cette ip ou non"""
|
||||
""" Permet de savoir si un user basique peut assigner cette ip ou
|
||||
non"""
|
||||
return self.ip_type.need_infra
|
||||
|
||||
def clean(self):
|
||||
""" Erreur si l'ip_type est incorrect"""
|
||||
if not str(self.ipv4) in self.ip_type.ip_set_as_str:
|
||||
raise ValidationError("L'ipv4 et le range de l'iptype ne correspondent pas!")
|
||||
raise ValidationError("L'ipv4 et le range de l'iptype ne\
|
||||
correspondent pas!")
|
||||
return
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
|
@ -430,24 +533,36 @@ class IpList(models.Model):
|
|||
def __str__(self):
|
||||
return self.ipv4
|
||||
|
||||
|
||||
class Service(models.Model):
|
||||
""" Definition d'un service (dhcp, dns, etc)"""
|
||||
service_type = models.CharField(max_length=255, blank=True, unique=True)
|
||||
min_time_regen = models.DurationField(default=timedelta(minutes=1), help_text="Temps minimal avant nouvelle génération du service")
|
||||
regular_time_regen = models.DurationField(default=timedelta(hours=1), help_text="Temps maximal avant nouvelle génération du service")
|
||||
min_time_regen = models.DurationField(
|
||||
default=timedelta(minutes=1),
|
||||
help_text="Temps minimal avant nouvelle génération du service"
|
||||
)
|
||||
regular_time_regen = models.DurationField(
|
||||
default=timedelta(hours=1),
|
||||
help_text="Temps maximal avant nouvelle génération du service"
|
||||
)
|
||||
servers = models.ManyToManyField('Interface', through='Service_link')
|
||||
|
||||
def ask_regen(self):
|
||||
""" Marque à True la demande de régénération pour un service x """
|
||||
Service_link.objects.filter(service=self).exclude(asked_regen=True).update(asked_regen=True)
|
||||
Service_link.objects.filter(service=self).exclude(asked_regen=True)\
|
||||
.update(asked_regen=True)
|
||||
return
|
||||
|
||||
def process_link(self, servers):
|
||||
""" Django ne peut créer lui meme les relations manytomany avec table intermediaire explicite"""
|
||||
for serv in servers.exclude(pk__in=Interface.objects.filter(service=self)):
|
||||
""" Django ne peut créer lui meme les relations manytomany avec table
|
||||
intermediaire explicite"""
|
||||
for serv in servers.exclude(
|
||||
pk__in=Interface.objects.filter(service=self)
|
||||
):
|
||||
link = Service_link(service=self, server=serv)
|
||||
link.save()
|
||||
Service_link.objects.filter(service=self).exclude(server__in=servers).delete()
|
||||
Service_link.objects.filter(service=self).exclude(server__in=servers)\
|
||||
.delete()
|
||||
return
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
|
@ -456,13 +571,16 @@ class Service(models.Model):
|
|||
def __str__(self):
|
||||
return str(self.service_type)
|
||||
|
||||
|
||||
def regen(service):
|
||||
""" Fonction externe pour régérération d'un service, prend un objet service en arg"""
|
||||
""" Fonction externe pour régérération d'un service, prend un objet service
|
||||
en arg"""
|
||||
obj = Service.objects.filter(service_type=service)
|
||||
if obj:
|
||||
obj[0].ask_regen()
|
||||
return
|
||||
|
||||
|
||||
class Service_link(models.Model):
|
||||
""" Definition du lien entre serveurs et services"""
|
||||
service = models.ForeignKey('Service', on_delete=models.CASCADE)
|
||||
|
@ -477,11 +595,16 @@ class Service_link(models.Model):
|
|||
self.save()
|
||||
|
||||
def need_regen(self):
|
||||
""" Décide si le temps minimal écoulé est suffisant pour provoquer une régénération de service"""
|
||||
if (self.asked_regen and (self.last_regen + self.service.min_time_regen) < timezone.now()) or (self.last_regen + self.service.regular_time_regen) < timezone.now():
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
""" Décide si le temps minimal écoulé est suffisant pour provoquer une
|
||||
régénération de service"""
|
||||
return bool(
|
||||
(self.asked_regen and (
|
||||
self.last_regen + self.service.min_time_regen
|
||||
) < timezone.now()
|
||||
) or (
|
||||
self.last_regen + self.service.regular_time_regen
|
||||
) < timezone.now()
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.server) + " " + str(self.service)
|
||||
|
@ -489,29 +612,48 @@ class Service_link(models.Model):
|
|||
|
||||
class OuverturePortList(models.Model):
|
||||
"""Liste des ports ouverts sur une interface."""
|
||||
name = models.CharField(help_text="Nom de la configuration des ports.", max_length=255)
|
||||
name = models.CharField(
|
||||
help_text="Nom de la configuration des ports.",
|
||||
max_length=255
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def tcp_ports_in(self):
|
||||
return self.ouvertureport_set.filter(protocole=OuverturePort.TCP, io=OuverturePort.IN)
|
||||
|
||||
"""Renvoie la liste des ports ouverts en TCP IN pour ce profil"""
|
||||
return self.ouvertureport_set.filter(
|
||||
protocole=OuverturePort.TCP,
|
||||
io=OuverturePort.IN
|
||||
)
|
||||
|
||||
def udp_ports_in(self):
|
||||
return self.ouvertureport_set.filter(protocole=OuverturePort.UDP, io=OuverturePort.IN)
|
||||
"""Renvoie la liste des ports ouverts en UDP IN pour ce profil"""
|
||||
return self.ouvertureport_set.filter(
|
||||
protocole=OuverturePort.UDP,
|
||||
io=OuverturePort.IN
|
||||
)
|
||||
|
||||
def tcp_ports_out(self):
|
||||
return self.ouvertureport_set.filter(protocole=OuverturePort.TCP, io=OuverturePort.OUT)
|
||||
|
||||
"""Renvoie la liste des ports ouverts en TCP OUT pour ce profil"""
|
||||
return self.ouvertureport_set.filter(
|
||||
protocole=OuverturePort.TCP,
|
||||
io=OuverturePort.OUT
|
||||
)
|
||||
|
||||
def udp_ports_out(self):
|
||||
return self.ouvertureport_set.filter(protocole=OuverturePort.UDP, io=OuverturePort.OUT)
|
||||
"""Renvoie la liste des ports ouverts en UDP OUT pour ce profil"""
|
||||
return self.ouvertureport_set.filter(
|
||||
protocole=OuverturePort.UDP,
|
||||
io=OuverturePort.OUT
|
||||
)
|
||||
|
||||
|
||||
class OuverturePort(models.Model):
|
||||
"""
|
||||
Représente un simple port ou une plage de ports.
|
||||
|
||||
Les ports de la plage sont compris entre begin et en inclus.
|
||||
|
||||
Les ports de la plage sont compris entre begin et en inclus.
|
||||
Si begin == end alors on ne représente qu'un seul port.
|
||||
|
||||
On limite les ports entre 0 et 65535, tels que défini par la RFC
|
||||
|
@ -522,112 +664,150 @@ class OuverturePort(models.Model):
|
|||
OUT = 'O'
|
||||
begin = models.PositiveIntegerField(validators=[MaxValueValidator(65535)])
|
||||
end = models.PositiveIntegerField(validators=[MaxValueValidator(65535)])
|
||||
port_list = models.ForeignKey('OuverturePortList', on_delete=models.CASCADE)
|
||||
port_list = models.ForeignKey(
|
||||
'OuverturePortList',
|
||||
on_delete=models.CASCADE
|
||||
)
|
||||
protocole = models.CharField(
|
||||
max_length=1,
|
||||
choices=(
|
||||
(TCP, 'TCP'),
|
||||
(UDP, 'UDP'),
|
||||
),
|
||||
default=TCP,
|
||||
max_length=1,
|
||||
choices=(
|
||||
(TCP, 'TCP'),
|
||||
(UDP, 'UDP'),
|
||||
),
|
||||
default=TCP,
|
||||
)
|
||||
io = models.CharField(
|
||||
max_length=1,
|
||||
choices=(
|
||||
(IN, 'IN'),
|
||||
(OUT, 'OUT'),
|
||||
),
|
||||
default=OUT,
|
||||
max_length=1,
|
||||
choices=(
|
||||
(IN, 'IN'),
|
||||
(OUT, 'OUT'),
|
||||
),
|
||||
default=OUT,
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
if self.begin == self.end :
|
||||
if self.begin == self.end:
|
||||
return str(self.begin)
|
||||
return '-'.join([str(self.begin), str(self.end)])
|
||||
|
||||
def show_port(self):
|
||||
"""Formatage plus joli, alias pour str"""
|
||||
return str(self)
|
||||
|
||||
|
||||
@receiver(post_save, sender=Machine)
|
||||
def machine_post_save(sender, **kwargs):
|
||||
"""Synchronisation ldap et régen parefeu/dhcp lors de la modification
|
||||
d'une machine"""
|
||||
user = kwargs['instance'].user
|
||||
user.ldap_sync(base=False, access_refresh=False, mac_refresh=True)
|
||||
regen('dhcp')
|
||||
regen('mac_ip_list')
|
||||
|
||||
|
||||
@receiver(post_delete, sender=Machine)
|
||||
def machine_post_delete(sender, **kwargs):
|
||||
"""Synchronisation ldap et régen parefeu/dhcp lors de la suppression
|
||||
d'une machine"""
|
||||
machine = kwargs['instance']
|
||||
user = machine.user
|
||||
user.ldap_sync(base=False, access_refresh=False, mac_refresh=True)
|
||||
regen('dhcp')
|
||||
regen('mac_ip_list')
|
||||
|
||||
|
||||
@receiver(post_save, sender=Interface)
|
||||
def interface_post_save(sender, **kwargs):
|
||||
"""Synchronisation ldap et régen parefeu/dhcp lors de la modification
|
||||
d'une interface"""
|
||||
interface = kwargs['instance']
|
||||
user = interface.machine.user
|
||||
user.ldap_sync(base=False, access_refresh=False, mac_refresh=True)
|
||||
if not interface.may_have_port_open() and interface.port_lists.all():
|
||||
interface.port_lists.clear()
|
||||
# Regen services
|
||||
regen('dhcp')
|
||||
regen('mac_ip_list')
|
||||
|
||||
|
||||
@receiver(post_delete, sender=Interface)
|
||||
def interface_post_delete(sender, **kwargs):
|
||||
"""Synchronisation ldap et régen parefeu/dhcp lors de la suppression
|
||||
d'une interface"""
|
||||
interface = kwargs['instance']
|
||||
user = interface.machine.user
|
||||
user.ldap_sync(base=False, access_refresh=False, mac_refresh=True)
|
||||
|
||||
|
||||
@receiver(post_save, sender=IpType)
|
||||
def iptype_post_save(sender, **kwargs):
|
||||
"""Generation des objets ip après modification d'un range ip"""
|
||||
iptype = kwargs['instance']
|
||||
iptype.gen_ip_range()
|
||||
|
||||
|
||||
@receiver(post_save, sender=MachineType)
|
||||
def machine_post_save(sender, **kwargs):
|
||||
"""Mise à jour des interfaces lorsque changement d'attribution
|
||||
d'une machinetype (changement iptype parent)"""
|
||||
machinetype = kwargs['instance']
|
||||
for interface in machinetype.all_interfaces():
|
||||
interface.update_type()
|
||||
|
||||
|
||||
@receiver(post_save, sender=Domain)
|
||||
def domain_post_save(sender, **kwargs):
|
||||
"""Regeneration dns après modification d'un domain object"""
|
||||
regen('dns')
|
||||
|
||||
|
||||
@receiver(post_delete, sender=Domain)
|
||||
def domain_post_delete(sender, **kwargs):
|
||||
"""Regeneration dns après suppression d'un domain object"""
|
||||
regen('dns')
|
||||
|
||||
|
||||
@receiver(post_save, sender=Extension)
|
||||
def extension_post_save(sender, **kwargs):
|
||||
"""Regeneration dns après modification d'une extension"""
|
||||
regen('dns')
|
||||
|
||||
|
||||
@receiver(post_delete, sender=Extension)
|
||||
def extension_post_selete(sender, **kwargs):
|
||||
"""Regeneration dns après suppression d'une extension"""
|
||||
regen('dns')
|
||||
|
||||
|
||||
@receiver(post_save, sender=Mx)
|
||||
def mx_post_save(sender, **kwargs):
|
||||
"""Regeneration dns après modification d'un MX"""
|
||||
regen('dns')
|
||||
|
||||
|
||||
@receiver(post_delete, sender=Mx)
|
||||
def mx_post_delete(sender, **kwargs):
|
||||
"""Regeneration dns après suppresson d'un MX"""
|
||||
regen('dns')
|
||||
|
||||
|
||||
@receiver(post_save, sender=Ns)
|
||||
def ns_post_save(sender, **kwargs):
|
||||
"""Regeneration dns après modification d'un NS"""
|
||||
regen('dns')
|
||||
|
||||
|
||||
@receiver(post_delete, sender=Ns)
|
||||
def ns_post_delete(sender, **kwargs):
|
||||
"""Regeneration dns après modification d'un NS"""
|
||||
regen('dns')
|
||||
|
||||
|
||||
@receiver(post_save, sender=Text)
|
||||
def text_post_save(sender, **kwargs):
|
||||
"""Regeneration dns après modification d'un TXT"""
|
||||
regen('dns')
|
||||
|
||||
|
||||
@receiver(post_delete, sender=Text)
|
||||
def text_post_delete(sender, **kwargs):
|
||||
"""Regeneration dns après modification d'un TX"""
|
||||
regen('dns')
|
||||
|
|
Loading…
Reference in a new issue