From 9d73be593f035f18ad7be1898f5f4ad04cb0fbe4 Mon Sep 17 00:00:00 2001 From: Jan Speller Date: Tue, 16 Feb 2021 01:09:04 +0100 Subject: [PATCH 1/4] implement basic mysql functionality --- boswatch/router/routerManager.py | 6 +- plugin/mysql.py | 175 +++++++++++++++++++++++++++++++ 2 files changed, 178 insertions(+), 3 deletions(-) create mode 100644 plugin/mysql.py diff --git a/boswatch/router/routerManager.py b/boswatch/router/routerManager.py index cf26d5f..28a1788 100644 --- a/boswatch/router/routerManager.py +++ b/boswatch/router/routerManager.py @@ -28,6 +28,7 @@ logging.debug("- %s loaded", __name__) class RouterManager: """!Class to manage all routers""" + def __init__(self): """!Create new router""" self._routerDict = {} @@ -92,9 +93,8 @@ class RouterManager: logging.error("unknown type '%s' in %s", routeType, route) return False - # except ModuleNotFoundError: # only since Py3.6 - except ImportError: - logging.error("%s not found: %s", route.get("type"), route.get("res")) + except ModuleNotFoundError as e: + logging.error("%s not found: %s (%s)", route.get("type"), route.get("res"), str(e)) return False logging.debug("finished building routers") diff --git a/plugin/mysql.py b/plugin/mysql.py new file mode 100644 index 0000000..e4c153e --- /dev/null +++ b/plugin/mysql.py @@ -0,0 +1,175 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +"""! + ____ ____ ______ __ __ __ _____ + / __ )/ __ \/ ___/ | / /___ _/ /______/ /_ |__ / + / __ / / / /\__ \| | /| / / __ `/ __/ ___/ __ \ /_ < + / /_/ / /_/ /___/ /| |/ |/ / /_/ / /_/ /__/ / / / ___/ / +/_____/\____//____/ |__/|__/\__,_/\__/\___/_/ /_/ /____/ + German BOS Information Script + by Bastian Schroll + +@file: mysql.py +@date: 15.02.2021 +@author: Jan Speller +@description: Mysql Plugin +""" +import logging +from plugin.pluginBase import PluginBase + +# ###################### # +# Custom plugin includes # +import mysql.connector +from datetime import datetime + +# ###################### # + +logging.debug("- %s loaded", __name__) + + +class BoswatchPlugin(PluginBase): + """!Description of the Plugin""" + + def __init__(self, config): + """!Do not change anything here!""" + super().__init__(__name__, config) # you can access the config class on 'self.config' + + def onLoad(self): + """!Called by import of the plugin + Remove if not implemented""" + self.connection = mysql.connector.connect( + host=self.config.get("host"), + user=self.config.get("user"), + password=self.config.get("password"), + database=self.config.get("database"), + ) + self.sqlInserts = { + "pocsag": "INSERT INTO boswatch (packetTimestamp, packetMode, pocsag_ric, pocsag_subric, pocsag_subricText, pocsag_message, pocsag_bitrate, serverName, serverVersion, serverBuildDate, serverBranch, clientName, clientIP, clientVersion, clientBuildDate, clientBranch, inputSource, frequency) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)", + "zvei": "INSERT INTO boswatch (packetTimestamp, packetMode, zvei_tone, serverName, serverVersion, serverBuildDate, serverBranch, clientName, clientIP, clientVersion, clientBuildDate, clientBranch, inputSource, frequency) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)", + "fms": "INSERT INTO boswatch (packetTimestamp, packetMode, fms_fms, fms_service, fms_country, fms_location, fms_vehicle, fms_status, fms_direction, fms_directionText, fms_tacticalInfo, serverName, serverVersion, serverBuildDate, serverBranch, clientName, clientIP, clientVersion, clientBuildDate, clientBranch, inputSource, frequency) VALUE (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)", + "msg": "INSERT INTO boswatch (packetTimestamp, packetMode, serverName, serverVersion, serverBuildDate, serverBranch, clientName, clientIP, clientVersion, clientBuildDate, clientBranch, inputSource, frequency) VALUE (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" + } + + def setup(self): + """!Called before alarm + Remove if not implemented""" + try: + self.connection.ping(reconnect=True, attempts=3, delay=2) + except mysql.connector.Error as err: + logging.warning("Connection was down, trying to reconnect...") + self.onLoad() + + self.cursor = self.connection.cursor() + + def fms(self, bwPacket): + """!Called on FMS alarm + + @param bwPacket: bwPacket instance + Remove if not implemented""" + val = ( + datetime.fromtimestamp(float(bwPacket.get("timestamp"))), + bwPacket.get("mode"), + bwPacket.get("fms"), + bwPacket.get("service"), + bwPacket.get("country"), + bwPacket.get("location"), + bwPacket.get("vehicle"), + bwPacket.get("status"), + bwPacket.get("direction"), + bwPacket.get("directionText"), + bwPacket.get("tacticalInfo"), + bwPacket.get("serverName"), + bwPacket.get("serverVersion"), + bwPacket.get("serverBuildDate"), + bwPacket.get("serverBranch"), + bwPacket.get("clientName"), + bwPacket.get("clientIP"), + bwPacket.get("clientVersion"), + bwPacket.get("clientBuildDate"), + bwPacket.get("clientBranch"), + bwPacket.get("inputSource"), + bwPacket.get("frequency") + ) + self.cursor.execute(self.sqlInserts.get("fms"), val) + + def pocsag(self, bwPacket): + """!Called on POCSAG alarm + + @param bwPacket: bwPacket instance + Remove if not implemented""" + val = ( + datetime.fromtimestamp(float(bwPacket.get("timestamp"))), + bwPacket.get("mode"), + bwPacket.get("ric"), + bwPacket.get("subric"), + bwPacket.get("subricText"), + bwPacket.get("message"), + bwPacket.get("bitrate"), + bwPacket.get("serverName"), + bwPacket.get("serverVersion"), + bwPacket.get("serverBuildDate"), + bwPacket.get("serverBranch"), + bwPacket.get("clientName"), + bwPacket.get("clientIP"), + bwPacket.get("clientVersion"), + bwPacket.get("clientBuildDate"), + bwPacket.get("clientBranch"), + bwPacket.get("inputSource"), + bwPacket.get("frequency") + ) + self.cursor.execute(self.sqlInserts.get("pocsag"), val) + + def zvei(self, bwPacket): + """!Called on ZVEI alarm + + @param bwPacket: bwPacket instance + Remove if not implemented""" + val = ( + datetime.fromtimestamp(float(bwPacket.get("timestamp"))), + bwPacket.get("mode"), + bwPacket.get("tone"), + bwPacket.get("serverName"), + bwPacket.get("serverVersion"), + bwPacket.get("serverBuildDate"), + bwPacket.get("serverBranch"), + bwPacket.get("clientName"), + bwPacket.get("clientIP"), + bwPacket.get("clientVersion"), + bwPacket.get("clientBuildDate"), + bwPacket.get("clientBranch"), + bwPacket.get("inputSource"), + bwPacket.get("frequency") + ) + self.cursor.execute(self.sqlInserts.get("pocsag"), val) + + def msg(self, bwPacket): + """!Called on MSG packet + + @param bwPacket: bwPacket instance + Remove if not implemented""" + val = ( + datetime.fromtimestamp(float(bwPacket.get("timestamp"))), + bwPacket.get("mode"), + bwPacket.get("serverName"), + bwPacket.get("serverVersion"), + bwPacket.get("serverBuildDate"), + bwPacket.get("serverBranch"), + bwPacket.get("clientName"), + bwPacket.get("clientIP"), + bwPacket.get("clientVersion"), + bwPacket.get("clientBuildDate"), + bwPacket.get("clientBranch"), + bwPacket.get("inputSource"), + bwPacket.get("frequency") + ) + self.cursor.execute(self.sqlInserts.get("msg"), val) + + def teardown(self): + """!Called after alarm + Remove if not implemented""" + self.connection.commit() + + def onUnload(self): + """!Called by destruction of the plugin + Remove if not implemented""" + pass From 90d932d53c8c36a7466b783adb3fcfd80eabe2ef Mon Sep 17 00:00:00 2001 From: Jan Speller Date: Sun, 28 Feb 2021 13:58:29 +0100 Subject: [PATCH 2/4] update mysql plugin: add init_db.sql and create table automatically --- boswatch/router/routerManager.py | 4 ++-- init_db.sql | 34 ++++++++++++++++++++++++++++++++ plugin/mysql.py | 29 +++++++++++++++++++-------- 3 files changed, 57 insertions(+), 10 deletions(-) create mode 100644 init_db.sql diff --git a/boswatch/router/routerManager.py b/boswatch/router/routerManager.py index 28a1788..86f6326 100644 --- a/boswatch/router/routerManager.py +++ b/boswatch/router/routerManager.py @@ -93,8 +93,8 @@ class RouterManager: logging.error("unknown type '%s' in %s", routeType, route) return False - except ModuleNotFoundError as e: - logging.error("%s not found: %s (%s)", route.get("type"), route.get("res"), str(e)) + except ModuleNotFoundError: + logging.exception("%s not found: %s", route.get("type"), route.get("res")) return False logging.debug("finished building routers") diff --git a/init_db.sql b/init_db.sql new file mode 100644 index 0000000..79a86fc --- /dev/null +++ b/init_db.sql @@ -0,0 +1,34 @@ +create table boswatch +( + id int auto_increment primary key, + packetTimestamp timestamp default now() not null, + packetMode enum('fms', 'pocsag', 'zvei', 'msg') not null, + pocsag_ric char(7) default null, + pocsag_subric enum('1', '2', '3', '4') default null, + pocsag_subricText enum('a', 'b', 'c', 'd') default null, + pocsag_message text default null, + pocsag_bitrate enum('512', '1200', '2400') default null, + zvei_tone char(5) default null, + fms_fms char(8) default null, + fms_service varchar(255) default null, + fms_country varchar(255) default null, + fms_location varchar(255) default null, + fms_vehicle varchar(255) default null, + fms_status char(1) default null, + fms_direction char(1) default null, + fms_directionText tinytext default null, + fms_tacticalInfo char(3) default null, + serverName varchar(255) not null, + serverVersion varchar(100) not null, + serverBuildDate varchar(255) not null, + serverBranch varchar(255) not null, + clientName varchar(255) not null, + clientIP varchar(255) not null, + clientVersion varchar(100) not null, + clientBuildDate varchar(255) not null, + clientBranch varchar(255) not null, + inputSource varchar(30) not null, + frequency varchar(30) not null +); +create unique index boswatch_id_uindex + on boswatch (id); \ No newline at end of file diff --git a/plugin/mysql.py b/plugin/mysql.py index e4c153e..f882703 100644 --- a/plugin/mysql.py +++ b/plugin/mysql.py @@ -37,12 +37,6 @@ class BoswatchPlugin(PluginBase): def onLoad(self): """!Called by import of the plugin Remove if not implemented""" - self.connection = mysql.connector.connect( - host=self.config.get("host"), - user=self.config.get("user"), - password=self.config.get("password"), - database=self.config.get("database"), - ) self.sqlInserts = { "pocsag": "INSERT INTO boswatch (packetTimestamp, packetMode, pocsag_ric, pocsag_subric, pocsag_subricText, pocsag_message, pocsag_bitrate, serverName, serverVersion, serverBuildDate, serverBranch, clientName, clientIP, clientVersion, clientBuildDate, clientBranch, inputSource, frequency) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)", "zvei": "INSERT INTO boswatch (packetTimestamp, packetMode, zvei_tone, serverName, serverVersion, serverBuildDate, serverBranch, clientName, clientIP, clientVersion, clientBuildDate, clientBranch, inputSource, frequency) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)", @@ -50,12 +44,30 @@ class BoswatchPlugin(PluginBase): "msg": "INSERT INTO boswatch (packetTimestamp, packetMode, serverName, serverVersion, serverBuildDate, serverBranch, clientName, clientIP, clientVersion, clientBuildDate, clientBranch, inputSource, frequency) VALUE (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" } + self.connection = mysql.connector.connect( + host=self.config.get("host"), + user=self.config.get("user"), + password=self.config.get("password"), + database=self.config.get("database"), + ) + + self.cursor = self.connection.cursor() + self.cursor.execute("SHOW TABLES LIKE 'boswatch'") + + if self.cursor.fetchone() is None: + with open('init_db.sql') as f: + for stmnt in f.read().split(';'): + self.cursor.execute(stmnt) + self.connection.commit() + + self.cursor.close() + def setup(self): """!Called before alarm Remove if not implemented""" try: self.connection.ping(reconnect=True, attempts=3, delay=2) - except mysql.connector.Error as err: + except mysql.connector.Error: logging.warning("Connection was down, trying to reconnect...") self.onLoad() @@ -168,8 +180,9 @@ class BoswatchPlugin(PluginBase): """!Called after alarm Remove if not implemented""" self.connection.commit() + self.cursor.close() def onUnload(self): """!Called by destruction of the plugin Remove if not implemented""" - pass + self.connection.close() From 3354a7d5f2353e95fd970a3e3e6b7d663316186e Mon Sep 17 00:00:00 2001 From: Jan Speller Date: Mon, 1 Mar 2021 08:13:26 +0100 Subject: [PATCH 3/4] add documentation --- docu/docs/plugin/mysql.md | 42 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 docu/docs/plugin/mysql.md diff --git a/docu/docs/plugin/mysql.md b/docu/docs/plugin/mysql.md new file mode 100644 index 0000000..0497aeb --- /dev/null +++ b/docu/docs/plugin/mysql.md @@ -0,0 +1,42 @@ +#
Mysql
+--- + +## Beschreibung +Mit diesem Plugin ist es moeglich, die Alarmierungen in einer Mysql / Mariadb Datenbank zu speichern. + +## Unterstütze Alarmtypen +- Fms +- Pocsag +- Zvei +- Msg + +## Resource +`mysql` + +## Konfiguration +|Feld|Beschreibung|Default| +|----|------------|-------| +|host|IP-Adresse bzw. URL des Hosts|| +|user|Username|| +|password|Passwort|| +|database|Name der Datenbank|| + +**Beispiel:** +```yaml + - type: plugin + name: mysql + res: mysql + config: + host: HOST + user: USERNAME + password: PASSWORD + database: DATABASE +``` + +--- +## Modul Abhängigkeiten +- keine + +--- +## Externe Abhängigkeiten +- mysql-connector-python From 31ee935628bcff0988a078cb7a04f737062f289c Mon Sep 17 00:00:00 2001 From: Jan Speller Date: Thu, 4 Mar 2021 12:40:57 +0100 Subject: [PATCH 4/4] Change spacing in init_db.sql and add comment on table creation --- docu/docs/plugin/mysql.md | 1 + init_db.sql | 23 ++++++++++++----------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/docu/docs/plugin/mysql.md b/docu/docs/plugin/mysql.md index 0497aeb..b2cd2d4 100644 --- a/docu/docs/plugin/mysql.md +++ b/docu/docs/plugin/mysql.md @@ -3,6 +3,7 @@ ## Beschreibung Mit diesem Plugin ist es moeglich, die Alarmierungen in einer Mysql / Mariadb Datenbank zu speichern. +Das Plugin legt die Tabelle "boswatch" selbststaendig an, wenn diese nicht vorhanden ist. ## Unterstütze Alarmtypen - Fms diff --git a/init_db.sql b/init_db.sql index 79a86fc..b5948bc 100644 --- a/init_db.sql +++ b/init_db.sql @@ -8,16 +8,16 @@ create table boswatch pocsag_subricText enum('a', 'b', 'c', 'd') default null, pocsag_message text default null, pocsag_bitrate enum('512', '1200', '2400') default null, - zvei_tone char(5) default null, - fms_fms char(8) default null, - fms_service varchar(255) default null, - fms_country varchar(255) default null, - fms_location varchar(255) default null, - fms_vehicle varchar(255) default null, - fms_status char(1) default null, - fms_direction char(1) default null, - fms_directionText tinytext default null, - fms_tacticalInfo char(3) default null, + zvei_tone char(5) default null, + fms_fms char(8) default null, + fms_service varchar(255) default null, + fms_country varchar(255) default null, + fms_location varchar(255) default null, + fms_vehicle varchar(255) default null, + fms_status char(1) default null, + fms_direction char(1) default null, + fms_directionText tinytext default null, + fms_tacticalInfo char(3) default null, serverName varchar(255) not null, serverVersion varchar(100) not null, serverBuildDate varchar(255) not null, @@ -31,4 +31,5 @@ create table boswatch frequency varchar(30) not null ); create unique index boswatch_id_uindex - on boswatch (id); \ No newline at end of file + on boswatch (id); +