From c319417ee386241283ef123b5fd7d79eda92851a Mon Sep 17 00:00:00 2001 From: Johannes Findeisen Date: Sat, 10 Sep 2022 01:09:38 +0200 Subject: [PATCH] Seperated environment vars from configuration to exclusive object and added a seperate URL (/environment) for requesting data from the HTTP server. --- bin/uplink | 21 ++++++----- uplink/configuration.py | 16 --------- uplink/environment.py | 55 ++++++++++++++++++++++++++++ uplink/httpserver.py | 24 +++++++++++-- uplink/notification.py | 2 +- uplink/speedtest.py | 13 +++---- uplink/uplink.py | 80 ++++++++++++++++++++--------------------- 7 files changed, 136 insertions(+), 75 deletions(-) create mode 100644 uplink/environment.py diff --git a/bin/uplink b/bin/uplink index 7813f70..d2f5188 100755 --- a/bin/uplink +++ b/bin/uplink @@ -36,6 +36,7 @@ import sys import time from uplink.configuration import Configuration +from uplink.environment import Environment from uplink.uplink import Uplink """ @@ -48,7 +49,7 @@ MINOR changes are "just-in-time" changes or small enhancements which should not documentation. FIXES should never affect anything else then stability or security. """ -__version__ = '0.8.4.2' +__version__ = '0.9.0.0' __author__ = 'Johannes Findeisen ' logger = logging.getLogger('uplink') @@ -108,15 +109,17 @@ def main(): logger.error(str('[uplink] configuration error: {0}'.format(err))) sys.exit(1) + environment = Environment() + # To be more cross-platform compatible maybe changes are needed: # https://stackoverflow.com/questions/4271740/how-can-i-use-python-to-get-the-system-hostname - configuration.set_env_var('_hostname', socket.gethostname()) + environment.set_env_var('_hostname', socket.gethostname()) - configuration.set_env_var('__version__', __version__) + environment.set_env_var('__version__', __version__) - configuration.set_env_var('_internal_start_date', time.strftime('%Y-%m-%d %H:%M:%S', - time.localtime(calendar.timegm(time.gmtime())))) - configuration.set_env_var('_internal_start_timestamp', calendar.timegm(time.gmtime())) + environment.set_env_var('_internal_start_date', time.strftime('%Y-%m-%d %H:%M:%S', + time.localtime(calendar.timegm(time.gmtime())))) + environment.set_env_var('_internal_start_timestamp', calendar.timegm(time.gmtime())) # interval set in args is overriding configuration and default if args.interval: @@ -157,7 +160,7 @@ def main(): configuration.set_httpserver(True) try: - u = Uplink(configuration) + u = Uplink(configuration, environment) except Exception as err: logger.error(str('[uplink] core error! {0}'.format(err))) sys.exit(1) @@ -178,13 +181,13 @@ def main(): from threading import Thread if configuration.get_httpserver(): from uplink.httpserver import HTTPServer - s = HTTPServer(configuration) + s = HTTPServer(configuration, environment) st = Thread(target=s.run_server, daemon=True) st.start() if configuration.get_speedtest(): from uplink.speedtest import Speedtest - se = Speedtest(configuration) + se = Speedtest(configuration, environment) ste = Thread(target=se.run_speedtest, daemon=True) ste.start() diff --git a/uplink/configuration.py b/uplink/configuration.py index 9ebebfc..593f3fd 100644 --- a/uplink/configuration.py +++ b/uplink/configuration.py @@ -31,15 +31,11 @@ class Configuration: def __init__(self, configuration): self.__configuration = configuration - self.__base_configuration = None self.__database_host = None self.__database_name = None self.__database_password = None self.__database_port = 3306 self.__database_user = None - # environment vars which can be set dynamically at runtime. these vars are shared across all - # objects and readable and writable by all of them. - self.__env = {} self.__httpserver = False self.__httpserver_host = '127.0.0.1' self.__httpserver_port = 1042 @@ -182,15 +178,6 @@ class Configuration: def get_database_user(self): return self.__database_user - def get_env(self): - return self.__env - - def get_env_var(self, key): - if key in self.__env: - return self.__env[key] - else: - return False - def get_httpserver(self): return self.__httpserver @@ -249,9 +236,6 @@ class Configuration: return self.__uplinks # set methods - def set_env_var(self, key, value): - self.__env[key] = value - def set_httpserver(self, value): self.__httpserver = value diff --git a/uplink/environment.py b/uplink/environment.py new file mode 100644 index 0000000..0a93519 --- /dev/null +++ b/uplink/environment.py @@ -0,0 +1,55 @@ +# Copyright (c) 2022 Johannes Findeisen +# +# 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. + +import re +import socket + +from logging import getLogger + +logger = getLogger('uplink') + +""" +This is experimental because you can set what you want but if a env key you set already exists it +will be overwritten. But it is an easy and maybe secure way to to set runtime variables which should +not affect the execution of uplink but may be required variables to execute to your wanted +configuration. Core functionality must not be affected when using this class! +""" + + +class Environment: + + def __init__(self): + # environment vars which can be set dynamically at runtime. these vars are shared across all + # objects and readable and writable by all of them. + self.__env = {} + + def get_env_var(self, key): + if key in self.__env: + return self.__env[key] + else: + logger.info('environment var "' + key + '" not found! could be that is set late at ' + 'runtime. if you encounter errors executing ' + 'uplink, something is wrong in the code. ' + 'please consider to report this as a bug! btw. ' + 'INFO is not an ERROR!') + return False + + def set_env_var(self, key, value): + self.__env[key] = value diff --git a/uplink/httpserver.py b/uplink/httpserver.py index 5b8e0d4..5d710ac 100644 --- a/uplink/httpserver.py +++ b/uplink/httpserver.py @@ -31,8 +31,9 @@ logger = getLogger('uplink') class HTTPServer: - def __init__(self, configuration): + def __init__(self, configuration, environment): self.__configuration = configuration + self.__environment = environment @cherrypy.expose def index(self): @@ -41,13 +42,25 @@ class HTTPServer: @cherrypy.expose def configuration(self): return '[uplink-' + \ - self.__configuration.get_env_var("__version__") + '@' + \ - self.__configuration.get_env_var("_hostname") + '] configuration
' + \
                json.dumps(vars(self.__configuration), sort_keys=True, indent=4) + \
                '
' + @cherrypy.expose + def environment(self): + return '[uplink-' + \ + self.__environment.get_env_var("__version__") + '@' + \ + self.__environment.get_env_var("_hostname") + '] environment
' + \
+               json.dumps(vars(self.__environment), sort_keys=True, indent=4) + \
+               '
' + + + @cherrypy.expose def playground(self): return 'My Playground!' @@ -65,6 +78,11 @@ class HTTPServer: 'tools.response_headers.on': True, 'tools.response_headers.headers': [('Content-Type', 'text/html')], }, + '/environment': { + # 'request.dispatch': cherrypy.dispatch.MethodDispatcher(), + 'tools.response_headers.on': True, + 'tools.response_headers.headers': [('Content-Type', 'text/html')], + }, '/playground': { # 'tools.staticdir.on': True, # 'tools.staticdir.dir': './public' diff --git a/uplink/notification.py b/uplink/notification.py index e2f3217..a01ccce 100644 --- a/uplink/notification.py +++ b/uplink/notification.py @@ -27,7 +27,7 @@ logger = getLogger('uplink') class Notification: - def __init__(self, configuration): + def __init__(self, configuration, environment): self.__configuration = configuration #self.__state_machine = gammu.StateMachine() #self.__state_machine.ReadConfig( diff --git a/uplink/speedtest.py b/uplink/speedtest.py index ea919d1..c170343 100644 --- a/uplink/speedtest.py +++ b/uplink/speedtest.py @@ -29,8 +29,9 @@ logger = getLogger('uplink') class Speedtest: - def __init__(self, configuration): + def __init__(self, configuration, environment): self.__configuration = configuration + self.__environment = environment self.__speedtest_maximum_speed = None self.__speedtest_average_speed = None @@ -39,11 +40,11 @@ class Speedtest: def run_speedtest(self): while True: tmp_time = time.localtime(calendar.timegm(time.gmtime())) - self.__configuration.set_env_var('_speedtest_last_run_date', + self.__environment.set_env_var('_speedtest_last_run_date', time.strftime('%Y-%m-%d %H:%M:%S', tmp_time)) - self.__configuration.set_env_var('_speedtest_last_run_timestamp', + self.__environment.set_env_var('_speedtest_last_run_timestamp', calendar.timegm(time.gmtime())) start = time.perf_counter() @@ -65,15 +66,15 @@ class Speedtest: total_mbps += mbps self.__speedtest_average_speed = total_mbps / total_chunks - self.__configuration.set_env_var('_speedtest_average_speed_megabyte_per_second', + self.__environment.set_env_var('_speedtest_average_speed_megabyte_per_second', str(round(self.__speedtest_average_speed))) self.__speedtest_maximum_speed = maximum_speed - self.__configuration.set_env_var('_speedtest_maximum_speed_megabyte_per_second', + self.__environment.set_env_var('_speedtest_maximum_speed_megabyte_per_second', str(round(self.__speedtest_maximum_speed))) self.__speedtest_time_elapsed = time.perf_counter() - start - self.__configuration.set_env_var('_speedtest_time_elapsed', + self.__environment.set_env_var('_speedtest_time_elapsed', str(self.__speedtest_time_elapsed)) logger.info('speedtest average: ' + str(self.__speedtest_average_speed) + ', max: ' + str(self.__speedtest_maximum_speed) + diff --git a/uplink/uplink.py b/uplink/uplink.py index 57d301f..baa991f 100644 --- a/uplink/uplink.py +++ b/uplink/uplink.py @@ -23,7 +23,6 @@ # be optional too. Also reinvent SQLite as database backend. import calendar -import logging import socket import time @@ -39,9 +38,10 @@ logger = getLogger('uplink') class Uplink(Daemon): - def __init__(self, configuration): + def __init__(self, configuration, environment): super().__init__(configuration.get_pid_file()) self.__configuration = configuration + self.__environment = environment def fetch_data(self, i): timestamp = calendar.timegm(time.gmtime()) @@ -49,68 +49,68 @@ class Uplink(Daemon): date_formatted = time.strftime('%Y-%m-%d', local_time) time_formatted = time.strftime('%H:%M:%S', local_time) - self.__configuration.set_env_var('_internal_last_run_date', date_formatted + ' ' + - time_formatted) - self.__configuration.set_env_var('_internal_last_run_timestamp', timestamp) + self.__environment.set_env_var('_internal_last_run_date', date_formatted + ' ' + + time_formatted) + self.__environment.set_env_var('_internal_last_run_timestamp', timestamp) uplink = self.__configuration.get_uplink(i) if 'primary' in uplink: - self.__configuration.set_env_var('_uplink_' + uplink['identifier'] + '_primary', - uplink['primary']) + self.__environment.set_env_var('_uplink_' + uplink['identifier'] + '_primary', + uplink['primary']) - if self.__configuration.get_env_var('_uplink_' + uplink['identifier'] + - '_fail_count') is False: - self.__configuration.set_env_var('_uplink_' + uplink['identifier'] + - '_fail_count', 0) + if self.__environment.get_env_var('_uplink_' + uplink['identifier'] + + '_fail_count') is False: + self.__environment.set_env_var('_uplink_' + uplink['identifier'] + + '_fail_count', 0) - if self.__configuration.get_env_var('_uplink_' + uplink['identifier'] + - '_fail_overall_count') is False: - self.__configuration.set_env_var('_uplink_' + uplink['identifier'] + - '_fail_overall_count', 0) + if self.__environment.get_env_var('_uplink_' + uplink['identifier'] + + '_fail_overall_count') is False: + self.__environment.set_env_var('_uplink_' + uplink['identifier'] + + '_fail_overall_count', 0) try: fritz_connection = FritzStatus(address=uplink['ip'], password=uplink['password']) if fritz_connection.is_connected: - self.__configuration.set_env_var('_uplink_' + uplink['identifier'] + - '_fail_count', 0) + self.__environment.set_env_var('_uplink_' + uplink['identifier'] + + '_fail_count', 0) - self.__configuration.set_env_var('_uplink_' + uplink['identifier'] + - '_last_success_date', date_formatted + ' ' + - time_formatted) + self.__environment.set_env_var('_uplink_' + uplink['identifier'] + + '_last_success_date', date_formatted + ' ' + + time_formatted) - self.__configuration.set_env_var('_uplink_' + uplink['identifier'] + - '_last_success_timestamp', timestamp) + self.__environment.set_env_var('_uplink_' + uplink['identifier'] + + '_last_success_timestamp', timestamp) - self.__configuration.set_env_var('_uplink_' + uplink['identifier'] + - '_status', 'UP') + self.__environment.set_env_var('_uplink_' + uplink['identifier'] + + '_status', 'UP') status = 'UP' else: fail_count = self.__configuration.get_env_var('_uplink_' + uplink['identifier'] + '_fail_count') fail_count += 1 - self.__configuration.set_env_var('_uplink_' + uplink['identifier'] + '_fail_count', - fail_count) + self.__environment.set_env_var('_uplink_' + uplink['identifier'] + '_fail_count', + fail_count) - fail_overall_count = self.__configuration.get_env_var('_uplink_' + - uplink['identifier'] + - '_fail_overall_count') + fail_overall_count = self.__environment.get_env_var('_uplink_' + + uplink['identifier'] + + '_fail_overall_count') fail_overall_count += 1 - self.__configuration.set_env_var('_uplink_' + uplink['identifier'] + - '_fail_overall_count', fail_overall_count) + self.__environment.set_env_var('_uplink_' + uplink['identifier'] + + '_fail_overall_count', fail_overall_count) - self.__configuration.set_env_var('_uplink_' + uplink['identifier'] + - '_last_fail_date', date_formatted + ' ' + - time_formatted) + self.__environment.set_env_var('_uplink_' + uplink['identifier'] + + '_last_fail_date', date_formatted + ' ' + + time_formatted) - self.__configuration.set_env_var('_uplink_' + uplink['identifier'] + - '_last_fail_timestamp', timestamp) + self.__environment.set_env_var('_uplink_' + uplink['identifier'] + + '_last_fail_timestamp', timestamp) - self.__configuration.set_env_var('_uplink_' + uplink['identifier'] + - '_status', 'DOWN') + self.__environment.set_env_var('_uplink_' + uplink['identifier'] + + '_status', 'DOWN') status = 'DOWN' @@ -161,13 +161,13 @@ class Uplink(Daemon): def run(self): if self.__configuration.get_http_server(): from uplink.httpserver import HTTPServer - hs = HTTPServer(self.__configuration) + hs = HTTPServer(self.__configuration, self.__environment) hst = Thread(target=hs.run_server, daemon=True) hst.start() if self.__configuration.get_speedtest(): from uplink.speedtest import Speedtest - st = Speedtest(self.__configuration) + st = Speedtest(self.__configuration, self.__environment) stt = Thread(target=st.run_speedtest, daemon=True) stt.start()