Browse Source

доделал периодическую синхронизацию биллинга с абонентским шлюзом интернета(NAS)

devel
Dmitry 9 years ago
parent
commit
222ddd2775
  1. 59
      agent/mod_mikrotik.py
  2. 61
      cron.py

59
agent/mod_mikrotik.py

@ -4,7 +4,7 @@ import binascii
from hashlib import md5 from hashlib import md5
from .core import BaseTransmitter, NasFailedResult, NasNetworkError from .core import BaseTransmitter, NasFailedResult, NasNetworkError
from mydefs import ping from mydefs import ping
from .structs import TariffStruct, AbonStruct, IpStruct
from .structs import TariffStruct, AbonStruct, IpStruct, ShapeItem
from . import settings from . import settings
from djing.settings import DEBUG from djing.settings import DEBUG
@ -163,42 +163,60 @@ class MikrotikTransmitter(BaseTransmitter):
res.append(rt[1]) res.append(rt[1])
return res return res
# Строим объект ShapeItem из инфы, присланной из mikrotik'a
def _build_shape_obj(self, info):
speeds = info['=max-limit'].split('/')
speeds = [sp.replace('M','') for sp in speeds]
t = TariffStruct(speedIn=speeds[0], speedOut=speeds[1])
a = AbonStruct(
uid=int(info['=name'][3:]),
ip=info['=target-addresses'][:-3],
tariff=t
)
return ShapeItem(abon=a, sid=info['=.id'].replace('*', ''))
# ищем правило по имени, и возвращаем всю инфу о найденном правиле # ищем правило по имени, и возвращаем всю инфу о найденном правиле
def _find_queue(self, name):
def find_queue(self, name):
ret = self._exec_cmd(['/queue/simple/print', '?name=%s' % name]) ret = self._exec_cmd(['/queue/simple/print', '?name=%s' % name])
return ret[0]
if ret:
return self._build_shape_obj(ret[0])
def add_user_range(self, user_list): def add_user_range(self, user_list):
for usr in user_list: for usr in user_list:
self.add_user(usr) self.add_user(usr)
# В @user_ids передаём номера правил из mikrotik
def remove_user_range(self, user_ids): def remove_user_range(self, user_ids):
names = ['%d' % usr for usr in user_ids] names = ['%d' % usr for usr in user_ids]
return self._exec_cmd(['/queue/simple/remove', *names]) return self._exec_cmd(['/queue/simple/remove', *names])
# добавляем правило шейпинга для указанного ip и со скоростью max-limit=Upload/Download # добавляем правило шейпинга для указанного ip и со скоростью max-limit=Upload/Download
# Мы уверены что user это инстанс класса agent.structs.AbonStruct
# Мы уверены что @user это инстанс класса agent.structs.AbonStruct
def add_user(self, user): def add_user(self, user):
assert isinstance(user.tariff, TariffStruct) assert isinstance(user.tariff, TariffStruct)
assert isinstance(user.ip, IpStruct) assert isinstance(user.ip, IpStruct)
return self._exec_cmd(['/queue/simple/add', return self._exec_cmd(['/queue/simple/add',
'=name=uid%d' % user.uid, '=name=uid%d' % user.uid,
'=target-addresses=%s/32' % user.ip.get_str(),
'=max-limit=%fM/%fM' % (user.tariff.speedOut, user.tariff.speedIn)
'=target-addresses=%s' % user.ip.get_str(),
'=max-limit=%.3fM/%.3fM' % (user.tariff.speedOut, user.tariff.speedIn)
]) ])
# удаляем правило шейпера по имени правила # удаляем правило шейпера по имени правила
# В @user передаём номер правила в mikrotik для абонента
def remove_user(self, user): def remove_user(self, user):
uid = user if type(user) is int else user.uid
return self._exec_cmd(['/queue/simple/remove', '=name=uid%d' % uid])
assert type(user) is int
return self._exec_cmd(['/queue/simple/remove', '=.id=*'+str(user)])
# обновляем основную инфу абонента # обновляем основную инфу абонента
def update_user(self, user):
# @mk_id это номер в mikrotik
def update_user(self, user, mk_id=None):
assert mk_id is not None
assert isinstance(user.tariff, TariffStruct) assert isinstance(user.tariff, TariffStruct)
assert isinstance(user.ip, IpStruct) assert isinstance(user.ip, IpStruct)
return self._exec_cmd(['/queue/simple/set', '=name=uid%d' % user.uid,
'=max-limit=%fM/%fM' % (user.tariff.speedOut, user.tariff.speedIn),
'=target-addresses=%s/32' % user.ip.get_str()
return self._exec_cmd(['/queue/simple/set', '=.id=*'+mk_id,
'=name=uid%d' % user.uid,
'=max-limit=%.3fM/%.3fM' % (user.tariff.speedOut, user.tariff.speedIn),
'=target-addresses=%s' % user.ip.get_str()
]) ])
# читаем абонентов, возващаем абнента и номер в микротике # читаем абонентов, возващаем абнента и номер в микротике
@ -206,16 +224,9 @@ class MikrotikTransmitter(BaseTransmitter):
ret_it = self._exec_cmd_iter(['/queue/simple/print', '=detail']) ret_it = self._exec_cmd_iter(['/queue/simple/print', '=detail'])
for re in ret_it: for re in ret_it:
if re[0] == '!done': return if re[0] == '!done': return
speeds = re[1]['=limit-at'].split('/')
speeds = [sp.replace('M','') for sp in speeds]
abon = AbonStruct(
uid=int(re[1]['=name'][3:]),
ip=IpStruct(re[1]['=target-addresses'][:-3]),
tariff=TariffStruct(speedIn=speeds[0], speedOut=speeds[1])
)
yield abon
# то же что и выше, только получаем номера в микротике
yield self._build_shape_obj(re[1])
# то же что и выше, только получаем только номера в микротике
def read_users_mikroids_iter(self): def read_users_mikroids_iter(self):
ret_it = self._exec_cmd_iter(['/queue/simple/print', '=detail']) ret_it = self._exec_cmd_iter(['/queue/simple/print', '=detail'])
for re in ret_it: for re in ret_it:
@ -225,12 +236,12 @@ class MikrotikTransmitter(BaseTransmitter):
# приостановливаем обслуживание абонента # приостановливаем обслуживание абонента
# в @user передаём номер в микротике # в @user передаём номер в микротике
def pause_user(self, user): def pause_user(self, user):
self._exec_cmd(['/queue/simple/disable', user])
self._exec_cmd(['/queue/simple/disable', '=.id=*'+user])
# продолжаем обслуживание абонента # продолжаем обслуживание абонента
# в @user передаём номер в микротике # в @user передаём номер в микротике
def start_user(self, user): def start_user(self, user):
self._exec_cmd(['/queue/simple/enable', user])
self._exec_cmd(['/queue/simple/enable', '=.id=*'+user])
# Тарифы хранить нам не надо, так что методы тарифов ниже не реализуем # Тарифы хранить нам не надо, так что методы тарифов ниже не реализуем
def add_tariff_range(self, tariff_list): def add_tariff_range(self, tariff_list):

61
cron.py

@ -8,35 +8,54 @@ if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djing.settings") os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djing.settings")
django.setup() django.setup()
from abonapp.models import Abon from abonapp.models import Abon
from agent import Transmitter, AbonStruct, TariffStruct, NasFailedResult
from agent import Transmitter
tm = Transmitter() tm = Transmitter()
# получим инфу о записях в NAS
queues = [queue for queue in tm.read_users_iter()]
users = Abon.objects.all() users = Abon.objects.all()
for user in users: for user in users:
# если нет ip то и нет смысла лезть в NAS
if user.ip_address is None: if user.ip_address is None:
continue continue
cur_tar = user.active_tariff()
if cur_tar is None:
# а есть-ли у абонента доступ к услуге
if not user.is_access():
continue
# строим структуру агента
ab = user.build_agent_struct()
if ab is None:
# если не построилась структура агента, значит нет ip
# а если нет ip то и синхронизировать абонента без ip нельзя
continue
# ищем абонента в списке инфы из nas
abons = [{'abon': queue.abon, 'mikro_id': queue.sid} for queue in queues if queue.abon.uid == user.pk]
abons_len = len(abons)
if abons_len < 1:
# абонент не найден в nas, добавим
tm.add_user(ab)
continue continue
ab = AbonStruct(
uid=user.id,
ip=user.ip_address.int_ip(),
tariff=TariffStruct(
tariff_id=cur_tar.id,
speedIn=cur_tar.speedIn,
speedOut=cur_tar.speedOut
elif abons_len > 1:
# удаляем срез из nas, всё кроме 1й записи
tm.remove_user_range(
[mkid['mikro_id'] for mkid in abons[1:]]
) )
)
# обновляем абонента на NAS
mikroid = tm._find_queue('uid%d' % user.id)
if mikroid:
mikroid = mikroid['=.id'].replace('*', '')
tm.update_user(ab)
# один абонент
# сравним совпадает-ли инфа об абоненте в базе и в nas
if ab == abons[0]['abon']:
# если всё совпадает, то менять нечего
continue
else:
print('Change abon:', user.get_full_name())
# иначе обновляем абонента
tm.update_user(ab, abons[0]['mikro_id'])
# если не активен то приостановим услугу # если не активен то приостановим услугу
if user.is_active: if user.is_active:
tm.start_user(mikroid)
tm.start_user(abons[0]['mikro_id'])
else: else:
tm.pause_user(mikroid)
else:
tm.add_user(ab)
tm.pause_user(abons[0]['mikro_id'])
Loading…
Cancel
Save