Browse Source

Merge branch 'master' of https://github.com/bashmak/djing

# Conflicts:
#	agent/mod_mikrotik.py
devel
Dmitry 9 years ago
parent
commit
65953dae5c
  1. 88
      agent/mod_mikrotik.py

88
agent/mod_mikrotik.py

@ -4,9 +4,8 @@ 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, IpStruct
from . import settings from . import settings
from djing.settings import DEBUG
class ApiRos: class ApiRos:
@ -16,17 +15,18 @@ class ApiRos:
self.currenttag = 0 self.currenttag = 0
def login(self, username, pwd): def login(self, username, pwd):
for repl, attrs in self.talk_iter(["/login"]):
for repl, attrs in self.talk(["/login"]):
chal = binascii.unhexlify(attrs['=ret']) chal = binascii.unhexlify(attrs['=ret'])
md = md5() md = md5()
md.update(b'\x00') md.update(b'\x00')
md.update(bytes(pwd, 'utf-8')) md.update(bytes(pwd, 'utf-8'))
md.update(chal) md.update(chal)
for r in self.talk_iter(["/login", "=name=" + username,
"=response=00" + binascii.hexlify(md.digest()).decode('utf-8')]): pass
self.talk(["/login", "=name=" + username,
"=response=00" + binascii.hexlify(md.digest()).decode('utf-8')])
def talk_iter(self, words):
def talk(self, words):
if self.writeSentence(words) == 0: return if self.writeSentence(words) == 0: return
r = []
while 1: while 1:
i = self.readSentence() i = self.readSentence()
if len(i) == 0: continue if len(i) == 0: continue
@ -38,8 +38,8 @@ class ApiRos:
attrs[w] = '' attrs[w] = ''
else: else:
attrs[w[:j]] = w[j+1:] attrs[w[:j]] = w[j+1:]
yield (reply, attrs)
if reply == '!done': return
r.append((reply, attrs))
if reply == '!done': return r
def writeSentence(self, words): def writeSentence(self, words):
ret = 0 ret = 0
@ -57,16 +57,14 @@ class ApiRos:
r.append(w) r.append(w)
def writeWord(self, w): def writeWord(self, w):
if DEBUG:
print("<<< " + w)
print("<<< " + w)
b = bytes(w, "utf-8") b = bytes(w, "utf-8")
self.writeLen(len(b)) self.writeLen(len(b))
self.writeBytes(b) self.writeBytes(b)
def readWord(self): def readWord(self):
ret = self.readBytes(self.readLen()).decode('utf-8') ret = self.readBytes(self.readLen()).decode('utf-8')
if DEBUG:
print(">>> " + ret)
print(">>> " + ret)
return ret return ret
def writeLen(self, l): def writeLen(self, l):
@ -132,6 +130,7 @@ class ApiRos:
return ret return ret
# TODO: Реализовать передачу в шейпер срок действия тарифа
class MikrotikTransmitter(BaseTransmitter): class MikrotikTransmitter(BaseTransmitter):
def __init__(self, login=None, password=None, ip=None, port=None): def __init__(self, login=None, password=None, ip=None, port=None):
ip = ip or settings.NAS_IP ip = ip or settings.NAS_IP
@ -145,36 +144,25 @@ class MikrotikTransmitter(BaseTransmitter):
except ConnectionRefusedError: except ConnectionRefusedError:
raise NasNetworkError('Подключение к %s отклонено (Connection Refused)' % ip) raise NasNetworkError('Подключение к %s отклонено (Connection Refused)' % ip)
def _exec_cmd_iter(self, cmd):
assert isinstance(cmd, list)
result_iter = self.ar.talk_iter(cmd)
for rt in result_iter:
if rt[0] == '!trap':
raise NasFailedResult(rt[1]['=message'])
yield rt
def _exec_cmd(self, cmd): def _exec_cmd(self, cmd):
assert isinstance(cmd, list) assert isinstance(cmd, list)
result_iter = self.ar.talk_iter(cmd)
res = []
for rt in result_iter:
result = self.ar.talk(cmd)
for rt in result:
if rt[0] == '!trap': if rt[0] == '!trap':
raise NasFailedResult(rt[1]['=message']) raise NasFailedResult(rt[1]['=message'])
res.append(rt[1])
return res
return result
# ищем правило по имени, и возвращаем всю инфу о найденном правиле # ищем правило по имени, и возвращаем всю инфу о найденном правиле
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]
return ret[0][1]
def add_user_range(self, user_list): def add_user_range(self, user_list):
for usr in user_list:
self.add_user(usr)
return list(map(self.add_user, user_list))
def remove_user_range(self, user_ids):
names = ['%d' % usr for usr in user_ids]
return self._exec_cmd(['/queue/simple/remove', *names])
def remove_user_range(self, user_list):
names = ['uid%d' % usr.uid for usr in user_list]
return self._exec_cmd(['/queue/simple/remove', '=.id=%s' % ','.join(names)])
# добавляем правило шейпинга для указанного ip и со скоростью max-limit=Upload/Download # добавляем правило шейпинга для указанного ip и со скоростью max-limit=Upload/Download
# Мы уверены что user это инстанс класса agent.structs.AbonStruct # Мы уверены что user это инстанс класса agent.structs.AbonStruct
@ -190,63 +178,41 @@ class MikrotikTransmitter(BaseTransmitter):
# удаляем правило шейпера по имени правила # удаляем правило шейпера по имени правила
def remove_user(self, user): def remove_user(self, user):
uid = user if type(user) is int else user.uid uid = user if type(user) is int else user.uid
return self._exec_cmd(['/queue/simple/remove', '=name=uid%d' % uid])
self._exec_cmd(['/queue/simple/remove', '=.id=uid%d' % uid])
# обновляем основную инфу абонента # обновляем основную инфу абонента
def update_user(self, user): def update_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/set', '=name=uid%d' % user.uid,
self._exec_cmd(['/queue/simple/set', '=.id=uid%d' % user.uid,
'=max-limit=%fM/%fM' % (user.tariff.speedOut, user.tariff.speedIn), '=max-limit=%fM/%fM' % (user.tariff.speedOut, user.tariff.speedIn),
'=target-addresses=%s/32' % user.ip.get_str() '=target-addresses=%s/32' % user.ip.get_str()
]) ])
# читаем абонентов, возващаем абнента и номер в микротике
def read_users_iter(self):
ret_it = self._exec_cmd_iter(['/queue/simple/print', '=detail'])
for re in ret_it:
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
# то же что и выше, только получаем номера в микротике
def read_users_mikroids_iter(self):
ret_it = self._exec_cmd_iter(['/queue/simple/print', '=detail'])
for re in ret_it:
if re[0] == '!done': return
yield int(re[1]['=.id'].replace('*', ''), base=16)
# приостановливаем обслуживание абонента # приостановливаем обслуживание абонента
# в @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=uid%d' % user.uid])
# продолжаем обслуживание абонента # продолжаем обслуживание абонента
# в @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=uid%d' % user.uid])
# Тарифы хранить нам не надо, так что методы тарифов ниже не реализуем # Тарифы хранить нам не надо, так что методы тарифов ниже не реализуем
def add_tariff_range(self, tariff_list): def add_tariff_range(self, tariff_list):
pass pass
# соответственно и удалять тарифы не надо
# todo: реальзовать
def remove_tariff_range(self, tariff_list): def remove_tariff_range(self, tariff_list):
pass pass
# и добавлять тоже
# todo: реальзовать
def add_tariff(self, tariff): def add_tariff(self, tariff):
pass pass
# и обновлять
# todo: реальзовать
def update_tariff(self, tariff): def update_tariff(self, tariff):
pass pass
# todo: реальзовать
def remove_tariff(self, tid): def remove_tariff(self, tid):
pass pass
Loading…
Cancel
Save