From 97b9b171b5504a3a6768f0ec6d7d208a45e41b19 Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Wed, 20 Mar 2019 18:32:43 +0300 Subject: [PATCH] improve ping function. First time do simple ping, and if not response then try arp ping --- abonapp/locale/ru/LC_MESSAGES/django.po | 12 ++--- abonapp/views.py | 58 ++++++++++++++----------- gw_app/models.py | 31 +++++++------ gw_app/nas_managers/core.py | 3 +- gw_app/nas_managers/mod_mikrotik.py | 31 +++++++------ 5 files changed, 76 insertions(+), 59 deletions(-) diff --git a/abonapp/locale/ru/LC_MESSAGES/django.po b/abonapp/locale/ru/LC_MESSAGES/django.po index 33564f3..9e32206 100644 --- a/abonapp/locale/ru/LC_MESSAGES/django.po +++ b/abonapp/locale/ru/LC_MESSAGES/django.po @@ -992,18 +992,18 @@ msgstr "пингуется" #: views.py:698 #, python-format -msgid "IP Conflict! %(all)d/%(return)d results" -msgstr "IP Конфликт! ping %(all)d из %(return)d" +msgid "IP Conflict! %(return)d/%(all)d results" +msgstr "IP Конфликт! ping %(return)d из %(all)d" #: views.py:701 #, python-format -msgid "ok ping, %(all)d/%(return)d loses" -msgstr "пингуется, %(all)d/%(return)d" +msgid "ok ping, %(return)d/%(all)d loses" +msgstr "пингуется, %(return)d/%(all)d" #: views.py:705 #, python-format -msgid "no ping, %(all)d/%(return)d loses" -msgstr "не пингуется, %(all)d/%(return)d" +msgid "no ping, %(return)d/%(all)d loses" +msgstr "не пингуется, %(return)d/%(all)d" #: views.py:811 msgid "Method is not POST" diff --git a/abonapp/views.py b/abonapp/views.py index 590143b..91472de 100644 --- a/abonapp/views.py +++ b/abonapp/views.py @@ -694,8 +694,7 @@ def clear_dev(request, gid: int, uname): def abon_ping(request, gid: int, uname): ip = request.GET.get('cmd_param') status = False - text = ' %s' % _( - 'no ping') + text = ' %s' % _('no ping') abon = get_object_or_404(models.Abon, username=uname) try: if ip is None: @@ -710,35 +709,44 @@ def abon_ping(request, gid: int, uname): mngr = abon.nas.get_nas_manager() ping_result = mngr.ping(ip) if ping_result is None: - if ping(ip, 10): - status = True - text = ' %s' % _( - 'ping ok') - else: - if type(ping_result) is tuple: - loses_percent = ( - ping_result[0] / ping_result[1] if ping_result[ - 1] != 0 else 1) - ping_result = {'all': ping_result[0], 'return': ping_result[1]} - if loses_percent > 1.0: - text = ' %s' % _( - 'IP Conflict! %(all)d/%(return)d results') % ping_result - elif loses_percent > 0.5: - text = ' %s' % _( - 'ok ping, %(all)d/%(return)d loses') % ping_result - status = True + return { + 'status': False, + 'dat': text + } + if isinstance(ping_result, tuple): + received, sent = ping_result + print(ping_result) + if received == 0: + ping_result = mngr.ping(ip, arp=True) + if ping_result is not None and isinstance(ping_result, tuple): + received, sent = ping_result else: - text = ' %s' % _( - 'no ping, %(all)d/%(return)d loses') % ping_result - else: + return { + 'status': False, + 'dat': text + } + loses_percent = ( + received / sent if sent != 0 else 1 + ) + ping_result = {'return': received, 'all': sent} + if loses_percent > 1.0: + text = ' %s' % _( + 'IP Conflict! %(return)d/%(all)d results' + ) % ping_result + elif loses_percent > 0.5: text = ' %s' % _( - 'ping ok') + ' ' + str(ping_result) + 'ok ping, %(return)d/%(all)d loses' + ) % ping_result status = True + else: + text = ' %s' % _( + 'no ping, %(return)d/%(all)d loses' + ) % ping_result except (NasFailedResult, lib.LogicError) as e: - messages.error(request, e) + text = str(e) except NasNetworkError as e: - messages.warning(request, e) + text = str(e) return { 'status': 0 if status else 1, diff --git a/gw_app/models.py b/gw_app/models.py index 217bb68..f9e3d10 100644 --- a/gw_app/models.py +++ b/gw_app/models.py @@ -5,7 +5,7 @@ from django.shortcuts import resolve_url from django.utils.translation import gettext_lazy as _ from django.db import models from djing.lib import MyChoicesAdapter -from gw_app.nas_managers import NAS_TYPES +from gw_app.nas_managers import NAS_TYPES, NasNetworkError class NASModel(models.Model): @@ -25,19 +25,22 @@ class NASModel(models.Model): raise TypeError(_('One of nas types implementation is not found')) def get_nas_manager(self): - klass = self.get_nas_manager_klass() - if hasattr(self, '_nas_mngr'): - o = getattr(self, '_nas_mngr') - else: - o = klass( - login=self.auth_login, - password=self.auth_passw, - ip=self.ip_address, - port=int(self.ip_port), - enabled=bool(self.enabled) - ) - setattr(self, '_nas_mngr', o) - return o + try: + klass = self.get_nas_manager_klass() + if hasattr(self, '_nas_mngr'): + o = getattr(self, '_nas_mngr') + else: + o = klass( + login=self.auth_login, + password=self.auth_passw, + ip=self.ip_address, + port=int(self.ip_port), + enabled=bool(self.enabled) + ) + setattr(self, '_nas_mngr', o) + return o + except ConnectionResetError: + raise NasNetworkError('ConnectionResetError') def get_absolute_url(self): return resolve_url('gw_app:edit', self.pk) diff --git a/gw_app/nas_managers/core.py b/gw_app/nas_managers/core.py index 9eb08f2..fd0b8cc 100644 --- a/gw_app/nas_managers/core.py +++ b/gw_app/nas_managers/core.py @@ -67,10 +67,11 @@ class BaseTransmitter(ABC): """ @abstractmethod - def ping(self, host: str, count=10) -> Optional[Tuple[int, int]]: + def ping(self, host: str, count=10, arp=False) -> Optional[Tuple[int, int]]: """ :param host: ip address in text view, for example '192.168.0.1' :param count: count of ping queries + :param arp: Is use arp ping :return: None if not response, else tuple it contains count returned and count sent for example (received, sent) -> (7, 10). """ diff --git a/gw_app/nas_managers/mod_mikrotik.py b/gw_app/nas_managers/mod_mikrotik.py index 7bd102c..312715f 100644 --- a/gw_app/nas_managers/mod_mikrotik.py +++ b/gw_app/nas_managers/mod_mikrotik.py @@ -430,19 +430,24 @@ class MikrotikTransmitter(core.BaseTransmitter, ApiRos, if res_ips: self.remove_ip(res_ips.get('=.id')) - def ping(self, host, count=10) -> Optional[Tuple[int, int]]: - r = self._exec_cmd(( - '/ip/arp/print', - '?address=%s' % host - )) - if r == {}: - return - interface = r['!re'].get('=interface') - r = self._exec_cmd(( - '/ping', '=address=%s' % host, '=arp-ping=yes', '=interval=100ms', - '=count=%d' % count, - '=interface=%s' % interface - )) + def ping(self, host, count=10, arp=False) -> Optional[Tuple[int, int]]: + params = [ + '/ping', '=address=%s' % host, + '=interval=100ms', '=count=%d' % count + ] + if arp: + r = self._exec_cmd(( + '/ip/arp/print', + '?address=%s' % host + )) + if r == {}: + return + interface = r['!re'].get('=interface') + params.extend(( + '=arp-ping=yes', + '=interface=%s' % interface + )) + r = self._exec_cmd(params) res = r.get('!re') if res is not None: received, sent = int(res.get('=received')), int(res.get('=sent'))