@ -35,26 +35,18 @@ from ipaddress import IPv6Address
from itertools import chain
from itertools import chain
from django . core . validators import MaxValueValidator , MinValueValidator
from django . core . validators import MaxValueValidator , MinValueValidator
from django . db import models
from django . db import models , transaction
from django . db . models import Q
from django . db . models import Q
from django . db . models . signals import post_save , post_delet e
from django . db . models . signals import post_delete , post_sav e
from django . dispatch import receiver
from django . dispatch import receiver
from django . forms import ValidationError
from django . forms import ValidationError
from django . utils import timezone
from django . utils import timezone
from django . db import transaction
from reversion import revisions as reversion
from django . utils . functional import cached_property
from django . utils . functional import cached_property
from django . utils . translation import ugettext_lazy as _
from django . utils . translation import ugettext_lazy as _
from macaddress . fields import MACAddressField , default_dialect
from macaddress . fields import MACAddressField , default_dialect
from netaddr import (
from netaddr import ( EUI , IPAddress , IPNetwork , IPRange , IPSet ,
mac_bare ,
NotRegisteredError , mac_bare )
EUI ,
from reversion import revisions as reversion
NotRegisteredError ,
IPSet ,
IPRange ,
IPNetwork ,
IPAddress ,
)
import preferences . models
import preferences . models
import users . models
import users . models
@ -79,9 +71,7 @@ class Machine(RevMixin, FieldPermissionModelMixin, AclMixin, models.Model):
active = models . BooleanField ( default = True )
active = models . BooleanField ( default = True )
class Meta :
class Meta :
permissions = (
permissions = ( ( " change_machine_user " , _ ( " Can change the user of a machine " ) ) , )
( " change_machine_user " , _ ( " Can change the user of a machine " ) ) ,
)
verbose_name = _ ( " machine " )
verbose_name = _ ( " machine " )
verbose_name_plural = _ ( " machines " )
verbose_name_plural = _ ( " machines " )
@ -342,9 +332,7 @@ class MachineType(RevMixin, AclMixin, models.Model):
)
)
class Meta :
class Meta :
permissions = (
permissions = ( ( " use_all_machinetype " , _ ( " Can use all machine types " ) ) , )
( " use_all_machinetype " , _ ( " Can use all machine types " ) ) ,
)
verbose_name = _ ( " machine type " )
verbose_name = _ ( " machine type " )
verbose_name_plural = _ ( " machine types " )
verbose_name_plural = _ ( " machine types " )
@ -356,7 +344,9 @@ class MachineType(RevMixin, AclMixin, models.Model):
""" Update domains extension with the extension of interface_parent. Called after update of an ip_type or a machine_type object. Exceptions are handled in the views.
""" Update domains extension with the extension of interface_parent. Called after update of an ip_type or a machine_type object. Exceptions are handled in the views.
( Calling domain . clear ( ) for all domains could take several minutes )
( Calling domain . clear ( ) for all domains could take several minutes )
"""
"""
Domain . objects . filter ( interface_parent__machine_type = self ) . update ( extension = self . ip_type . extension )
Domain . objects . filter ( interface_parent__machine_type = self ) . update (
extension = self . ip_type . extension
)
@staticmethod
@staticmethod
def can_use_all ( user_request , * _args , * * _kwargs ) :
def can_use_all ( user_request , * _args , * * _kwargs ) :
@ -379,7 +369,7 @@ class MachineType(RevMixin, AclMixin, models.Model):
@classmethod
@classmethod
def can_list ( cls , user_request , * _args , * * _kwargs ) :
def can_list ( cls , user_request , * _args , * * _kwargs ) :
""" All users can list unprivileged machinetypes
""" All users can list unprivileged machinetypes
Only members of privileged groups can list all .
Only members of privileged groups can list all .
: param user_request : The user who wants to view the list .
: param user_request : The user who wants to view the list .
@ -389,20 +379,13 @@ class MachineType(RevMixin, AclMixin, models.Model):
"""
"""
can , _message , _group = cls . can_use_all ( user_request )
can , _message , _group = cls . can_use_all ( user_request )
if can :
if can :
return (
return ( True , None , None , cls . objects . all ( ) )
True ,
None ,
None ,
cls . objects . all ( )
)
else :
else :
return (
return (
True ,
True ,
_ ( " You don ' t have the right to use all machine types. " ) ,
_ ( " You don ' t have the right to use all machine types. " ) ,
( " machines.use_all_machinetype " , ) ,
( " machines.use_all_machinetype " , ) ,
cls . objects . filter (
cls . objects . filter ( ip_type__in = IpType . objects . filter ( need_infra = False ) ) ,
ip_type__in = IpType . objects . filter ( need_infra = False )
) ,
)
)
def __str__ ( self ) :
def __str__ ( self ) :
@ -455,12 +438,12 @@ class IpType(RevMixin, AclMixin, models.Model):
default = False , help_text = _ ( " Enable reverse DNS for IPv6. " )
default = False , help_text = _ ( " Enable reverse DNS for IPv6. " )
)
)
vlan = models . ForeignKey ( " Vlan " , on_delete = models . PROTECT , blank = True , null = True )
vlan = models . ForeignKey ( " Vlan " , on_delete = models . PROTECT , blank = True , null = True )
ouverture_ports = models . ForeignKey ( " OuverturePortList " , blank = True , null = True , on_delete = models . PROTECT )
ouverture_ports = models . ForeignKey (
" OuverturePortList " , blank = True , null = True , on_delete = models . PROTECT
)
class Meta :
class Meta :
permissions = (
permissions = ( ( " use_all_iptype " , _ ( " Can use all IP types " ) ) , )
( " use_all_iptype " , _ ( " Can use all IP types " ) ) ,
)
verbose_name = _ ( " IP type " )
verbose_name = _ ( " IP type " )
verbose_name_plural = _ ( " IP types " )
verbose_name_plural = _ ( " IP types " )
@ -897,9 +880,7 @@ class Extension(RevMixin, AclMixin, models.Model):
)
)
class Meta :
class Meta :
permissions = (
permissions = ( ( " use_all_extension " , _ ( " Can use all extensions " ) ) , )
( " use_all_extension " , _ ( " Can use all extensions " ) ) ,
)
verbose_name = _ ( " DNS extension " )
verbose_name = _ ( " DNS extension " )
verbose_name_plural = _ ( " DNS extensions " )
verbose_name_plural = _ ( " DNS extensions " )
@ -977,7 +958,7 @@ class Extension(RevMixin, AclMixin, models.Model):
@classmethod
@classmethod
def can_list ( cls , user_request , * _args , * * _kwargs ) :
def can_list ( cls , user_request , * _args , * * _kwargs ) :
""" All users can list unprivileged extensions
""" All users can list unprivileged extensions
Only members of privileged groups can list all .
Only members of privileged groups can list all .
: param user_request : The user who wants to view the list .
: param user_request : The user who wants to view the list .
@ -987,12 +968,7 @@ class Extension(RevMixin, AclMixin, models.Model):
"""
"""
can , _message , _group = cls . can_use_all ( user_request )
can , _message , _group = cls . can_use_all ( user_request )
if can :
if can :
return (
return ( True , None , None , cls . objects . all ( ) )
True ,
None ,
None ,
cls . objects . all ( )
)
else :
else :
return (
return (
True ,
True ,
@ -1035,8 +1011,7 @@ class Mx(RevMixin, AclMixin, models.Model):
@cached_property
@cached_property
def dns_entry ( self ) :
def dns_entry ( self ) :
""" Get the complete DNS entry of the MX record, to put in zone files.
""" Get the complete DNS entry of the MX record, to put in zone files. """
"""
return " @ IN MX {prior} {name} " . format (
return " @ IN MX {prior} {name} " . format (
prior = str ( self . priority ) . ljust ( 3 ) , name = str ( self . name )
prior = str ( self . priority ) . ljust ( 3 ) , name = str ( self . name )
)
)
@ -1066,8 +1041,7 @@ class Ns(RevMixin, AclMixin, models.Model):
@cached_property
@cached_property
def dns_entry ( self ) :
def dns_entry ( self ) :
""" Get the complete DNS entry of the NS record, to put in zone files.
""" Get the complete DNS entry of the NS record, to put in zone files. """
"""
return " @ IN NS " + str ( self . ns )
return " @ IN NS " + str ( self . ns )
def __str__ ( self ) :
def __str__ ( self ) :
@ -1100,8 +1074,7 @@ class Txt(RevMixin, AclMixin, models.Model):
@cached_property
@cached_property
def dns_entry ( self ) :
def dns_entry ( self ) :
""" Get the complete DNS entry of the TXT record, to put in zone files.
""" Get the complete DNS entry of the TXT record, to put in zone files. """
"""
return str ( self . field1 ) . ljust ( 15 ) + " IN TXT " + str ( self . field2 )
return str ( self . field1 ) . ljust ( 15 ) + " IN TXT " + str ( self . field2 )
@ -1129,8 +1102,7 @@ class DName(RevMixin, AclMixin, models.Model):
@cached_property
@cached_property
def dns_entry ( self ) :
def dns_entry ( self ) :
""" Get the complete DNS entry of the TXT record, to put in zone files.
""" Get the complete DNS entry of the TXT record, to put in zone files. """
"""
return str ( self . alias ) . ljust ( 15 ) + " IN DNAME " + str ( self . zone )
return str ( self . alias ) . ljust ( 15 ) + " IN DNAME " + str ( self . zone )
@ -1204,8 +1176,7 @@ class Srv(RevMixin, AclMixin, models.Model):
@cached_property
@cached_property
def dns_entry ( self ) :
def dns_entry ( self ) :
""" Get the complete DNS entry of the SRV record, to put in zone files.
""" Get the complete DNS entry of the SRV record, to put in zone files. """
"""
return (
return (
str ( self . service )
str ( self . service )
+ " ._ "
+ " ._ "
@ -1387,8 +1358,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
return vendor
return vendor
def sync_ipv6_dhcpv6 ( self ) :
def sync_ipv6_dhcpv6 ( self ) :
""" Assign an IPv6 address by DHCPv6, computed from the interface ' s ID.
""" Assign an IPv6 address by DHCPv6, computed from the interface ' s ID. """
"""
ipv6_dhcpv6 = self . gen_ipv6_dhcpv6
ipv6_dhcpv6 = self . gen_ipv6_dhcpv6
if not ipv6_dhcpv6 :
if not ipv6_dhcpv6 :
return
return
@ -1414,8 +1384,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
ipv6_object . save ( )
ipv6_object . save ( )
def sync_ipv6 ( self ) :
def sync_ipv6 ( self ) :
""" Create and update the IPv6 addresses according to the IPv6 mode set.
""" Create and update the IPv6 addresses according to the IPv6 mode set. """
"""
if preferences . models . OptionalMachine . get_cached_value ( " ipv6_mode " ) == " SLAAC " :
if preferences . models . OptionalMachine . get_cached_value ( " ipv6_mode " ) == " SLAAC " :
self . sync_ipv6_slaac ( )
self . sync_ipv6_slaac ( )
elif (
elif (
@ -1581,8 +1550,10 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
_ ( " You don ' t have the right to add a machine. " ) ,
_ ( " You don ' t have the right to add a machine. " ) ,
( " machines.add_interface " , ) ,
( " machines.add_interface " , ) ,
)
)
max_lambdauser_interfaces = preferences . models . OptionalMachine . get_cached_value (
max_lambdauser_interfaces = (
" max_lambdauser_interfaces "
preferences . models . OptionalMachine . get_cached_value (
" max_lambdauser_interfaces "
)
)
)
if machine . user != user_request :
if machine . user != user_request :
return (
return (
@ -1721,8 +1692,7 @@ class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
)
)
slaac_ip = models . BooleanField ( default = False )
slaac_ip = models . BooleanField ( default = False )
active = models . BooleanField (
active = models . BooleanField (
default = True ,
default = True , help_text = _ ( " If false,the DNS will not provide this ip. " )
help_text = _ ( " If false,the DNS will not provide this ip. " )
)
)
class Meta :
class Meta :
@ -1856,8 +1826,9 @@ class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
def check_and_replace_prefix ( self , prefix = None ) :
def check_and_replace_prefix ( self , prefix = None ) :
""" Check if the IPv6 prefix is correct and update it if not. """
""" Check if the IPv6 prefix is correct and update it if not. """
prefix_v6 = prefix or self . interface . machine_type . ip_type . prefix_v6 . encode ( ) . decode (
prefix_v6 = (
" utf-8 "
prefix
or self . interface . machine_type . ip_type . prefix_v6 . encode ( ) . decode ( " utf-8 " )
)
)
if not prefix_v6 :
if not prefix_v6 :
return
return
@ -1930,7 +1901,11 @@ class Domain(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
)
)
extension = models . ForeignKey ( " Extension " , on_delete = models . PROTECT )
extension = models . ForeignKey ( " Extension " , on_delete = models . PROTECT )
cname = models . ForeignKey (
cname = models . ForeignKey (
" self " , null = True , blank = True , related_name = " related_domain " , on_delete = models . PROTECT
" self " ,
null = True ,
blank = True ,
related_name = " related_domain " ,
on_delete = models . PROTECT ,
)
)
ttl = models . PositiveIntegerField (
ttl = models . PositiveIntegerField (
verbose_name = _ ( " Time To Live (TTL) " ) ,
verbose_name = _ ( " Time To Live (TTL) " ) ,
@ -1940,9 +1915,7 @@ class Domain(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
class Meta :
class Meta :
unique_together = ( ( " name " , " extension " ) , )
unique_together = ( ( " name " , " extension " ) , )
permissions = (
permissions = ( ( " change_ttl " , _ ( " Can change the TTL of a domain object " ) ) , )
( " change_ttl " , _ ( " Can change the TTL of a domain object " ) ) ,
)
verbose_name = _ ( " domain " )
verbose_name = _ ( " domain " )
verbose_name_plural = _ ( " domains " )
verbose_name_plural = _ ( " domains " )
@ -2037,8 +2010,10 @@ class Domain(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
except Interface . DoesNotExist :
except Interface . DoesNotExist :
return False , _ ( " Nonexistent interface. " ) , None
return False , _ ( " Nonexistent interface. " ) , None
if not user_request . has_perm ( " machines.add_domain " ) :
if not user_request . has_perm ( " machines.add_domain " ) :
max_lambdauser_aliases = preferences . models . OptionalMachine . get_cached_value (
max_lambdauser_aliases = (
" max_lambdauser_aliases "
preferences . models . OptionalMachine . get_cached_value (
" max_lambdauser_aliases "
)
)
)
if interface . machine . user != user_request :
if interface . machine . user != user_request :
return (
return (
@ -2173,8 +2148,7 @@ class IpList(RevMixin, AclMixin, models.Model):
@cached_property
@cached_property
def need_infra ( self ) :
def need_infra ( self ) :
""" Check if the ' infra ' right is required to assign this IP address.
""" Check if the ' infra ' right is required to assign this IP address. """
"""
return self . ip_type . need_infra
return self . ip_type . need_infra
def clean ( self ) :
def clean ( self ) :
@ -2206,20 +2180,13 @@ class IpList(RevMixin, AclMixin, models.Model):
"""
"""
can , _message , _group = IpType . can_use_all ( user_request )
can , _message , _group = IpType . can_use_all ( user_request )
if can :
if can :
return (
return ( True , None , None , cls . objects . all ( ) )
True ,
None ,
None ,
cls . objects . all ( )
)
else :
else :
return (
return (
True ,
True ,
_ ( " You don ' t have the right to use all machine types. " ) ,
_ ( " You don ' t have the right to use all machine types. " ) ,
( " machines.use_all_machinetype " , ) ,
( " machines.use_all_machinetype " , ) ,
cls . objects . filter (
cls . objects . filter ( ip_type__in = IpType . objects . filter ( need_infra = False ) ) ,
ip_type__in = IpType . objects . filter ( need_infra = False )
) ,
)
)
def __str__ ( self ) :
def __str__ ( self ) :
@ -2517,7 +2484,13 @@ class OuverturePort(RevMixin, AclMixin, models.Model):
def machine_post_save ( * * kwargs ) :
def machine_post_save ( * * kwargs ) :
""" Synchronise LDAP and regen firewall/DHCP after a machine is edited. """
""" Synchronise LDAP and regen firewall/DHCP after a machine is edited. """
user = kwargs [ " instance " ] . user
user = kwargs [ " instance " ] . user
users . signals . synchronise . send ( sender = users . models . User , instance = user , base = False , access_refresh = False , mac_refresh = True )
users . signals . synchronise . send (
sender = users . models . User ,
instance = user ,
base = False ,
access_refresh = False ,
mac_refresh = True ,
)
regen ( " dhcp " )
regen ( " dhcp " )
regen ( " mac_ip_list " )
regen ( " mac_ip_list " )
@ -2527,7 +2500,13 @@ def machine_post_delete(**kwargs):
""" Synchronise LDAP and regen firewall/DHCP after a machine is deleted. """
""" Synchronise LDAP and regen firewall/DHCP after a machine is deleted. """
machine = kwargs [ " instance " ]
machine = kwargs [ " instance " ]
user = machine . user
user = machine . user
users . signals . synchronise . send ( sender = users . models . User , instance = user , base = False , access_refresh = False , mac_refresh = True )
users . signals . synchronise . send (
sender = users . models . User ,
instance = user ,
base = False ,
access_refresh = False ,
mac_refresh = True ,
)
regen ( " dhcp " )
regen ( " dhcp " )
regen ( " mac_ip_list " )
regen ( " mac_ip_list " )
@ -2540,7 +2519,13 @@ def interface_post_save(**kwargs):
interface = kwargs [ " instance " ]
interface = kwargs [ " instance " ]
interface . sync_ipv6 ( )
interface . sync_ipv6 ( )
user = interface . machine . user
user = interface . machine . user
users . signals . synchronise . send ( sender = users . models . User , instance = user , base = False , access_refresh = False , mac_refresh = True )
users . signals . synchronise . send (
sender = users . models . User ,
instance = user ,
base = False ,
access_refresh = False ,
mac_refresh = True ,
)
# Regen services
# Regen services
regen ( " dhcp " )
regen ( " dhcp " )
regen ( " mac_ip_list " )
regen ( " mac_ip_list " )
@ -2552,11 +2537,16 @@ def interface_post_save(**kwargs):
@receiver ( post_delete , sender = Interface )
@receiver ( post_delete , sender = Interface )
def interface_post_delete ( * * kwargs ) :
def interface_post_delete ( * * kwargs ) :
""" Synchronise LDAP and regen firewall/DHCP after an interface is deleted.
""" Synchronise LDAP and regen firewall/DHCP after an interface is deleted. """
"""
interface = kwargs [ " instance " ]
interface = kwargs [ " instance " ]
user = interface . machine . user
user = interface . machine . user
users . signals . synchronise . send ( sender = users . models . User , instance = user , base = False , access_refresh = False , mac_refresh = True )
users . signals . synchronise . send (
sender = users . models . User ,
instance = user ,
base = False ,
access_refresh = False ,
mac_refresh = True ,
)
@receiver ( post_save , sender = IpType )
@receiver ( post_save , sender = IpType )