|
|
|
@ -1,13 +1,10 @@ |
|
|
|
from datetime import timedelta |
|
|
|
from ipaddress import ip_network, ip_address |
|
|
|
from typing import Optional, Generator |
|
|
|
|
|
|
|
from django.conf import settings |
|
|
|
from django.db.utils import IntegrityError |
|
|
|
from django.shortcuts import resolve_url |
|
|
|
from django.core.exceptions import ValidationError, ImproperlyConfigured |
|
|
|
from django.core.exceptions import ValidationError |
|
|
|
from django.db import models |
|
|
|
from django.utils.timezone import now |
|
|
|
from django.utils.translation import gettext_lazy as _ |
|
|
|
|
|
|
|
from djing.fields import MACAddressField |
|
|
|
@ -21,7 +18,8 @@ class NetworkModel(models.Model): |
|
|
|
|
|
|
|
network = GenericIpAddressWithPrefix( |
|
|
|
verbose_name=_('IP network'), |
|
|
|
help_text=_('Ip address of network. For example: 192.168.1.0 or fde8:6789:1234:1::'), |
|
|
|
help_text=_('Ip address of network. For example: ' |
|
|
|
'192.168.1.0 or fde8:6789:1234:1::'), |
|
|
|
unique=True |
|
|
|
) |
|
|
|
NETWORK_KINDS = ( |
|
|
|
@ -31,7 +29,10 @@ class NetworkModel(models.Model): |
|
|
|
('device', _('Devices')), |
|
|
|
('admin', _('Admin')) |
|
|
|
) |
|
|
|
kind = models.CharField(_('Kind of network'), max_length=6, choices=NETWORK_KINDS, default='guest') |
|
|
|
kind = models.CharField( |
|
|
|
_('Kind of network'), max_length=6, |
|
|
|
choices=NETWORK_KINDS, default='guest' |
|
|
|
) |
|
|
|
description = models.CharField(_('Description'), max_length=64) |
|
|
|
groups = models.ManyToManyField(Group, verbose_name=_('Groups')) |
|
|
|
|
|
|
|
@ -56,33 +57,53 @@ class NetworkModel(models.Model): |
|
|
|
def clean(self): |
|
|
|
errs = {} |
|
|
|
if self.network is None: |
|
|
|
errs['network'] = ValidationError(_('Network is invalid'), code='invalid') |
|
|
|
errs['network'] = ValidationError( |
|
|
|
_('Network is invalid'), |
|
|
|
code='invalid' |
|
|
|
) |
|
|
|
raise ValidationError(errs) |
|
|
|
net = self.get_network() |
|
|
|
if self.ip_start is None: |
|
|
|
errs['ip_start'] = ValidationError(_('Ip start is invalid'), code='invalid') |
|
|
|
errs['ip_start'] = ValidationError( |
|
|
|
_('Ip start is invalid'), |
|
|
|
code='invalid' |
|
|
|
) |
|
|
|
raise ValidationError(errs) |
|
|
|
start_ip = ip_address(self.ip_start) |
|
|
|
if start_ip not in net: |
|
|
|
errs['ip_start'] = ValidationError(_('Start ip must be in subnet of specified network'), code='invalid') |
|
|
|
errs['ip_start'] = ValidationError( |
|
|
|
_('Start ip must be in subnet of specified network'), |
|
|
|
code='invalid' |
|
|
|
) |
|
|
|
if self.ip_end is None: |
|
|
|
errs['ip_end'] = ValidationError(_('Ip end is invalid'), code='invalid') |
|
|
|
errs['ip_end'] = ValidationError( |
|
|
|
_('Ip end is invalid'), |
|
|
|
code='invalid' |
|
|
|
) |
|
|
|
raise ValidationError(errs) |
|
|
|
end_ip = ip_address(self.ip_end) |
|
|
|
if end_ip not in net: |
|
|
|
errs['ip_end'] = ValidationError(_('End ip must be in subnet of specified network'), code='invalid') |
|
|
|
errs['ip_end'] = ValidationError( |
|
|
|
_('End ip must be in subnet of specified network'), |
|
|
|
code='invalid' |
|
|
|
) |
|
|
|
if errs: |
|
|
|
raise ValidationError(errs) |
|
|
|
|
|
|
|
other_nets = NetworkModel.objects.exclude(pk=self.pk).only('network').order_by('network') |
|
|
|
other_nets = NetworkModel.objects.exclude( |
|
|
|
pk=self.pk |
|
|
|
).only('network').order_by('network') |
|
|
|
if not other_nets.exists(): |
|
|
|
return |
|
|
|
for onet in other_nets.iterator(): |
|
|
|
onet_netw = onet.get_network() |
|
|
|
if net.overlaps(onet_netw): |
|
|
|
errs['network'] = ValidationError(_('Network is overlaps with %(other_network)s'), params={ |
|
|
|
'other_network': str(onet_netw) |
|
|
|
}) |
|
|
|
errs['network'] = ValidationError( |
|
|
|
_('Network is overlaps with %(other_network)s'), |
|
|
|
params={ |
|
|
|
'other_network': str(onet_netw) |
|
|
|
} |
|
|
|
) |
|
|
|
raise ValidationError(errs) |
|
|
|
|
|
|
|
def get_scope(self) -> str: |
|
|
|
@ -108,7 +129,8 @@ class NetworkModel(models.Model): |
|
|
|
def get_free_ip(self, employed_ips: Optional[Generator]): |
|
|
|
""" |
|
|
|
Find free ip in network. |
|
|
|
:param employed_ips: Sorted from less to more ip addresses from current network. |
|
|
|
:param employed_ips: Sorted from less to more |
|
|
|
ip addresses from current network. |
|
|
|
:return: single finded ip |
|
|
|
""" |
|
|
|
network = self.get_network() |
|
|
|
@ -144,7 +166,10 @@ class IpLeaseManager(models.Manager): |
|
|
|
netw = network.get_network() |
|
|
|
work_range_start_ip = ip_address(network.ip_start) |
|
|
|
work_range_end_ip = ip_address(network.ip_end) |
|
|
|
employed_ip_queryset = self.filter(network=network, is_dynamic=False).order_by('ip').only('ip') |
|
|
|
employed_ip_queryset = self.filter( |
|
|
|
network=network, |
|
|
|
is_dynamic=False |
|
|
|
).order_by('ip').only('ip') |
|
|
|
|
|
|
|
if employed_ip_queryset.exists(): |
|
|
|
used_ip_gen = employed_ip_queryset.iterator() |
|
|
|
@ -164,7 +189,8 @@ class IpLeaseManager(models.Manager): |
|
|
|
if work_range_start_ip <= net <= work_range_end_ip: |
|
|
|
return net |
|
|
|
|
|
|
|
def create_from_ip(self, ip: str, net: Optional[NetworkModel], mac=None, is_dynamic=True): |
|
|
|
def create_from_ip(self, ip: str, net: Optional[NetworkModel], |
|
|
|
mac=None, is_dynamic=True): |
|
|
|
# ip = ip_address(ip) |
|
|
|
try: |
|
|
|
return self.create( |
|
|
|
|