Dmitry Novikov 8 years ago
parent
commit
5f9757b69c
  1. 4
      abonapp/models.py
  2. 18
      abonapp/views.py
  3. 6
      agent/core.py
  4. 61
      agent/mod_mikrotik.py
  5. 32
      agent/structs.py
  6. 15
      djing/lib/__init__.py
  7. 3
      ip_pool/models.py

4
abonapp/models.py

@ -215,8 +215,8 @@ class Abon(BaseAccount):
# make subscriber from agent structure
def build_agent_struct(self):
abon_addresses = tuple(ip_address(i.ip) for i in self.ip_addresses.filter(is_active=True))
if not abon_addresses:
return
# if not abon_addresses:
# return
abon_tariff = self.active_tariff()
if abon_tariff is None:
agent_trf = None

18
abonapp/views.py

@ -1,3 +1,4 @@
from ipaddress import ip_address
from typing import Dict, Optional
from datetime import datetime, date
from django.contrib.gis.shortcuts import render_to_text
@ -16,7 +17,6 @@ from django.conf import settings
from jsonview.decorators import json_view
from agent.commands.dhcp import dhcp_commit, dhcp_expiry, dhcp_release
from agent.structs import IpStruct
from statistics.models import StatCache
from tariff_app.models import Tariff
from agent import NasFailedResult, Transmitter, NasNetworkError
@ -1117,16 +1117,20 @@ def user_session_toggle(request, gid, uname, lease_id, action=None):
lease = abon.ip_addresses.get(pk=lease_id)
tm = Transmitter()
abon_nas_obj = abon.build_agent_struct()
res_text = '#Parameter needed#'
try:
if action == 'free':
if abon.ip_addresses.filter(is_active=True).count() > 1:
tm.lease_free(abon_nas_obj, ip_address(lease.ip))
lease.free()
tm.lease_free(abon_nas_obj, IpStruct(lease.ip))
res_text = _('Ip lease has been freed')
messages.success(request, _('Ip lease has been freed'))
else:
messages.error(request, _('You cannot disable last session'))
elif action == 'start':
tm.lease_start(abon_nas_obj, ip_address(lease.ip))
lease.start()
tm.lease_start(abon_nas_obj, IpStruct(lease.ip))
res_text = _('Ip lease has been started')
messages.success(request, res_text)
messages.success(request, _('Ip lease has been started'))
except NasFailedResult as e:
messages.error(request, e)
return redirect('abonapp:abon_home', gid, uname)

6
agent/core.py

@ -1,7 +1,7 @@
from abc import ABC, abstractmethod
from typing import Iterator, Any, Tuple, Optional
from .structs import AbonStruct, TariffStruct, VectorAbon, VectorTariff, IpStruct
from .structs import AbonStruct, TariffStruct, VectorAbon, VectorTariff
# Raised if NAS has returned failed result
@ -78,14 +78,14 @@ class BaseTransmitter(ABC):
pass
@abstractmethod
def lease_free(self, user: AbonStruct, lease: IpStruct):
def lease_free(self, user: AbonStruct, lease):
"""
Remove ip lease from allowed to network
:return:
"""
@abstractmethod
def lease_start(self, user: AbonStruct, lease: IpStruct):
def lease_start(self, user: AbonStruct, lease):
"""
Starts ip lease to allowed to network
:return:

61
agent/mod_mikrotik.py

@ -3,13 +3,14 @@ import socket
import binascii
from abc import ABCMeta
from hashlib import md5
from ipaddress import ip_network, _BaseAddress
from ipaddress import _BaseAddress, ip_address
from typing import Iterable, Optional, Tuple, Generator, Dict
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from djing.lib.decorators import LazyInitMetaclass
from .structs import TariffStruct, AbonStruct, IpStruct, VectorAbon, VectorTariff
from .structs import TariffStruct, AbonStruct, VectorAbon, VectorTariff
from . import settings as local_settings
from djing import ping
from agent.core import BaseTransmitter, NasNetworkError, NasFailedResult
@ -161,18 +162,11 @@ class ApiRos(object):
return ret
def __del__(self):
if hasattr(self, 'sk'):
sk = getattr(self, 'sk')
if sk is not None:
self.sk.close()
class IpAddressListObj(IpStruct):
__slots__ = ('__ip', 'mk_id')
def __init__(self, ip, mk_id):
super(IpAddressListObj, self).__init__(ip)
self.mk_id = str(mk_id).replace('*', '')
class MikrotikTransmitter(BaseTransmitter, ApiRos, metaclass=type('_ABC_Lazy_mcs', (ABCMeta, LazyInitMetaclass), {})):
def __init__(self, login=None, password=None, ip=None, port=None):
@ -246,17 +240,18 @@ class MikrotikTransmitter(BaseTransmitter, ApiRos, metaclass=type('_ABC_Lazy_mcs
if disabled is not None:
disabled = True if disabled == 'true' else False
if target is not None and name is not None:
target_ip, target_net = target.split('/')
# target may be '192.168.0.3/32,192.168.0.2/32'
ips = (ip.split('/')[0] for ip in target.split(','))
a = AbonStruct(
uid=int(name[3:]),
ip=target_ip,
ips=ips,
tariff=t,
is_active=disabled or False
is_access=disabled or False
)
a.queue_id = info.get('=.id')
return a
except ValueError:
pass
except ValueError as e:
print('ValueError:', e)
#################################################
# QUEUES
@ -266,18 +261,19 @@ class MikrotikTransmitter(BaseTransmitter, ApiRos, metaclass=type('_ABC_Lazy_mcs
def find_queue(self, name: str) -> Optional[AbonStruct]:
r = self._exec_cmd(('/queue/simple/print', '?name=%s' % name))
if r:
return self._build_shape_obj(r)
return self._build_shape_obj(r.get('!re'))
def add_queue(self, user: AbonStruct) -> None:
if not isinstance(user, AbonStruct):
raise TypeError
if user.tariff is None or not isinstance(user.tariff, TariffStruct):
return
ips = ','.join(str(i) for i in user.ips)
self._exec_cmd((
'/queue/simple/add',
'=name=uid%d' % user.uid,
# FIXME: тут в разных микротиках или =target-addresses или =target
'=target=%s' % ','.join(str(i) for i in user.ips),
'=target=%s' % ips,
'=max-limit=%.3fM/%.3fM' % (user.tariff.speedOut, user.tariff.speedIn),
'=queue=MikroBILL_SFQ/MikroBILL_SFQ',
'=burst-time=1/1'
@ -314,7 +310,7 @@ class MikrotikTransmitter(BaseTransmitter, ApiRos, metaclass=type('_ABC_Lazy_mcs
'/queue/simple/set',
'=name=uid%d' % user.uid,
'=max-limit=%.3fM/%.3fM' % (user.tariff.speedOut, user.tariff.speedIn),
# FIXME: тут в разных микротиках или =target-addresses или =target
# FIXME: тут в разных версиях прошивки микротика или =target-addresses или =target
'=target=%s' % ','.join(str(i) for i in user.ips),
'=queue=MikroBILL_SFQ/MikroBILL_SFQ',
'=burst-time=1/1'
@ -334,8 +330,8 @@ class MikrotikTransmitter(BaseTransmitter, ApiRos, metaclass=type('_ABC_Lazy_mcs
# Ip->firewall->address list
#################################################
def add_ip(self, list_name: str, ip: IpStruct):
if not isinstance(ip, IpStruct):
def add_ip(self, list_name: str, ip):
if not issubclass(ip.__class__, _BaseAddress):
raise TypeError
commands = (
'/ip/firewall/address-list/add',
@ -373,7 +369,7 @@ class MikrotikTransmitter(BaseTransmitter, ApiRos, metaclass=type('_ABC_Lazy_mcs
'?dynamic=no'
))
for dat in ips:
yield IpAddressListObj(dat.get('=address'), dat.get('=.id'))
yield ip_address(dat.get('=address')), dat.get('=.id')
#################################################
# BaseTransmitter implementation
@ -402,7 +398,7 @@ class MikrotikTransmitter(BaseTransmitter, ApiRos, metaclass=type('_ABC_Lazy_mcs
raise TypeError
self.add_queue(user)
for ip in user.ips:
if not isinstance(ip, IpStruct):
if not issubclass(ip.__class__, _BaseAddress):
raise TypeError
self.add_ip(LIST_USERS_ALLOWED, ip)
@ -444,7 +440,7 @@ class MikrotikTransmitter(BaseTransmitter, ApiRos, metaclass=type('_ABC_Lazy_mcs
self.add_queue(user)
return
if queue != user:
self.update_queue(user)
self.update_queue(user, queue)
def ping(self, host, count=10) -> Optional[Tuple[int, int]]:
r = self._exec_cmd((
@ -503,20 +499,25 @@ class MikrotikTransmitter(BaseTransmitter, ApiRos, metaclass=type('_ABC_Lazy_mcs
# self.remove_ip_range(diff)
return queues
def lease_free(self, user: AbonStruct, lease: IpStruct):
ip = self.find_ip(lease, LIST_USERS_ALLOWED)
if ip is not None:
self.remove_ip(ip.get('=.id'))
def lease_free(self, user: AbonStruct, lease):
queue = self.find_queue('uid%d' % user.uid)
if len(queue.ips) > 1:
if queue is not None:
user.ips = tuple(i for i in user.ips if i != lease)
self.update_queue(user, queue)
ip = self.find_ip(lease, LIST_USERS_ALLOWED)
if ip is not None:
self.remove_ip(ip.get('=.id'))
else:
raise NasFailedResult(_('You cannot disable last session'))
def lease_start(self, user: AbonStruct, lease: IpStruct):
def lease_start(self, user: AbonStruct, lease):
ip = self.find_ip(lease, LIST_USERS_ALLOWED)
if ip is None:
self.add_ip(LIST_USERS_ALLOWED, lease)
queue = self.find_queue('uid%d' % user.uid)
if queue is not None:
user.ips += lease,
if queue is None:
self.add_queue(user)
else:
self.update_queue(user, queue)

32
agent/structs.py

@ -1,40 +1,12 @@
# -*- coding: utf-8 -*-
from abc import ABCMeta
from ipaddress import ip_address
from typing import Iterable
from djing.lib import int2ip, ip2int
class BaseStruct(object, metaclass=ABCMeta):
__slots__ = ()
class IpStruct(BaseStruct):
__slots__ = ('__ip',)
def __init__(self, ip):
if type(ip) is int:
self.__ip = ip
else:
self.__ip = ip2int(str(ip))
def get_int(self):
return self.__ip
def __eq__(self, other):
if not isinstance(other, IpStruct):
raise TypeError('Instance must be IpStruct')
return self.__ip == other.__ip
def __int__(self):
return self.__ip
def __str__(self):
return int2ip(self.__ip)
def __hash__(self):
return hash(self.__ip)
# Как обслуживается абонент
class TariffStruct(BaseStruct):
__slots__ = ('tid', 'speedIn', 'speedOut')
@ -71,7 +43,7 @@ class AbonStruct(BaseStruct):
if ips is None:
self.ips = ()
else:
self.ips = tuple(IpStruct(ip) for ip in ips)
self.ips = tuple(ip_address(ip) for ip in ips)
self.tariff = tariff
self.is_access = is_access
self.queue_id = 0

15
djing/lib/__init__.py

@ -1,25 +1,10 @@
import socket
import struct
from functools import wraps
from hashlib import sha256
from datetime import timedelta
from collections import Iterator
def ip2int(addr):
try:
return struct.unpack("!I", socket.inet_aton(addr))[0]
except:
return 0
def int2ip(addr):
try:
return socket.inet_ntoa(struct.pack("!I", addr))
except:
return ''
def safe_float(fl):
try:
return 0.0 if fl is None or fl == '' else float(fl)

3
ip_pool/models.py

@ -10,6 +10,7 @@ from django.db import models
from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _
from djing.fields import MACAddressField
from djing.lib import DuplicateEntry
from ip_pool.fields import GenericIpAddressWithPrefix
from group_app.models import Group
@ -162,9 +163,11 @@ class IpLeaseManager(models.Manager):
class IpLeaseModel(models.Model):
ip = models.GenericIPAddressField(verbose_name=_('Ip address'), unique=True)
network = models.ForeignKey(NetworkModel, on_delete=models.CASCADE, verbose_name=_('Parent network'))
mac_addr = MACAddressField(verbose_name=_('Mac address'), null=True, blank=True, unique=True)
lease_time = models.DateTimeField(_('Lease time'), auto_now_add=True)
is_dynamic = models.BooleanField(_('Is dynamic'), default=False)
is_active = models.BooleanField(_('Is active'), default=True)
device_info = models.CharField(null=True, blank=True, default=None, max_length=128)
objects = IpLeaseManager()

Loading…
Cancel
Save