|
|
|
@ -27,32 +27,30 @@ The models definitions for the Machines app |
|
|
|
|
|
|
|
from __future__ import unicode_literals |
|
|
|
|
|
|
|
from datetime import timedelta |
|
|
|
import base64 |
|
|
|
import hashlib |
|
|
|
import re |
|
|
|
from datetime import timedelta |
|
|
|
from ipaddress import IPv6Address |
|
|
|
from itertools import chain |
|
|
|
from netaddr import mac_bare, EUI, IPSet, IPRange, IPNetwork, IPAddress |
|
|
|
import hashlib |
|
|
|
import base64 |
|
|
|
|
|
|
|
from django.core.validators import MaxValueValidator, MinValueValidator |
|
|
|
from django.db import models |
|
|
|
from django.db.models import Q |
|
|
|
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, MinValueValidator |
|
|
|
from django.utils.functional import cached_property |
|
|
|
from django.utils.translation import ugettext_lazy as _ |
|
|
|
|
|
|
|
from macaddress.fields import MACAddressField |
|
|
|
from netaddr import mac_bare, EUI, IPSet, IPRange, IPNetwork, IPAddress |
|
|
|
|
|
|
|
import preferences.models |
|
|
|
import users.models |
|
|
|
from re2o.field_permissions import FieldPermissionModelMixin |
|
|
|
from re2o.mixins import AclMixin, RevMixin |
|
|
|
|
|
|
|
import users.models |
|
|
|
import preferences.models |
|
|
|
|
|
|
|
|
|
|
|
class Machine(RevMixin, FieldPermissionModelMixin, models.Model): |
|
|
|
""" Class définissant une machine, object parent user, objets fils |
|
|
|
@ -116,7 +114,7 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model): |
|
|
|
:return: True ou False avec la raison de l'échec le cas échéant""" |
|
|
|
if not user_request.has_perm('machines.view_machine'): |
|
|
|
return False, _("You don't have the right to view all the" |
|
|
|
" machines.") |
|
|
|
" machines.") |
|
|
|
return True, None |
|
|
|
|
|
|
|
@staticmethod |
|
|
|
@ -131,9 +129,9 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model): |
|
|
|
except users.models.User.DoesNotExist: |
|
|
|
return False, _("Nonexistent user.") |
|
|
|
max_lambdauser_interfaces = (preferences.models.OptionalMachine |
|
|
|
.get_cached_value( |
|
|
|
'max_lambdauser_interfaces' |
|
|
|
)) |
|
|
|
.get_cached_value( |
|
|
|
'max_lambdauser_interfaces' |
|
|
|
)) |
|
|
|
if not user_request.has_perm('machines.add_machine'): |
|
|
|
if not (preferences.models.OptionalMachine |
|
|
|
.get_cached_value('create_machine')): |
|
|
|
@ -180,7 +178,7 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model): |
|
|
|
**kwargs |
|
|
|
)[0]): |
|
|
|
return False, _("You don't have the right to delete a machine" |
|
|
|
" of another user.") |
|
|
|
" of another user.") |
|
|
|
return True, None |
|
|
|
|
|
|
|
def can_view(self, user_request, *_args, **_kwargs): |
|
|
|
@ -192,7 +190,7 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model): |
|
|
|
if (not user_request.has_perm('machines.view_machine') and |
|
|
|
self.user != user_request): |
|
|
|
return False, _("You don't have the right to view other machines" |
|
|
|
" than yours.") |
|
|
|
" than yours.") |
|
|
|
return True, None |
|
|
|
|
|
|
|
@cached_property |
|
|
|
@ -213,14 +211,14 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model): |
|
|
|
machine""" |
|
|
|
return Domain.objects.filter( |
|
|
|
interface_parent__machine=self |
|
|
|
).values_list('name', flat=True).distinct() |
|
|
|
).values_list('name', flat=True).distinct() |
|
|
|
|
|
|
|
@cached_property |
|
|
|
def all_complete_names(self): |
|
|
|
"""Renvoie tous les tls complets de la machine""" |
|
|
|
return [str(domain) for domain in Domain.objects.filter( |
|
|
|
Q(cname__interface_parent__machine=self) | Q(interface_parent__machine=self) |
|
|
|
)] |
|
|
|
)] |
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs): |
|
|
|
super(Machine, self).__init__(*args, **kwargs) |
|
|
|
@ -296,8 +294,8 @@ class IpType(RevMixin, AclMixin, models.Model): |
|
|
|
help_text=_("Netmask for the domain's IPv4 range") |
|
|
|
) |
|
|
|
reverse_v4 = models.BooleanField( |
|
|
|
default=False, |
|
|
|
help_text=_("Enable reverse DNS for IPv4"), |
|
|
|
default=False, |
|
|
|
help_text=_("Enable reverse DNS for IPv4"), |
|
|
|
) |
|
|
|
prefix_v6 = models.GenericIPAddressField( |
|
|
|
protocol='IPv6', |
|
|
|
@ -310,10 +308,10 @@ class IpType(RevMixin, AclMixin, models.Model): |
|
|
|
MaxValueValidator(128), |
|
|
|
MinValueValidator(0) |
|
|
|
] |
|
|
|
) |
|
|
|
) |
|
|
|
reverse_v6 = models.BooleanField( |
|
|
|
default=False, |
|
|
|
help_text=_("Enable reverse DNS for IPv6"), |
|
|
|
default=False, |
|
|
|
help_text=_("Enable reverse DNS for IPv6"), |
|
|
|
) |
|
|
|
vlan = models.ForeignKey( |
|
|
|
'Vlan', |
|
|
|
@ -333,7 +331,7 @@ class IpType(RevMixin, AclMixin, models.Model): |
|
|
|
("use_all_iptype", _("Can use all IP types")), |
|
|
|
) |
|
|
|
verbose_name = _("IP type") |
|
|
|
verbose_name_plural = ("IP types") |
|
|
|
verbose_name_plural = "IP types" |
|
|
|
|
|
|
|
@cached_property |
|
|
|
def ip_range(self): |
|
|
|
@ -373,9 +371,9 @@ class IpType(RevMixin, AclMixin, models.Model): |
|
|
|
def ip6_set_full_info(self): |
|
|
|
if self.prefix_v6: |
|
|
|
return { |
|
|
|
'network' : str(self.prefix_v6), |
|
|
|
'netmask' : 'ffff:ffff:ffff:ffff::', |
|
|
|
'netmask_cidr' : str(self.prefix_v6_length), |
|
|
|
'network': str(self.prefix_v6), |
|
|
|
'netmask': 'ffff:ffff:ffff:ffff::', |
|
|
|
'netmask_cidr': str(self.prefix_v6_length), |
|
|
|
'vlan': str(self.vlan), |
|
|
|
'vlan_id': self.vlan.vlan_id |
|
|
|
} |
|
|
|
@ -394,10 +392,10 @@ class IpType(RevMixin, AclMixin, models.Model): |
|
|
|
def ip_net_full_info(self): |
|
|
|
"""Renvoie les infos du network contenant du range""" |
|
|
|
return { |
|
|
|
'network' : str(self.ip_network.network), |
|
|
|
'netmask' : str(self.ip_network.netmask), |
|
|
|
'broadcast' : str(self.ip_network.broadcast), |
|
|
|
'netmask_cidr' : str(self.ip_network.prefixlen), |
|
|
|
'network': str(self.ip_network.network), |
|
|
|
'netmask': str(self.ip_network.netmask), |
|
|
|
'broadcast': str(self.ip_network.broadcast), |
|
|
|
'netmask_cidr': str(self.ip_network.prefixlen), |
|
|
|
} |
|
|
|
|
|
|
|
@cached_property |
|
|
|
@ -448,9 +446,9 @@ class IpType(RevMixin, AclMixin, models.Model): |
|
|
|
return |
|
|
|
else: |
|
|
|
for ipv6 in Ipv6List.objects.filter( |
|
|
|
interface__in=Interface.objects.filter( |
|
|
|
type__in=MachineType.objects.filter(ip_type=self) |
|
|
|
) |
|
|
|
interface__in=Interface.objects.filter( |
|
|
|
type__in=MachineType.objects.filter(ip_type=self) |
|
|
|
) |
|
|
|
): |
|
|
|
ipv6.check_and_replace_prefix(prefix=self.prefix_v6) |
|
|
|
|
|
|
|
@ -814,8 +812,8 @@ class Txt(RevMixin, AclMixin, models.Model): |
|
|
|
verbose_name_plural = _("TXT records") |
|
|
|
|
|
|
|
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): |
|
|
|
@ -874,7 +872,7 @@ class Srv(RevMixin, AclMixin, models.Model): |
|
|
|
default=0, |
|
|
|
validators=[MaxValueValidator(65535)], |
|
|
|
help_text=_("Relative weight for records with the same priority" |
|
|
|
" (integer value between 0 and 65535)") |
|
|
|
" (integer value between 0 and 65535)") |
|
|
|
) |
|
|
|
port = models.PositiveIntegerField( |
|
|
|
validators=[MaxValueValidator(65535)], |
|
|
|
@ -894,17 +892,17 @@ class Srv(RevMixin, AclMixin, models.Model): |
|
|
|
verbose_name_plural = _("SRV records") |
|
|
|
|
|
|
|
def __str__(self): |
|
|
|
return str(self.service) + ' ' + str(self.protocole) + ' ' +\ |
|
|
|
str(self.extension) + ' ' + str(self.priority) +\ |
|
|
|
' ' + str(self.weight) + str(self.port) + str(self.target) |
|
|
|
return str(self.service) + ' ' + str(self.protocole) + ' ' + \ |
|
|
|
str(self.extension) + ' ' + str(self.priority) + \ |
|
|
|
' ' + str(self.weight) + str(self.port) + str(self.target) |
|
|
|
|
|
|
|
@cached_property |
|
|
|
def dns_entry(self): |
|
|
|
"""Renvoie l'enregistrement SRV complet pour le fichier de zone""" |
|
|
|
return str(self.service) + '._' + str(self.protocole).lower() +\ |
|
|
|
str(self.extension) + '. ' + str(self.ttl) + ' IN SRV ' +\ |
|
|
|
str(self.priority) + ' ' + str(self.weight) + ' ' +\ |
|
|
|
str(self.port) + ' ' + str(self.target) + '.' |
|
|
|
return str(self.service) + '._' + str(self.protocole).lower() + \ |
|
|
|
str(self.extension) + '. ' + str(self.ttl) + ' IN SRV ' + \ |
|
|
|
str(self.priority) + ' ' + str(self.weight) + ' ' + \ |
|
|
|
str(self.port) + ' ' + str(self.target) + '.' |
|
|
|
|
|
|
|
|
|
|
|
class SshFp(RevMixin, AclMixin, models.Model): |
|
|
|
@ -949,8 +947,8 @@ class SshFp(RevMixin, AclMixin, models.Model): |
|
|
|
"""Return the hashess for the pub key with correct id |
|
|
|
cf RFC, 1 is sha1 , 2 sha256""" |
|
|
|
return { |
|
|
|
"1" : hashlib.sha1(base64.b64decode(self.pub_key_entry)).hexdigest(), |
|
|
|
"2" : hashlib.sha256(base64.b64decode(self.pub_key_entry)).hexdigest(), |
|
|
|
"1": hashlib.sha1(base64.b64decode(self.pub_key_entry)).hexdigest(), |
|
|
|
"2": hashlib.sha256(base64.b64decode(self.pub_key_entry)).hexdigest(), |
|
|
|
} |
|
|
|
|
|
|
|
class Meta: |
|
|
|
@ -973,7 +971,6 @@ class SshFp(RevMixin, AclMixin, models.Model): |
|
|
|
return str(self.algo) + ' ' + str(self.comment) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): |
|
|
|
""" Une interface. Objet clef de l'application machine : |
|
|
|
- une address mac unique. Possibilité de la rendre unique avec le |
|
|
|
@ -1067,7 +1064,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): |
|
|
|
.get_cached_value('ipv6_mode') == 'SLAAC'): |
|
|
|
self.sync_ipv6_slaac() |
|
|
|
elif (preferences.models.OptionalMachine |
|
|
|
.get_cached_value('ipv6_mode') == 'DHCPV6'): |
|
|
|
.get_cached_value('ipv6_mode') == 'DHCPV6'): |
|
|
|
self.sync_ipv6_dhcpv6() |
|
|
|
else: |
|
|
|
return |
|
|
|
@ -1080,7 +1077,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): |
|
|
|
.get_cached_value('ipv6_mode') == 'SLAAC'): |
|
|
|
return self.ipv6list.all() |
|
|
|
elif (preferences.models.OptionalMachine |
|
|
|
.get_cached_value('ipv6_mode') == 'DHCPV6'): |
|
|
|
.get_cached_value('ipv6_mode') == 'DHCPV6'): |
|
|
|
return self.ipv6list.filter(slaac_ip=False) |
|
|
|
else: |
|
|
|
return None |
|
|
|
@ -1159,9 +1156,9 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): |
|
|
|
.get_cached_value('create_machine')): |
|
|
|
return False, _("You can't add a machine.") |
|
|
|
max_lambdauser_interfaces = (preferences.models.OptionalMachine |
|
|
|
.get_cached_value( |
|
|
|
'max_lambdauser_interfaces' |
|
|
|
)) |
|
|
|
.get_cached_value( |
|
|
|
'max_lambdauser_interfaces' |
|
|
|
)) |
|
|
|
if machine.user != user_request: |
|
|
|
return False, _("You don't have the right to add an interface" |
|
|
|
" to a machine of another user.") |
|
|
|
@ -1365,8 +1362,8 @@ class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): |
|
|
|
|
|
|
|
def clean(self, *args, **kwargs): |
|
|
|
if self.slaac_ip and (Ipv6List.objects |
|
|
|
.filter(interface=self.interface, slaac_ip=True) |
|
|
|
.exclude(id=self.id)): |
|
|
|
.filter(interface=self.interface, slaac_ip=True) |
|
|
|
.exclude(id=self.id)): |
|
|
|
raise ValidationError(_("A SLAAC IP address is already registered.")) |
|
|
|
prefix_v6 = self.interface.type.ip_type.prefix_v6.encode().decode('utf-8') |
|
|
|
if prefix_v6: |
|
|
|
@ -1498,18 +1495,18 @@ class Domain(RevMixin, AclMixin, models.Model): |
|
|
|
return False, _("Nonexistent interface.") |
|
|
|
if not user_request.has_perm('machines.add_domain'): |
|
|
|
max_lambdauser_aliases = (preferences.models.OptionalMachine |
|
|
|
.get_cached_value( |
|
|
|
'max_lambdauser_aliases' |
|
|
|
)) |
|
|
|
.get_cached_value( |
|
|
|
'max_lambdauser_aliases' |
|
|
|
)) |
|
|
|
if interface.machine.user != user_request: |
|
|
|
return False, _("You don't have the right to add an alias to a" |
|
|
|
" machine of another user.") |
|
|
|
if Domain.objects.filter( |
|
|
|
cname__in=Domain.objects.filter( |
|
|
|
interface_parent__in=(interface.machine.user |
|
|
|
.user_interfaces()) |
|
|
|
.user_interfaces()) |
|
|
|
) |
|
|
|
).count() >= max_lambdauser_aliases: |
|
|
|
).count() >= max_lambdauser_aliases: |
|
|
|
return False, _("You reached the maximum number of alias that" |
|
|
|
" you are allowed to create yourself (%s). " |
|
|
|
% max_lambdauser_aliases) |
|
|
|
@ -1695,7 +1692,7 @@ class Service(RevMixin, AclMixin, models.Model): |
|
|
|
|
|
|
|
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)\ |
|
|
|
Service_link.objects.filter(service=self).exclude(asked_regen=True) \ |
|
|
|
.update(asked_regen=True) |
|
|
|
return |
|
|
|
|
|
|
|
@ -1703,11 +1700,11 @@ class Service(RevMixin, AclMixin, models.Model): |
|
|
|
""" 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) |
|
|
|
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)\ |
|
|
|
Service_link.objects.filter(service=self).exclude(server__in=servers) \ |
|
|
|
.delete() |
|
|
|
return |
|
|
|
|
|
|
|
@ -1754,10 +1751,10 @@ class Service_link(RevMixin, AclMixin, models.Model): |
|
|
|
régénération de service""" |
|
|
|
return bool( |
|
|
|
(self.asked_regen and ( |
|
|
|
self.last_regen + self.service.min_time_regen |
|
|
|
self.last_regen + self.service.min_time_regen |
|
|
|
) < timezone.now() |
|
|
|
) or ( |
|
|
|
self.last_regen + self.service.regular_time_regen |
|
|
|
) or ( |
|
|
|
self.last_regen + self.service.regular_time_regen |
|
|
|
) < timezone.now() |
|
|
|
) |
|
|
|
|
|
|
|
@ -1875,9 +1872,8 @@ class OuverturePort(RevMixin, AclMixin, models.Model): |
|
|
|
), |
|
|
|
default=OUT, |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
class Meta: |
|
|
|
verbose_name = _("ports opening") |
|
|
|
verbose_name = _("ports openings") |
|
|
|
|
|
|
|
def __str__(self): |
|
|
|
@ -2044,4 +2040,3 @@ def srv_post_save(**_kwargs): |
|
|
|
def srv_post_delete(**_kwargs): |
|
|
|
"""Regeneration dns après modification d'un SRV""" |
|
|
|
regen('dns') |
|
|
|
|
|
|
|
|