Browse Source

Fix when error while snmp walk

devel
bashmak 8 years ago
parent
commit
7b7e07fa0d
  1. 46
      agent/mod_mikrotik.py
  2. 29
      devapp/base_intr.py
  3. 47
      devapp/dev_types.py
  4. 15
      devapp/views.py

46
agent/mod_mikrotik.py

@ -3,7 +3,7 @@ import socket
import binascii import binascii
from abc import ABCMeta from abc import ABCMeta
from hashlib import md5 from hashlib import md5
from typing import List, Iterable
from typing import List, Iterable, Optional, Tuple
from .core import BaseTransmitter, NasFailedResult, NasNetworkError from .core import BaseTransmitter, NasFailedResult, NasNetworkError
from mydefs import ping, singleton from mydefs import ping, singleton
from .structs import TariffStruct, AbonStruct, IpStruct, VectorAbon, VectorTariff from .structs import TariffStruct, AbonStruct, IpStruct, VectorAbon, VectorTariff
@ -336,7 +336,7 @@ class IpAddressListObj(IpStruct):
class IpAddressListManager(TransmitterManager, metaclass=ABCMeta): class IpAddressListManager(TransmitterManager, metaclass=ABCMeta):
def add(self, list_name: str, ip: IpStruct, timeout=0):
def add(self, list_name: str, ip: IpStruct):
if not isinstance(ip, IpStruct): if not isinstance(ip, IpStruct):
raise TypeError raise TypeError
commands = [ commands = [
@ -344,18 +344,8 @@ class IpAddressListManager(TransmitterManager, metaclass=ABCMeta):
'=list=%s' % list_name, '=list=%s' % list_name,
'=address=%s' % str(ip) '=address=%s' % str(ip)
] ]
if timeout > 0:
commands.append('=timeout=%d' % timeout)
return self._exec_cmd(commands) return self._exec_cmd(commands)
def _edit(self, mk_id, timeout=None):
if timeout is not None:
commands = [
'/ip/firewall/address-list/set', '=.id=' + str(mk_id),
'=timeout=%d' % timeout
]
return self._exec_cmd(commands)
def remove(self, mk_id): def remove(self, mk_id):
return self._exec_cmd([ return self._exec_cmd([
'/ip/firewall/address-list/remove', '/ip/firewall/address-list/remove',
@ -410,12 +400,10 @@ class IpAddressListManager(TransmitterManager, metaclass=ABCMeta):
class MikrotikTransmitter(QueueManager, IpAddressListManager): class MikrotikTransmitter(QueueManager, IpAddressListManager):
def add_user_range(self, user_list: VectorAbon): def add_user_range(self, user_list: VectorAbon):
super(MikrotikTransmitter, self).add_user_range(user_list)
for usr in user_list: for usr in user_list:
self.add_user(usr) self.add_user(usr)
def remove_user_range(self, users: VectorAbon): def remove_user_range(self, users: VectorAbon):
super(MikrotikTransmitter, self).remove_user_range(users)
queue_ids = [usr.queue_id for usr in users if usr is not None] queue_ids = [usr.queue_id for usr in users if usr is not None]
QueueManager.remove_range(self, queue_ids) QueueManager.remove_range(self, queue_ids)
ips = [user.ip for user in users if isinstance(user, AbonStruct)] ips = [user.ip for user in users if isinstance(user, AbonStruct)]
@ -424,34 +412,30 @@ class MikrotikTransmitter(QueueManager, IpAddressListManager):
if ip_list_entity is not None and len(ip_list_entity) > 1: if ip_list_entity is not None and len(ip_list_entity) > 1:
IpAddressListManager.remove(self, ip_list_entity[0]['=.id']) IpAddressListManager.remove(self, ip_list_entity[0]['=.id'])
def add_user(self, user: AbonStruct, ip_timeout=0):
super(MikrotikTransmitter, self).add_user(user, ip_timeout)
def add_user(self, user: AbonStruct, *args):
if not isinstance(user.ip, IpStruct): if not isinstance(user.ip, IpStruct):
raise TypeError raise TypeError
if user.tariff is None or not isinstance(user.tariff, TariffStruct): if user.tariff is None or not isinstance(user.tariff, TariffStruct):
return return
QueueManager.add(self, user) QueueManager.add(self, user)
IpAddressListManager.add(self, LIST_USERS_ALLOWED, user.ip, ip_timeout)
# удаляем из списка заблокированных абонентов
IpAddressListManager.add(self, LIST_USERS_ALLOWED, user.ip)
# remove user from denied user list
firewall_ip_list_obj = IpAddressListManager.find(self, user.ip, LIST_USERS_BLOCKED) firewall_ip_list_obj = IpAddressListManager.find(self, user.ip, LIST_USERS_BLOCKED)
if len(firewall_ip_list_obj) > 1: if len(firewall_ip_list_obj) > 1:
IpAddressListManager.remove(self, firewall_ip_list_obj[0]['=.id']) IpAddressListManager.remove(self, firewall_ip_list_obj[0]['=.id'])
def remove_user(self, user: AbonStruct): def remove_user(self, user: AbonStruct):
super(MikrotikTransmitter, self).remove_user(user)
QueueManager.remove(self, user) QueueManager.remove(self, user)
firewall_ip_list_obj = IpAddressListManager.find(self, user.ip, LIST_USERS_ALLOWED) firewall_ip_list_obj = IpAddressListManager.find(self, user.ip, LIST_USERS_ALLOWED)
if firewall_ip_list_obj is not None and len(firewall_ip_list_obj) > 1: if firewall_ip_list_obj is not None and len(firewall_ip_list_obj) > 1:
IpAddressListManager.remove(self, firewall_ip_list_obj[0]['=.id']) IpAddressListManager.remove(self, firewall_ip_list_obj[0]['=.id'])
# обновляем основную инфу абонента
def update_user(self, user: AbonStruct, ip_timeout=0):
super(MikrotikTransmitter, self).update_user(user, ip_timeout)
def update_user(self, user: AbonStruct, *args):
if not isinstance(user.ip, IpStruct): if not isinstance(user.ip, IpStruct):
raise TypeError raise TypeError
# ищем ip абонента в списке ip
find_res = IpAddressListManager.find(self, user.ip, LIST_USERS_ALLOWED) find_res = IpAddressListManager.find(self, user.ip, LIST_USERS_ALLOWED)
queue = QueueManager.find(self, 'uid%d' % user.uid)
if not user.is_active: if not user.is_active:
# если не активен - то и обновлять не надо # если не активен - то и обновлять не надо
@ -459,11 +443,12 @@ class MikrotikTransmitter(QueueManager, IpAddressListManager):
if len(find_res) > 1: if len(find_res) > 1:
# и если найден был - то удалим ip из разрешённых # и если найден был - то удалим ip из разрешённых
IpAddressListManager.remove(self, find_res[0]['=.id']) IpAddressListManager.remove(self, find_res[0]['=.id'])
if queue is not None:
QueueManager.remove(self, user)
return return
# если нет услуги то её не должно быть и в nas # если нет услуги то её не должно быть и в nas
if user.tariff is None or not isinstance(user.tariff, TariffStruct): if user.tariff is None or not isinstance(user.tariff, TariffStruct):
queue = QueueManager.find(self, 'uid%d' % user.uid)
if queue is not None: if queue is not None:
QueueManager.remove(self, user) QueueManager.remove(self, user)
return return
@ -471,22 +456,17 @@ class MikrotikTransmitter(QueueManager, IpAddressListManager):
# если не найден (mikrotik возвращает пустой словарь в списке если ничего нет) # если не найден (mikrotik возвращает пустой словарь в списке если ничего нет)
if len(find_res) < 2: if len(find_res) < 2:
# добавим запись об абоненте # добавим запись об абоненте
IpAddressListManager.add(self, LIST_USERS_ALLOWED, user.ip, ip_timeout)
else:
mk_id = find_res[0]['=.id']
# то обновляем запись в mikrotik
IpAddressListManager._edit(self, mk_id, ip_timeout)
IpAddressListManager.add(self, LIST_USERS_ALLOWED, user.ip)
# Проверяем шейпер # Проверяем шейпер
queue = QueueManager.find(self, 'uid%d' % user.uid)
if queue is None: if queue is None:
QueueManager.add(self, user) QueueManager.add(self, user)
return return
if queue != user: if queue != user:
QueueManager.update(self, user) QueueManager.update(self, user)
def ping(self, host, count=10):
super(MikrotikTransmitter, self).ping(host)
def ping(self, host, count=10) -> Optional[Tuple[int, int]]:
r = self._exec_cmd([ r = self._exec_cmd([
'/ip/arp/print', '/ip/arp/print',
'?address=%s' % host '?address=%s' % host
@ -520,7 +500,7 @@ class MikrotikTransmitter(QueueManager, IpAddressListManager):
def remove_tariff(self, tid: int): def remove_tariff(self, tid: int):
pass pass
def read_users(self):
def read_users(self) -> Iterable[AbonStruct]:
# shapes is ShapeItem # shapes is ShapeItem
allowed_ips = set(IpAddressListManager.read_ips_iter(self, LIST_USERS_ALLOWED)) allowed_ips = set(IpAddressListManager.read_ips_iter(self, LIST_USERS_ALLOWED))
queues = set(q for q in QueueManager.read_queue_iter(self) if q.ip in allowed_ips) queues = set(q for q in QueueManager.read_queue_iter(self) if q.ip in allowed_ips)

29
devapp/base_intr.py

@ -1,7 +1,16 @@
from abc import ABCMeta, abstractmethod from abc import ABCMeta, abstractmethod
from datetime import timedelta
from typing import Union, Iterable, AnyStr, Generator
from easysnmp import Session from easysnmp import Session
ListOrError = Union[
Iterable,
Union[Exception, Iterable]
]
class DeviceImplementationError(Exception): class DeviceImplementationError(Exception):
pass pass
@ -12,7 +21,7 @@ class DevBase(object, metaclass=ABCMeta):
self.db_instance = dev_instance self.db_instance = dev_instance
@staticmethod @staticmethod
def description():
def description() -> AnyStr:
pass pass
@abstractmethod @abstractmethod
@ -20,29 +29,29 @@ class DevBase(object, metaclass=ABCMeta):
pass pass
@abstractmethod @abstractmethod
def get_ports(self):
def get_ports(self) -> ListOrError:
pass pass
@abstractmethod @abstractmethod
def get_device_name(self):
def get_device_name(self) -> AnyStr:
"""Return device name by snmp""" """Return device name by snmp"""
@abstractmethod @abstractmethod
def uptime(self):
def uptime(self) -> timedelta:
pass pass
@abstractmethod @abstractmethod
def get_template_name(self):
def get_template_name(self) -> AnyStr:
"""Return path to html template for device""" """Return path to html template for device"""
@staticmethod @staticmethod
@abstractmethod @abstractmethod
def has_attachable_to_subscriber():
def has_attachable_to_subscriber() -> bool:
"""Can connect device to subscriber""" """Can connect device to subscriber"""
@staticmethod @staticmethod
@abstractmethod @abstractmethod
def is_use_device_port():
def is_use_device_port() -> bool:
"""True if used device port while opt82 authorization""" """True if used device port while opt82 authorization"""
@ -62,7 +71,7 @@ class BasePort(object, metaclass=ABCMeta):
def enable(self): def enable(self):
pass pass
def mac(self):
def mac(self) -> str:
return ':'.join(['%x' % ord(i) for i in self._mac]) return ':'.join(['%x' % ord(i) for i in self._mac])
@ -75,11 +84,11 @@ class SNMPBaseWorker(object, metaclass=ABCMeta):
def set_int_value(self, oid, value): def set_int_value(self, oid, value):
return self.ses.set(oid, value, 'i') return self.ses.set(oid, value, 'i')
def get_list(self, oid):
def get_list(self, oid) -> Generator:
for v in self.ses.walk(oid): for v in self.ses.walk(oid):
yield v.value yield v.value
def get_list_keyval(self, oid):
def get_list_keyval(self, oid) -> Generator:
for v in self.ses.walk(oid): for v in self.ses.walk(oid):
snmpnum = v.oid.split('.')[-1:] snmpnum = v.oid.split('.')[-1:]
yield v.value, snmpnum[0] if len(snmpnum) > 0 else None yield v.value, snmpnum[0] if len(snmpnum) > 0 else None

47
devapp/dev_types.py

@ -1,9 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from django.utils.translation import gettext_lazy as _
from django.utils.translation import gettext_lazy as _, gettext
from mydefs import RuTimedelta, safe_int from mydefs import RuTimedelta, safe_int
from datetime import timedelta from datetime import timedelta
from easysnmp import EasySNMPTimeoutError from easysnmp import EasySNMPTimeoutError
from .base_intr import DevBase, SNMPBaseWorker, BasePort, DeviceImplementationError
from .base_intr import DevBase, SNMPBaseWorker, BasePort, DeviceImplementationError, ListOrError
class DLinkPort(BasePort): class DLinkPort(BasePort):
@ -40,7 +40,7 @@ class DLinkDevice(DevBase, SNMPBaseWorker):
def reboot(self): def reboot(self):
return self.get_item('.1.3.6.1.4.1.2021.8.1.101.1') return self.get_item('.1.3.6.1.4.1.2021.8.1.101.1')
def get_ports(self):
def get_ports(self) -> ListOrError:
interfaces_count = safe_int(self.get_item('.1.3.6.1.2.1.2.1.0')) interfaces_count = safe_int(self.get_item('.1.3.6.1.2.1.2.1.0'))
nams = list(self.get_list('.1.3.6.1.4.1.171.10.134.2.1.1.100.2.1.3')) nams = list(self.get_list('.1.3.6.1.4.1.171.10.134.2.1.1.100.2.1.3'))
stats = list(self.get_list('.1.3.6.1.2.1.2.2.1.7')) stats = list(self.get_list('.1.3.6.1.2.1.2.2.1.7'))
@ -59,7 +59,7 @@ class DLinkDevice(DevBase, SNMPBaseWorker):
self)) self))
return res return res
except IndexError: except IndexError:
raise DeviceImplementationError('Dlink port index error')
return DeviceImplementationError('Dlink port index error'), res
def get_device_name(self): def get_device_name(self):
return self.get_item('.1.3.6.1.2.1.1.1.0') return self.get_item('.1.3.6.1.2.1.1.1.0')
@ -114,23 +114,28 @@ class OLTDevice(DevBase, SNMPBaseWorker):
def reboot(self): def reboot(self):
pass pass
def get_ports(self):
def get_ports(self) -> ListOrError:
nms = self.get_list('.1.3.6.1.4.1.3320.101.10.1.1.79') nms = self.get_list('.1.3.6.1.4.1.3320.101.10.1.1.79')
res = [] res = []
for nm in nms:
n = int(nm)
status = self.get_item('.1.3.6.1.4.1.3320.101.10.1.1.26.%d' % n)
signal = self.get_item('.1.3.6.1.4.1.3320.101.10.5.1.5.%d' % n)
onu = ONUdev(
num=n,
name=self.get_item('.1.3.6.1.2.1.2.2.1.2.%d' % n),
status=True if status == '3' else False,
mac=self.get_item('.1.3.6.1.4.1.3320.101.10.1.1.3.%d' % n),
speed=0,
signal=int(signal) / 10 if signal != 'NOSUCHINSTANCE' else 0,
snmpWorker=self)
res.append(onu)
try:
for nm in nms:
n = int(nm)
status = self.get_item('.1.3.6.1.4.1.3320.101.10.1.1.26.%d' % n)
signal = self.get_item('.1.3.6.1.4.1.3320.101.10.5.1.5.%d' % n)
onu = ONUdev(
num=n,
name=self.get_item('.1.3.6.1.2.1.2.2.1.2.%d' % n),
status=True if status == '3' else False,
mac=self.get_item('.1.3.6.1.4.1.3320.101.10.1.1.3.%d' % n),
speed=0,
signal=int(signal) / 10 if signal != 'NOSUCHINSTANCE' else 0,
snmpWorker=self)
res.append(onu)
except EasySNMPTimeoutError as e:
return EasySNMPTimeoutError(
"%s (%s)" % (gettext('wait for a reply from the SNMP Timeout'), e)
), res
return res return res
def get_device_name(self): def get_device_name(self):
@ -166,8 +171,8 @@ class OnuDevice(DevBase, SNMPBaseWorker):
def reboot(self): def reboot(self):
pass pass
def get_ports(self):
pass
def get_ports(self) -> ListOrError:
return []
def get_device_name(self): def get_device_name(self):
pass pass
@ -239,7 +244,7 @@ class EltexSwitch(DLinkDevice):
def description(): def description():
return _('Eltex switch') return _('Eltex switch')
def get_ports(self):
def get_ports(self) -> ListOrError:
#nams = self.get_list('.1.3.6.1.4.1.171.10.134.2.1.1.100.2.1.3') #nams = self.get_list('.1.3.6.1.4.1.171.10.134.2.1.1.100.2.1.3')
stats = list(self.get_list('.1.3.6.1.2.1.2.2.1.7')) stats = list(self.get_list('.1.3.6.1.2.1.2.2.1.7'))
oper_stats = list(self.get_list('.1.3.6.1.2.1.2.2.1.8')) oper_stats = list(self.get_list('.1.3.6.1.2.1.2.2.1.8'))

15
devapp/views.py

@ -11,7 +11,7 @@ from django.contrib import messages
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.utils.translation import gettext_lazy as _, gettext from django.utils.translation import gettext_lazy as _, gettext
from easysnmp import EasySNMPTimeoutError, EasySNMPError from easysnmp import EasySNMPTimeoutError, EasySNMPError
from django.views.generic import ListView, DetailView
from django.views.generic import DetailView
from devapp.base_intr import DeviceImplementationError from devapp.base_intr import DeviceImplementationError
from mydefs import res_success, res_error, only_admins, ping, ip_addr_regex from mydefs import res_success, res_error, only_admins, ping, ip_addr_regex
@ -30,13 +30,13 @@ from .forms import DeviceForm, PortForm
from mydefs import safe_int from mydefs import safe_int
class BaseDeviceListView(ListView):
class BaseDeviceListView(global_base_views.BaseListWithFiltering):
http_method_names = ['get'] http_method_names = ['get']
paginate_by = getattr(settings, 'PAGINATION_ITEMS_PER_PAGE', 10) paginate_by = getattr(settings, 'PAGINATION_ITEMS_PER_PAGE', 10)
@method_decorator([login_required, only_admins], name='dispatch') @method_decorator([login_required, only_admins], name='dispatch')
class DevicesListView(BaseDeviceListView, global_base_views.OrderingMixin):
class DevicesListView(global_base_views.OrderingMixin, BaseDeviceListView):
context_object_name = 'devices' context_object_name = 'devices'
template_name = 'devapp/devices.html' template_name = 'devapp/devices.html'
@ -63,7 +63,7 @@ class DevicesListView(BaseDeviceListView, global_base_views.OrderingMixin):
@method_decorator([login_required, only_admins], name='dispatch') @method_decorator([login_required, only_admins], name='dispatch')
class DevicesWithoutGroupsListView(BaseDeviceListView, global_base_views.OrderingMixin):
class DevicesWithoutGroupsListView(global_base_views.OrderingMixin, BaseDeviceListView):
context_object_name = 'devices' context_object_name = 'devices'
template_name = 'devapp/devices_null_group.html' template_name = 'devapp/devices_null_group.html'
queryset = Device.objects.filter(group=None).only('comment', 'devtype', 'pk', 'ip_address') queryset = Device.objects.filter(group=None).only('comment', 'devtype', 'pk', 'ip_address')
@ -366,6 +366,9 @@ def devview(request, device_id):
if dev.man_passw: if dev.man_passw:
manager = dev.get_manager_object() manager = dev.get_manager_object()
ports = manager.get_ports() ports = manager.get_ports()
if isinstance(ports[0], Exception):
messages.error(request, ports[0])
ports = ports[1]
template_name = manager.get_template_name() template_name = manager.get_template_name()
else: else:
messages.warning(request, _('Not Set snmp device password')) messages.warning(request, _('Not Set snmp device password'))
@ -377,8 +380,8 @@ def devview(request, device_id):
'dev_accs': Abon.objects.filter(device=dev), 'dev_accs': Abon.objects.filter(device=dev),
'dev_manager': manager 'dev_manager': manager
}) })
except EasySNMPError:
messages.error(request, _('SNMP error on device'))
except EasySNMPError as e:
messages.error(request, "%s: %s" % (gettext('SNMP error on device'), e))
except (DeviceDBException, DeviceImplementationError) as e: except (DeviceDBException, DeviceImplementationError) as e:
messages.error(request, e) messages.error(request, e)
return render(request, 'devapp/custom_dev_page/' + template_name, { return render(request, 'devapp/custom_dev_page/' + template_name, {

Loading…
Cancel
Save