Module alerter

Модуль для обработки сообщений от сетевых железок.

Expand source code
# This Python file uses the following encoding: utf-8
"""Модуль для обработки сообщений от сетевых железок."""

# Под Windows с 514-ым портом могут быть проблемы, нужно повышение привилегий.
# Можно заменить порт на тот, что выше 1023-его. На клиенте прописать аналогичный.
# HOST, PORT = 'x.x.x.x': str, 514: int

from configparser import ConfigParser
from datetime import datetime
import re
from rich.console import Console
import socketserver

import db_management


console = Console()
# from memory_profiler import memory_usage
TEMPLATE1 = '┌────┬────────────────────┬─────────────┬──────────────┬──────────────────────┐'
TEMPLATE2 = '│{:^4}│{:^19} │ {:^11} │ {:^12} │ {:^20} │'
TEMPLATE3 = '│{: <77}│'

config = ConfigParser()
config.read('options.ini')
# HOST, PORT = 'localhost', 5140
HOST, PORT = config['ALERTER']['host'], config['ALERTER']['port']

db = db_management.DatabaseConnection()
CONNECTION_RESULT = db.test_connection()

match CONNECTION_RESULT:
    case 'BASE EXISTS':
        print('База существует.')
    case 'BASE NOT EXISTS':
        db.create_db()
        print('База создана!')
    case ERROR:
        print(f'Что-то пошло не так! {ERROR}')

db.open()


class SyslogUDPHandler(socketserver.BaseRequestHandler):
    """Класс Syslog сервера."""

    def handle(self):
        """Обработчик событий сислога."""
        data = bytes.decode(self.request[0].strip())

        # Parse
        event = re.search(
            r'(?P<priority><\d{,3}>)'
            r'(?P<date>\w{,3}\s+\d{,2}\s+\d{,2}:\d{,2}:\d{2})'
            r'(?P<from_host>\s+[^:]+)?\s+'
            r'((?P<process>\S+):)?'
            r'((?P<syslog_tag>\s+\S+):)? '
            r'(?P<message>.+)',
            data)

        device_time = datetime.strptime(str(datetime.now().year) + ' ' + event.group('date'), '%Y %b %d %H:%M:%S')

        if isinstance(event.group('from_host'), str):
            from_host = event.group('from_host')
        else:
            from_host = self.client_address[0]

        mac_re = re.search('(?P<mac>[0-9a-fA-F]{2}(?:[:-][0-9a-fA-F]{2}){5})', event.group('message'))
        if mac_re:
            mac = mac_re.group('mac').upper()
        else:
            mac = None

        row = {'priority': event.group('priority').strip('><'),
               'device_time': device_time.strftime('%Y-%m-%d %H:%M:%S'),
               'from_host': from_host,
               'process': event.group('process'),
               'syslog_tag': event.group('syslog_tag'),
               'message': event.group('message'),
               'mac': mac}

        if row['process'] == 'kernel':
            if db.rdbms == 'sqlite':
                db_management.insert_data(row, 'syslog')
            elif db.rdbms == 'postgresql':
                db_management.new_syslog_event(row, db)

        # print(data)  # отправка сообщений от sysloga в консоль для отладки.
        console.print(TEMPLATE1)
        console.print(TEMPLATE2.format(row['priority'] or '-',
                                       row['from_host'] or '-',
                                       row['process'] or '-',
                                       row['syslog_tag'] or '-',
                                       row['mac'] or '-'))
        console.print(TEMPLATE3.format(row['message'][:77] or '-'))


if __name__ == '__main__':
    try:
        server = socketserver.UDPServer((HOST, int(PORT)), SyslogUDPHandler)
        console.print(f'Start server on: {HOST}. Listening port: {PORT}')
        console.print(TEMPLATE1, style='bold magenta')
        console.print(TEMPLATE2.format('PR', 'FROM_HOST', 'PROCESS', 'SYSLOG_TAG', 'MAC'),
                      style='bold magenta')
        server.serve_forever(poll_interval=0.5)
    except (IOError, SystemExit) as error:
        print(error)
        if 'WinError 10048' in str(error):
            print('Что делать?: Остановите другой экземпляр скрипта, использующий сокет.')
        else:
            print("""Причина: вероятнее всего вы в разных подсетях с роутером, с которого принимаете события.
Что делать?: смените IP-адрес на адрес из подсети роутера и перезапустите alerter.py.""")
    except KeyboardInterrupt:
        db.close()
        print('Ctrl+C Pressed. Shutting down.')

Classes

class SyslogUDPHandler (request, client_address, server)

Класс Syslog сервера.

Expand source code
class SyslogUDPHandler(socketserver.BaseRequestHandler):
    """Класс Syslog сервера."""

    def handle(self):
        """Обработчик событий сислога."""
        data = bytes.decode(self.request[0].strip())

        # Parse
        event = re.search(
            r'(?P<priority><\d{,3}>)'
            r'(?P<date>\w{,3}\s+\d{,2}\s+\d{,2}:\d{,2}:\d{2})'
            r'(?P<from_host>\s+[^:]+)?\s+'
            r'((?P<process>\S+):)?'
            r'((?P<syslog_tag>\s+\S+):)? '
            r'(?P<message>.+)',
            data)

        device_time = datetime.strptime(str(datetime.now().year) + ' ' + event.group('date'), '%Y %b %d %H:%M:%S')

        if isinstance(event.group('from_host'), str):
            from_host = event.group('from_host')
        else:
            from_host = self.client_address[0]

        mac_re = re.search('(?P<mac>[0-9a-fA-F]{2}(?:[:-][0-9a-fA-F]{2}){5})', event.group('message'))
        if mac_re:
            mac = mac_re.group('mac').upper()
        else:
            mac = None

        row = {'priority': event.group('priority').strip('><'),
               'device_time': device_time.strftime('%Y-%m-%d %H:%M:%S'),
               'from_host': from_host,
               'process': event.group('process'),
               'syslog_tag': event.group('syslog_tag'),
               'message': event.group('message'),
               'mac': mac}

        if row['process'] == 'kernel':
            if db.rdbms == 'sqlite':
                db_management.insert_data(row, 'syslog')
            elif db.rdbms == 'postgresql':
                db_management.new_syslog_event(row, db)

        # print(data)  # отправка сообщений от sysloga в консоль для отладки.
        console.print(TEMPLATE1)
        console.print(TEMPLATE2.format(row['priority'] or '-',
                                       row['from_host'] or '-',
                                       row['process'] or '-',
                                       row['syslog_tag'] or '-',
                                       row['mac'] or '-'))
        console.print(TEMPLATE3.format(row['message'][:77] or '-'))

Ancestors

  • socketserver.BaseRequestHandler

Methods

def handle(self)

Обработчик событий сислога.

Expand source code
def handle(self):
    """Обработчик событий сислога."""
    data = bytes.decode(self.request[0].strip())

    # Parse
    event = re.search(
        r'(?P<priority><\d{,3}>)'
        r'(?P<date>\w{,3}\s+\d{,2}\s+\d{,2}:\d{,2}:\d{2})'
        r'(?P<from_host>\s+[^:]+)?\s+'
        r'((?P<process>\S+):)?'
        r'((?P<syslog_tag>\s+\S+):)? '
        r'(?P<message>.+)',
        data)

    device_time = datetime.strptime(str(datetime.now().year) + ' ' + event.group('date'), '%Y %b %d %H:%M:%S')

    if isinstance(event.group('from_host'), str):
        from_host = event.group('from_host')
    else:
        from_host = self.client_address[0]

    mac_re = re.search('(?P<mac>[0-9a-fA-F]{2}(?:[:-][0-9a-fA-F]{2}){5})', event.group('message'))
    if mac_re:
        mac = mac_re.group('mac').upper()
    else:
        mac = None

    row = {'priority': event.group('priority').strip('><'),
           'device_time': device_time.strftime('%Y-%m-%d %H:%M:%S'),
           'from_host': from_host,
           'process': event.group('process'),
           'syslog_tag': event.group('syslog_tag'),
           'message': event.group('message'),
           'mac': mac}

    if row['process'] == 'kernel':
        if db.rdbms == 'sqlite':
            db_management.insert_data(row, 'syslog')
        elif db.rdbms == 'postgresql':
            db_management.new_syslog_event(row, db)

    # print(data)  # отправка сообщений от sysloga в консоль для отладки.
    console.print(TEMPLATE1)
    console.print(TEMPLATE2.format(row['priority'] or '-',
                                   row['from_host'] or '-',
                                   row['process'] or '-',
                                   row['syslog_tag'] or '-',
                                   row['mac'] or '-'))
    console.print(TEMPLATE3.format(row['message'][:77] or '-'))