Added a simple data model class to be more flexible. SQLAlchemy will not be included. uplink is to small for this... maybe later. Lot of housekeeping where done too.

This commit is contained in:
Johannes Findeisen 2022-08-28 04:17:53 +02:00
commit d2f3484ca9
8 changed files with 279 additions and 62 deletions

View file

@ -25,8 +25,6 @@
# TODO: Implement a speedtest/ping that will also run regularly but in an individual interval # TODO: Implement a speedtest/ping that will also run regularly but in an individual interval
# TODO: become more verbose in each log level and log only to error when it really is an error # TODO: become more verbose in each log level and log only to error when it really is an error
# else log to info and even add debug messages in DEBUG level # else log to info and even add debug messages in DEBUG level
# TODO: Maybe make path to pid_file an arg to use /var/run/user/$uid/uplink.pid instead of
# /tmp/uplink.pid or check user id and write it to /var/run or var/run/user/$uid automatically
# TODO: make all args consistent and clean... there is some stuff to do! # TODO: make all args consistent and clean... there is some stuff to do!
import argparse import argparse
@ -113,7 +111,7 @@ def main():
args = parse_args() args = parse_args()
root_logger = logging.getLogger() root_logger = logging.getLogger()
logger.error("TEST")
if args.logfile: if args.logfile:
logfile = os.path.expanduser(args.logfile) logfile = os.path.expanduser(args.logfile)
if not os.path.exists(os.path.dirname(logfile)): if not os.path.exists(os.path.dirname(logfile)):
@ -143,7 +141,7 @@ def main():
configuration.set_env_var('_start_date', time.strftime('%Y-%m-%d %H:%M:%S', configuration.set_env_var('_start_date', time.strftime('%Y-%m-%d %H:%M:%S',
time.localtime( time.localtime(
calendar.timegm(time.gmtime())))) calendar.timegm(time.gmtime()))))
# interval set in args is overriding configuration and default # interval set in args is overriding configuration and default
if args.interval: if args.interval:
@ -177,17 +175,17 @@ def main():
if configuration.get_httpserver_framework() == 'bottle': if configuration.get_httpserver_framework() == 'bottle':
from uplink.server_bottle import Server from uplink.server_bottle import Server
s = Server(configuration) s = Server(configuration)
st = Thread(target=s.run, daemon=True) st = Thread(target=s.run_server, daemon=True)
st.start() st.start()
elif configuration.get_httpserver_framework() == 'cherrypy': elif configuration.get_httpserver_framework() == 'cherrypy':
from uplink.server_cherrypy import Server from uplink.server_cherrypy import Server
s = Server(configuration) s = Server(configuration)
st = Thread(target=s.run, daemon=True) st = Thread(target=s.run_server, daemon=True)
st.start() st.start()
elif configuration.get_httpserver_framework() == 'pyramid': elif configuration.get_httpserver_framework() == 'pyramid':
from uplink.server_pyramid import Server from uplink.server_pyramid import Server
s = Server(configuration) s = Server(configuration)
st = Thread(target=s.run, daemon=True) st = Thread(target=s.run_server, daemon=True)
st.start() st.start()
else: else:
logger.error('[uplink] no http framework configured! ' logger.error('[uplink] no http framework configured! '

32
uplink/csv.py Normal file
View file

@ -0,0 +1,32 @@
# Copyright (c) 2022 Johannes Findeisen <you@hanez.org>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is furnished
# to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice (including the next
# paragraph) shall be included in all copies or substantial portions of the
# Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
# OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from logging import getLogger
logger = getLogger(__name__)
class Csv:
def __init__(self, configuration):
self.configuration = configuration
def write_model_to_csv(self):
return

View file

@ -18,13 +18,9 @@
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
# OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import calendar
import pymysql import pymysql
import socket
import time
from logging import getLogger from logging import getLogger
from sqlalchemy import create_engine
logger = getLogger(__name__) logger = getLogger(__name__)
@ -32,35 +28,57 @@ logger = getLogger(__name__)
class Database: class Database:
def __init__(self, configuration): def __init__(self, configuration):
self.configuration = configuration self.__configuration = configuration
self.date = None
self.time = None
self.status = None
def write_to_db(self, fc, ip, provider, status):
timestamp = calendar.timegm(time.gmtime())
local_time = time.localtime(timestamp)
self.date = time.strftime('%Y-%m-%d', local_time)
self.time = time.strftime('%H:%M:%S', local_time)
def write_model_to_db(self, model):
try: try:
con = pymysql.connect(host=self.configuration.get_database_host(), con = pymysql.connect(host=self.__configuration.get_database_host(),
user=self.configuration.get_database_user(), user=self.__configuration.get_database_user(),
password=self.configuration.get_database_password(), password=self.__configuration.get_database_password(),
database=self.configuration.get_database_name()) database=self.__configuration.get_database_name())
sql = 'INSERT INTO log (timestamp, date, time, uptime, internal_ip, external_ip, external_ipv6, is_linked, ' \ sql = 'INSERT INTO log (' \
'is_connected, str_transmission_rate_up, str_transmission_rate_down, str_max_bit_rate_up, ' \ 'timestamp, ' \
'str_max_bit_rate_down, str_max_linked_bit_rate_up, str_max_linked_bit_rate_down, model_name, ' \ 'date, ' \
'system_version, provider, message, source_host) VALUES (\"' + str(timestamp) + '\",\"' + str(self.date) + '\",\"' + \ 'time, ' \
str(self.time) + '\",\"' + str(fc.connection_uptime) + '\",\"' + str(ip) + '\",\"' + \ 'uptime, ' \
str(fc.external_ip) + '\",\"' + str(fc.external_ipv6) + '\",\"' + str(int(fc.is_linked)) + '\",\"' + \ 'internal_ip, ' \
str(int(fc.is_connected)) + '\",\"' + str(fc.str_transmission_rate[0]) + '\",\"' + \ 'external_ip, ' \
str(fc.str_transmission_rate[1]) + '\",\"' + str(fc.str_max_bit_rate[0]) + '\",\"' + \ 'external_ipv6, ' \
str(fc.str_max_bit_rate[1]) + '\",\"' + str(fc.str_max_linked_bit_rate[0]) + '\",\"' + \ 'is_linked, ' \
str(fc.str_max_linked_bit_rate[1]) + '\",\"' + str(fc.modelname) + '\",\"' + \ 'is_connected, ' \
str(fc.fc.system_version) + '\",\"' + str(provider) + '\",\"' + str(status) + '\",\"' + \ 'str_transmission_rate_up, ' \
socket.gethostname() + '\")' 'str_transmission_rate_down, ' \
'str_max_bit_rate_up, ' \
'str_max_bit_rate_down, ' \
'str_max_linked_bit_rate_up, ' \
'str_max_linked_bit_rate_down, ' \
'model_name, ' \
'system_version, ' \
'provider, ' \
'message, ' \
'source_host '\
') VALUES (\"' + \
str(model.get_timestamp()) + '\",\"' + \
str(model.get_date()) + '\",\"' + \
str(model.get_time()) + '\",\"' + \
str(model.get_uptime()) + '\",\"' + \
str(model.get_internal_ip()) + '\",\"' + \
str(model.get_external_ip()) + '\",\"' + \
str(model.get_external_ipv6()) + '\",\"' + \
str(int(model.get_is_linked())) + '\",\"' + \
str(int(model.get_is_connected())) + '\",\"' + \
str(model.get_str_transmission_rate_up()) + '\",\"' + \
str(model.get_str_transmission_rate_down()) + '\",\"' + \
str(model.get_str_max_bit_rate_up()) + '\",\"' + \
str(model.get_str_max_bit_rate_down()) + '\",\"' + \
str(model.get_str_max_linked_bit_rate_up()) + '\",\"' + \
str(model.get_str_max_linked_bit_rate_down()) + '\",\"' + \
str(model.get_model_name()) + '\",\"' + \
str(model.get_system_version()) + '\",\"' + \
str(model.get_provider()) + '\",\"' + \
str(model.get_message()) + '\",\"' + \
str(model.get_source_host() + '\")')
with con.cursor() as cur: with con.cursor() as cur:
cur.execute(sql) cur.execute(sql)

View file

@ -26,4 +26,152 @@ logger = getLogger(__name__)
class Model: class Model:
def __init__(self, configuration): def __init__(self, configuration):
self.configuration = configuration self.__configuration = configuration
self.__date = None
self.__external_ip = None
self.__external_ipv6 = None
# no set method for id; it is auto incrementing in the database
self.__id = None
self.__internal_ip = None
self.__is_connected = None
self.__is_linked = None
self.__message = None
self.__model_name = None
self.__provider = None
self.__source_host = None
self.__str_max_bit_rate_down = None
self.__str_max_bit_rate_up = None
self.__str_max_linked_bit_rate_down = None
self.__str_max_linked_bit_rate_up = None
self.__str_transmission_rate_down = None
self.__str_transmission_rate_up = None
self.__system_version = None
self.__time = None
self.__timestamp = None
self.__uptime = None
# set methods:
def set_date(self, date):
self.__date = date
def set_external_ip(self, external_ip):
self.__external_ip = external_ip
def set_external_ipv6(self, external_ipv6):
self.__external_ipv6 = external_ipv6
def set_internal_ip(self, internal_ip):
self.__internal_ip = internal_ip
def set_is_connected(self, is_connected):
self.__is_connected = is_connected
def set_is_linked(self, is_linked):
self.__is_linked = is_linked
def set_message(self, message):
self.__message = message
def set_model_name (self, model_name):
self.__model_name = model_name
def set_provider(self, provider):
self.__provider = provider
def set_source_host(self, source_host):
self.__source_host = source_host
def set_str_max_bit_rate_down(self, str_max_bit_rate_down):
self.__str_max_bit_rate_down = str_max_bit_rate_down
def set_str_max_bit_rate_up(self, str_max_bit_rate_up):
self.__str_max_bit_rate_up = str_max_bit_rate_up
def set_str_max_linked_bit_rate_down(self, str_max_linked_bit_rate_down):
self.__str_max_linked_bit_rate_down = str_max_linked_bit_rate_down
def set_str_max_linked_bit_rate_up(self, str_max_linked_bit_rate_up):
self.__str_max_linked_bit_rate_up = str_max_linked_bit_rate_up
def set_str_transmission_rate_down(self, str_transmission_rate_down):
self.__str_transmission_rate_down = str_transmission_rate_down
def set_str_transmission_rate_up(self, str_transmission_rate_up):
self.__str_transmission_rate_up = str_transmission_rate_up
def set_system_version(self, system_version):
self.__system_version = system_version
def set_time(self, time):
self.__time = time
def set_timestamp(self, timestamp):
self.__timestamp = timestamp
def set_uptime(self, uptime):
self.__uptime = uptime
# get methods:
def get_date(self):
return self.__date
def get_external_ip(self):
return self.__external_ip
def get_external_ipv6(self):
return self.__external_ipv6
def get_id(self):
return self.__id
def get_internal_ip(self):
return self.__internal_ip
def get_is_connected(self):
return self.__is_connected
def get_is_linked(self):
return self.__is_linked
def get_message(self):
return self.__message
def get_model_name(self):
return self.__model_name
def get_provider(self):
return self.__provider
def get_source_host(self):
return self.__source_host
def get_str_max_bit_rate_down(self):
return self.__str_max_bit_rate_down
def get_str_max_bit_rate_up(self):
return self.__str_max_bit_rate_up
def get_str_max_linked_bit_rate_down(self):
return self.__str_max_linked_bit_rate_down
def get_str_max_linked_bit_rate_up(self):
return self.__str_max_linked_bit_rate_up
def get_str_transmission_rate_down(self):
return self.__str_transmission_rate_down
def get_str_transmission_rate_up(self):
return self.__str_transmission_rate_up
def get_system_version(self):
return self.__system_version
def get_time(self):
return self.__time
def get_timestamp(self):
return self.__timestamp
def get_uptime(self):
return self.__uptime

View file

@ -31,17 +31,17 @@ logger = getLogger(__name__)
class Server: class Server:
def __init__(self, configuration): def __init__(self, configuration):
self.configuration = configuration self.__configuration = configuration
@route('/hello/<name>') @route('/hello/<name>')
def index(self, name): def index(self, name):
return template('<b>Hello {{name}}</b>!', name=name) return template('<b>Hello {{name}}</b>!', name=name)
@route('/config') @route('/config')
def configuration(self): def config(self):
return template('<pre>{{config}}</pre>!', config=json.dumps(vars(self.configuration), return template('<pre>{{config}}</pre>!', config=json.dumps(vars(self.__configuration),
sort_keys=True, indent=4)) sort_keys=True, indent=4))
def run(self): def run_server(self):
run(host=self.configuration.get_httpserver_host(), run(host=self.__configuration.get_httpserver_host(),
port=self.configuration.get_httpserver_port()) port=self.__configuration.get_httpserver_port())

View file

@ -32,23 +32,23 @@ logger = getLogger(__name__)
class Server: class Server:
def __init__(self, configuration): def __init__(self, configuration):
self.configuration = configuration self.__configuration = configuration
@cherrypy.expose @cherrypy.expose
def index(self): def index(self):
return "Hello world!" return 'Hello world!'
@cherrypy.expose @cherrypy.expose
def config(self): def config(self):
return '<pre style="border:2px solid black;background:#1d2021;color:#f0751a;">' + \ return '<pre style="border:2px solid black;background:#1d2021;color:#f0751a;">' + \
json.dumps(vars(self.configuration), sort_keys=True, indent=4) + \ json.dumps(vars(self.__configuration), sort_keys=True, indent=4) + \
'</pre>' '</pre>'
@cherrypy.expose @cherrypy.expose
def playground(self): def playground(self):
return "My Playground!" return 'My Playground!'
def run(self): def run_server(self):
conf = { conf = {
'/': { '/': {
# 'tools.sessions.on': True, # 'tools.sessions.on': True,
@ -73,8 +73,8 @@ class Server:
#}) #})
cherrypy.config.update({ cherrypy.config.update({
'global': { 'global': {
'server.socket_host': self.configuration.get_httpserver_host(), 'server.socket_host': self.__configuration.get_httpserver_host(),
'server.socket_port': self.configuration.get_httpserver_port(), 'server.socket_port': self.__configuration.get_httpserver_port(),
'environment': 'production' 'environment': 'production'
} }
}) })

View file

@ -31,16 +31,16 @@ logger = getLogger(__name__)
class Server: class Server:
def __init__(self, configuration): def __init__(self, configuration):
self.configuration = configuration self.__configuration = configuration
def config(self, request): def config(self, request):
return Response(config=json.dumps(vars(self.configuration), sort_keys=True, indent=4)) return Response(config=json.dumps(vars(self.__configuration), sort_keys=True, indent=4))
def run(self): def run_server(self):
with Configurator() as config: with Configurator() as config:
config.add_route('config', '/') config.add_route('config', '/')
config.add_view(self.config, route_name='config') config.add_view(self.config, route_name='config')
app = config.make_wsgi_app() app = config.make_wsgi_app()
server = make_server(self.configuration.get_httpserver_host(), server = make_server(self.__configuration.get_httpserver_host(),
self.configuration.get_httpserver_port(), app) self.__configuration.get_httpserver_port(), app)
server.serve_forever() server.serve_forever()

View file

@ -24,6 +24,7 @@
# be optional too. # be optional too.
import calendar import calendar
import socket
import time import time
from fritzconnection.lib.fritzstatus import FritzStatus from fritzconnection.lib.fritzstatus import FritzStatus
@ -60,13 +61,33 @@ class Uplink(Daemon):
else: else:
self.status = 'DOWN' self.status = 'DOWN'
logger.info(str(uplink['provider'] + ' ' + self.status + ' (ip: ' + logger.info(str(uplink['provider'] + ' (uplink IP: ' + fc.external_ip + ') ' +
fc.external_ip + ')')) self.status))
model = Model(self.configuration) model = Model(self.configuration)
model.set_date(self.date)
model.set_external_ip(fc.external_ip)
model.set_external_ipv6(fc.external_ipv6)
model.set_internal_ip(uplink['ip'])
model.set_is_connected(fc.is_connected)
model.set_is_linked(fc.is_linked)
model.set_message(self.status)
model.set_model_name(fc.modelname)
model.set_provider(uplink['provider'])
model.set_source_host(socket.gethostname())
model.set_str_max_bit_rate_down(fc.str_max_bit_rate[1])
model.set_str_max_bit_rate_up(fc.str_max_bit_rate[0])
model.set_str_max_linked_bit_rate_down(fc.str_max_linked_bit_rate[1])
model.set_str_max_linked_bit_rate_up(fc.str_max_linked_bit_rate[0])
model.set_str_transmission_rate_down(fc.str_transmission_rate[1])
model.set_str_transmission_rate_up (fc.str_transmission_rate[0])
model.set_system_version(fc.fc.system_version)
model.set_time(self.time)
model.set_timestamp(timestamp)
model.set_uptime(fc.connection_uptime)
database = Database(self.configuration) database = Database(self.configuration)
database.write_to_db(fc, uplink['ip'], uplink['provider'], self.status) database.write_model_to_db(model)
except Exception as err: except Exception as err:
message = str('error when getting data from ' + uplink['ip'] + ': {0}') message = str('error when getting data from ' + uplink['ip'] + ': {0}')
@ -77,17 +98,17 @@ class Uplink(Daemon):
if self.configuration.get_httpserver_framework() == 'bottle': if self.configuration.get_httpserver_framework() == 'bottle':
from uplink.server_bottle import Server from uplink.server_bottle import Server
s = Server(self.configuration) s = Server(self.configuration)
st = Thread(target=s.run, daemon=True) st = Thread(target=s.run_server, daemon=True)
st.start() st.start()
elif self.configuration.get_httpserver_framework() == 'cherrypy': elif self.configuration.get_httpserver_framework() == 'cherrypy':
from uplink.server_cherrypy import Server from uplink.server_cherrypy import Server
s = Server(self.configuration) s = Server(self.configuration)
st = Thread(target=s.run, daemon=True) st = Thread(target=s.run_server, daemon=True)
st.start() st.start()
elif self.configuration.get_httpserver_framework() == 'pyramid': elif self.configuration.get_httpserver_framework() == 'pyramid':
from uplink.server_pyramid import Server from uplink.server_pyramid import Server
s = Server(self.configuration) s = Server(self.configuration)
st = Thread(target=s.run, daemon=True) st = Thread(target=s.run_server, daemon=True)
st.start() st.start()
while True: while True:
for i in range(len(self.configuration.get_uplinks())): for i in range(len(self.configuration.get_uplinks())):