From ffc5a6d5ac06befe84c83c73367ddb5f47541463 Mon Sep 17 00:00:00 2001 From: bashmak Date: Mon, 29 Jan 2018 16:32:32 +0300 Subject: [PATCH] Multiple changes: 1) Makes mixin for API views. 2) Makes device monitoring notification. And little bit fixes --- agent/monitoring_agent.py | 68 +++++++++++ chatbot/telebot.py | 7 +- devapp/forms.py | 2 +- devapp/locale/ru/LC_MESSAGES/django.po | 44 +++++--- devapp/migrations/0006_auto_20180129_1625.py | 34 ++++++ devapp/models.py | 17 ++- devapp/templates/devapp/add_dev.html | 6 +- devapp/templates/devapp/dev.html | 2 + devapp/templates/devapp/devices.html | 20 ++-- devapp/urls.py | 6 +- devapp/views.py | 112 +++++++++++++++---- djing/global_base_views.py | 57 ++++++++++ djing/settings.py | 6 + djing/views.py | 4 - requirements.txt | 1 + taskapp/handle.py | 6 +- 16 files changed, 332 insertions(+), 60 deletions(-) create mode 100755 agent/monitoring_agent.py create mode 100644 devapp/migrations/0006_auto_20180129_1625.py create mode 100644 djing/global_base_views.py diff --git a/agent/monitoring_agent.py b/agent/monitoring_agent.py new file mode 100755 index 0000000..0e5cd74 --- /dev/null +++ b/agent/monitoring_agent.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +import sys +import re +from hashlib import sha256 +import requests + +API_AUTH_SECRET = 'asihdfaoisydoiayosidyaoisydoiasydaisydasd' + +SERVER_DOMAIN = 'http://localhost:8000' + + +IP_REGEXP = r'^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.' \ + r'(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.' \ + r'(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.' \ + r'(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$' + + +def calc_hash(data): + if type(data) is str: + result_data = data.encode('utf-8') + else: + result_data = bytes(data) + return sha256(result_data).hexdigest() + + +def check_sign(get_list, sign): + hashed = '_'.join(get_list) + my_sign = calc_hash(hashed) + return sign == my_sign + + +def validate(regexp, string): + if not bool(re.match(regexp, string)): + raise ValueError + return string + + +def validate_status(text): + if not text in ('UP', 'DOWN', 'UNREACHABLE'): + raise ValueError + return text + + +def send_request(ip, status, sign): + r = requests.get( + "%(domain)s/dev/on_device_down/" % {'domain': SERVER_DOMAIN}, + params={ + 'ip': ip, + 'status': status, + 'sign': sign + }) + if r.status_code == 200: + print(r.json()) + else: + print('Status:', r.status_code, r.text) + + +if __name__ == '__main__': + if len(sys.argv) < 3: + print('You forget parameters, example of usage:\n' + '$ python3 ./monitoring_agent.py 192.168.0.100 DOWN|UP|UNREACHABLE') + exit(0) + dev_ip = validate(IP_REGEXP, sys.argv[1]) + status = validate_status(sys.argv[2]) + + sign = calc_hash('_'.join((dev_ip, status, API_AUTH_SECRET))) + + send_request(dev_ip, status, sign) diff --git a/chatbot/telebot.py b/chatbot/telebot.py index caba809..cb18527 100755 --- a/chatbot/telebot.py +++ b/chatbot/telebot.py @@ -115,7 +115,6 @@ class DjingTelebot(helper.ChatHandler): self._dialog_fn = None self._chat_id = 0 - # пингуем адрес def ping(self, ip=None): if ip is None: self._question(_("Let's ping, write ip. It will be necessary to wait 10 seconds"), self.ping) @@ -131,7 +130,7 @@ class DjingTelebot(helper.ChatHandler): self._sent_reply(_("You're '%s', right?") % self._current_user.get_full_name()) -# Просто отправляем текст оповещения указанной учётке +# Just sending text to specified account def send_notify(msg_text, account, tag='none'): try: MessageQueue.objects.push(msg=msg_text, user=account, tag=tag) @@ -143,6 +142,6 @@ def send_notify(msg_text, account, tag='none'): except TelegramBot.DoesNotExist: raise ChatException(_("Recipient '%s' does not subscribed on notifications") % account.get_full_name()) except ProtocolError as e: - raise ChatException(e) + raise ChatException('ProtocolError: %s' % e) except TelegramError as e: - raise ChatException("%s - %s" % (e, tb.user.get_full_name())) + raise ChatException('Telegram error: %s' % e) diff --git a/devapp/forms.py b/devapp/forms.py index af3e5e6..407a4de 100644 --- a/devapp/forms.py +++ b/devapp/forms.py @@ -19,7 +19,7 @@ class DeviceForm(forms.ModelForm): class Meta: model = models.Device - exclude = ['map_dot'] + exclude = ['map_dot', 'status'] widgets = { 'ip_address': forms.TextInput(attrs={ 'pattern': ip_addr_regex, diff --git a/devapp/locale/ru/LC_MESSAGES/django.po b/devapp/locale/ru/LC_MESSAGES/django.po index f59f2fd..6354cbc 100644 --- a/devapp/locale/ru/LC_MESSAGES/django.po +++ b/devapp/locale/ru/LC_MESSAGES/django.po @@ -221,7 +221,7 @@ msgstr "Прикрепленный абонент" #: templates/devapp/custom_dev_page/onu.html:47 msgid "ONU Status" -msgstr "" +msgstr "Состояние ONU" #: templates/devapp/custom_dev_page/onu.html:57 msgid "ONU error" @@ -229,7 +229,7 @@ msgstr "ONU ошибка" #: templates/devapp/custom_dev_page/onu.html:71 msgid "Name on OLT" -msgstr "" +msgstr "Имя на OLT" #: templates/devapp/custom_dev_page/onu.html:72 msgid "Distance(m)" @@ -238,11 +238,11 @@ msgstr "Расстояние (м)" #: templates/devapp/custom_dev_page/onu.html:77 #: templates/devapp/custom_dev_page/onu.html:85 msgid "Mac on OLT" -msgstr "" +msgstr "MAC адрес на OLT" #: templates/devapp/custom_dev_page/onu.html:78 msgid "Mac-addresses does not match" -msgstr "" +msgstr "MAC адреса не совпадают" #: templates/devapp/custom_dev_page/onu.html:79 #: templates/devapp/custom_dev_page/onu.html:81 @@ -312,7 +312,7 @@ msgstr "Устройства без группы" #: templates/devapp/fix_dev_group.html:17 msgid "Fix device group" -msgstr "" +msgstr "Поправить группу устройства" #: templates/devapp/group_list.html:18 msgid "Group title" @@ -408,11 +408,11 @@ msgstr "Инфа о точке сохранена" #: views.py:110 msgid "You have redirected to existing device" -msgstr "" +msgstr "Вы были переадресованы на существующее устройство" #: views.py:113 views.py:329 views.py:419 msgid "Please attach user group for device" -msgstr "" +msgstr "Пожалуйста назначте устройству группу в настройках" #: views.py:117 views.py:275 views.py:304 views.py:421 msgid "Form is invalid, check fields and try again" @@ -473,11 +473,29 @@ msgstr "Исправлено, обновите страницу" msgid "Parent device not found" msgstr "Вышестоящее устройство не найдено" -#~ msgid "Map point" -#~ msgstr "Точка топологии" +msgid "Send notify when monitoring state changed" +msgstr "Отправлять уведомления при событиях мониторинга" + +msgid "Device %(device_name)s is up" +msgstr "%(device_name)s в сети" + +msgid "Device %(device_name)s is down" +msgstr "%(device_name)s не в сети" + +msgid "Device %(device_name)s is unreachable" +msgstr "%(device_name)s недостижим" + +msgid "Device %(device_name)s getting undefined status code" +msgstr "Устройство %(device_name)s получило не определённый код состояния" + +msgid "Undefined" +msgstr "Не определено" + +msgid "Up" +msgstr "В сети" -#~ msgid "Find the subscriber" -#~ msgstr "Найти абонента" +msgid "Unreachable" +msgstr "Не доступно" -#~ msgid "View the device" -#~ msgstr "Посмотреть устройство" +msgid "Down" +msgstr "Не в сети" diff --git a/devapp/migrations/0006_auto_20180129_1625.py b/devapp/migrations/0006_auto_20180129_1625.py new file mode 100644 index 0000000..3f0b439 --- /dev/null +++ b/devapp/migrations/0006_auto_20180129_1625.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2018-01-29 16:25 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('devapp', '0005_device_snmp_item_num'), + ] + + operations = [ + migrations.AlterModelOptions( + name='device', + options={'ordering': ['comment'], 'permissions': (('can_view_device', 'Can view device'),), 'verbose_name': 'Device', 'verbose_name_plural': 'Devices'}, + ), + migrations.AddField( + model_name='device', + name='is_noticeable', + field=models.BooleanField(default=False, verbose_name='Send notify when monitoring state changed'), + ), + migrations.AddField( + model_name='device', + name='status', + field=models.CharField(choices=[('und', 'Undefined'), ('up', 'Up'), ('unr', 'Unreachable'), ('dwn', 'Down')], default='und', max_length=3, verbose_name='Status'), + ), + migrations.AlterField( + model_name='device', + name='snmp_item_num', + field=models.PositiveSmallIntegerField(blank=True, default=0, verbose_name='SNMP Number'), + ), + ] diff --git a/devapp/models.py b/devapp/models.py index 8c482b7..7bb24de 100644 --- a/devapp/models.py +++ b/devapp/models.py @@ -54,7 +54,17 @@ class Device(models.Model): user_group = models.ForeignKey('abonapp.AbonGroup', verbose_name=_('User group'), on_delete=models.SET_NULL, null=True, blank=True) parent_dev = models.ForeignKey('self', verbose_name=_('Parent device'), blank=True, null=True, on_delete=models.SET_NULL) - snmp_item_num = models.PositiveSmallIntegerField(_('SNMP Number'), default=0) + snmp_item_num = models.PositiveSmallIntegerField(_('SNMP Number'), default=0, blank=True) + + NETWORK_STATES = ( + ('und', _('Undefined')), + ('up', _('Up')), + ('unr', _('Unreachable')), + ('dwn', _('Down')) + ) + status = models.CharField(_('Status'), max_length=3, choices=NETWORK_STATES, default='und') + + is_noticeable = models.BooleanField(_('Send notify when monitoring state changed'), default=False) objects = DeviceManager() @@ -65,14 +75,13 @@ class Device(models.Model): ) verbose_name = _('Device') verbose_name_plural = _('Devices') + ordering = ['comment'] def get_abons(self): pass def get_status(self): - url = getattr(settings, 'NAGIOS_URL') - if url: - return requests.get('%s/host/status?addr=%s' % (url, self.ip_address)) + return self.status def get_manager_klass(self): klasses = [kl for kl in DEVICE_TYPES if kl[0] == self.devtype] diff --git a/devapp/templates/devapp/add_dev.html b/devapp/templates/devapp/add_dev.html index d3ecca0..da222b7 100644 --- a/devapp/templates/devapp/add_dev.html +++ b/devapp/templates/devapp/add_dev.html @@ -54,8 +54,10 @@ - {% bootstrap_icon 'list-alt' as ic %} - {% bootstrap_field form.snmp_item_num addon_before=ic %} + {% bootstrap_icon 'list-alt' as ic %} + {% bootstrap_field form.snmp_item_num addon_before=ic %} + + {% bootstrap_field form.is_noticeable %}