From e4ad0bc5d57ebbcd986c976e302d59e67e0451c7 Mon Sep 17 00:00:00 2001 From: Johannes Findeisen Date: Wed, 22 Feb 2023 22:39:51 +0100 Subject: [PATCH] Refactoring! Removed all unused code and made stuff consistent! (0.20.4) --- bin/linspector | 2 +- etc/monitors/network1/gateway.conf | 6 +- etc/monitors/network2/gateway.conf | 5 +- linspector/core/linspector.py | 21 +- linspector/core/monitor.py | 257 ++++-------------- linspector/core/monitors.py | 20 +- .../services/vendor/avm/is_connected.py | 12 +- 7 files changed, 79 insertions(+), 244 deletions(-) diff --git a/bin/linspector b/bin/linspector index c765948..af1e589 100755 --- a/bin/linspector +++ b/bin/linspector @@ -17,7 +17,7 @@ from linspector.core.linspector import Linspector from linspector.core.logger import Log from linspector.core.monitors import Monitors -__version__ = '0.20.3' +__version__ = '0.20.4' __author__ = 'Johannes Findeisen ' diff --git a/etc/monitors/network1/gateway.conf b/etc/monitors/network1/gateway.conf index 561913e..8d3a1c4 100644 --- a/etc/monitors/network1/gateway.conf +++ b/etc/monitors/network1/gateway.conf @@ -2,11 +2,9 @@ title = Uplink Status description = Cable Provider Uplink Status service = vendor.avm.is_connected -; this is obsolete because the host will become part of the args but removing it now will break the code. linspector -; should be for checking local or remote stuff so a host is optional. -hosts = 192.168.1.1 +host = 192.168.1.1 +interval = 60 [args] host = 192.168.1.1 password = PASSWORD -interval = 60 diff --git a/etc/monitors/network2/gateway.conf b/etc/monitors/network2/gateway.conf index 4d58652..8a72f92 100644 --- a/etc/monitors/network2/gateway.conf +++ b/etc/monitors/network2/gateway.conf @@ -2,9 +2,8 @@ title = Uplink Status description = DSL Provider Uplink Status service = vendor.avm.is_connected -hosts = 192.168.2.1 +host = 192.168.2.1 +interval = 5 [args] -host = 192.168.2.1 password = PASSWORD -interval = 5 diff --git a/linspector/core/linspector.py b/linspector/core/linspector.py index feb6b82..e7a8fe5 100644 --- a/linspector/core/linspector.py +++ b/linspector/core/linspector.py @@ -13,11 +13,11 @@ from apscheduler.jobstores.memory import MemoryJobStore from apscheduler.schedulers.background import BackgroundScheduler -def job_function(log, monitor): +def job_execution(log, monitor): try: log.debug('executing job_function for monitor identifier: ' + monitor.get_identifier() + ' with monitor object: ' + str(monitor)) - monitor.handle_call() + monitor.execute() except Exception as err: log.warning('execution failed for job_function for monitor identifier: ' + monitor.get_identifier() + ' with monitor object: ' + str(monitor) + @@ -107,15 +107,17 @@ class Linspector: # add cron and one time run jobs to Linspector. not only "interval" jobs should be # supported. - scheduler_job = scheduler['linspector'].add_job(job_function, 'interval', + scheduler_job = scheduler['linspector'].add_job(job_execution, + 'interval', start_date=new_start_date, - seconds=interval, timezone=timezone, + seconds=interval, + timezone=timezone, args=[log, monitors.get(monitor)]) monitor_job.set_job(scheduler_job) self.__jobs.append(monitor_job) log.info('identifier=' + monitor + - ' host=' + "NOT IMPLEMENTED" + + ' host=' + monitors.get(monitor).get_host() + ' service=' + monitor_job.get_service() + ' delta=' + str(time_delta) + ' next=' + str(new_start_date) + @@ -123,12 +125,3 @@ class Linspector: if configuration.get_option('linspector', 'start_scheduler') == 'true': self.__scheduler['linspector'].start() - - # this function is just for testing purposes and can be removed some day - def print_debug(self): - # example on how to access the monitor objects in monitors - monitors = self.__monitors.get_monitors() - print(__file__ + ' (78): ' + str(monitors)) - for monitor in monitors: - print(__file__ + ' (80): ' + monitors.get(monitor).get_identifier()) - print(__file__ + ' (81): ' + monitors.get(monitor).get_service()) diff --git a/linspector/core/monitor.py b/linspector/core/monitor.py index 190a15c..14063a5 100644 --- a/linspector/core/monitor.py +++ b/linspector/core/monitor.py @@ -4,10 +4,7 @@ Copyright (c) 2022 Johannes Findeisen . All Rights Reserved. See LICENSE.txt (MIT license). """ import configparser -import hashlib import importlib -from binascii import crc32 -from datetime import datetime class Monitor: @@ -15,23 +12,32 @@ class Monitor: notifications, services, tasks, kwargs): self.__args = kwargs self.__configuration = configuration + self.__enabled = True self.__environment = environment - self.__identifier = identifier + self.__host = monitor_configuration.get('monitor', 'host') + try: - self.__interval = int(monitor_configuration.get('args', 'interval')) + self.__hostgroups = monitor_configuration.get('monitor', 'hostgroups') + except configparser.NoOptionError as err: + self.__hostgroups = "None" + + self.__identifier = identifier + self.__job_threshold = 0 + + try: + self.__interval = int(monitor_configuration.get('monitor', 'interval')) except Exception as err: - log.warning('no interval set in identifier ' + identifier + ', trying to get a monitor ' - 'configuration ' - 'setting. error: ' + - str(err)) + log.warning('no interval set in identifier ' + identifier + + ', trying to get a monitor configuration setting. error: ' + str(err)) + try: self.__interval = int(configuration.get_option('linspector', 'default_interval')) log.warning('set default_interval as per core configuration with ' 'identifier: ' + identifier + ' to: ' + str(self.__interval)) except Exception as err: log.warning('no default_interval found in core configuration for identifier ' + - identifier + ', set to default interval 300 seconds. error: ' + str( - err)) + identifier + + ', set to default interval 300 seconds. error: ' + str(err)) # default interval is 300 seconds (5 minutes) if not set in the monitor # configuration args or a default_interval in the core configuration. self.__interval = 300 @@ -40,6 +46,8 @@ class Monitor: self.__monitor_configuration = monitor_configuration self.__notification_list = [] self.__notifications = notifications + self.__scheduler_job = None + try: self.__service = monitor_configuration.get('monitor', 'service') except Exception as err: @@ -56,19 +64,6 @@ class Monitor: self.__services = services self.__task_list = [] # put tasks for the dedicated job here. self.__tasks = tasks - self.service = self.__service - self.host = monitor_configuration.get('monitor', 'hosts') - - try: - self.hostgroups = monitor_configuration.get('monitor', 'hostgroups') - except configparser.NoOptionError as err: - self.hostgroups = "None" - - self.job_threshold = 0 - self.enabled = True - self.scheduler_job = None - # the monitor_id is a sha256 string. - self.monitor_id = self.generate_monitor_id() """ NONE job was not executed @@ -78,12 +73,9 @@ class Monitor: ERROR when a jobs error threshold is overridden UNKNOWN when a job throws an exception which is not handled by the job itself (not implemented) - """ self.status = "NONE" self.last_execution = None - # self.monitor_information = MonitorInformation(self.monitor_id, self.hostgroup, self.host, - # self.service) - self.monitor_information = MonitorInformation(self.monitor_id, self.service) + """ try: if configuration.get_option('linspector', 'notifications') or \ @@ -149,6 +141,28 @@ class Monitor: except configparser.NoOptionError: self.__tasks = tasks + def execute(self): + self.__log.debug('identifier=' + self.__identifier + + ' object=' + str(self)) + self.__log.debug('identifier=' + self.__identifier + + ' message=handle call to service') + + if self.__enabled: + try: + self.__services[self.__service].execute(self.__identifier, + self, self.__service, + **self.__args) + except Exception as err: + self.__log.error(err) + else: + self.__log.info('identifier=' + self.__identifier + ' message=is disabled') + + def get_host(self): + return self.__host + + def get_hostgroups(self): + return self.__hostgroups + def get_identifier(self): return self.__identifier @@ -163,192 +177,15 @@ class Monitor: return self.__monitor_configuration.get(section, option) else: return None - return self.__monitor_configuration def get_service(self): return self.__service - def __str__(self): - return str(self.__dict__) - - def hex_string(self): - ret = hex(crc32(bytes(self.host + self.hostgroups + self.service, 'utf-8'))) - # ret = self.__hex__() - if ret[0] == "-": - ret = ret[3:] - else: - ret = ret[2:] - while len(ret) < 8: - ret = "0" + ret - return ret - - def generate_monitor_id(self): - return hashlib.sha256(bytes(self.__identifier + self.host + self.hostgroups + self.service, - 'utf-8')).hexdigest() + def set_enabled(self, enabled=True): + self.__enabled = enabled def set_job(self, scheduler_job): - self.scheduler_job = scheduler_job + self.__scheduler_job = scheduler_job - def set_enabled(self, enabled=True): - self.enabled = enabled - - def handle_threshold(self, service_threshold, execution_successful): - if execution_successful: - if self.job_threshold > 0: - if "threshold_reset" in self.core and self.core["threshold_reset"]: - # logger.info("Job " + self.get_monitor_id() + ", Threshold Reset") - self.job_threshold = 0 - else: - # logger.info("Job " + self.get_monitor_id() + ", Threshold Decrement") - self.job_threshold -= 1 - - self.status = "OK" - self.monitor_information.set_status(self.status) - self.monitor_information.inc_job_overall_wins() - else: - self.status = "WARNING" - self.monitor_information.set_status(self.status) - self.monitor_information.inc_job_overall_fails() - self.job_threshold += 1 - - if self.job_threshold >= service_threshold: - # logger.info("Job " + self.get_monitor_id() + ", Threshold reached!") - self.status = "ERROR" - self.monitor_information.set_status(self.status) - - def handle_tasks(self, monitor_information): - for task in self.__tasks: - if self.status.lower() in task.get_task_type().lower(): - self.__log.debug('message=executing task type=' + self.status) - # tasks can but should not be executed here. putting them in a queue is the better - # solution to execute them in a serial process. - # TaskExecutor.instance().schedule_task(monitor_information, task) - - def handle_call(self): - self.__log.debug('identifier=' + self.__identifier + - ' object=' + str(self)) - self.__log.debug('identifier=' + self.__identifier + - ' message=handle call to service') - # logger.debug("handle call") - # logger.debug(self.service) - if self.enabled: - self.last_execution = None - try: - self.last_execution = MonitorExecution(self.get_host()) - # self.__services[self.__service].execute(self.last_execution) - self.__services[self.__service].execute(self.__identifier, self.__service, **self.__args) - except Exception as err: - self.__log.error(err) - - # self.last_execution.set_execution_end() - - # self.handle_threshold(self.service.get_threshold(), - # self.last_execution.was_successful()) - - # log.info("Job " + self.get_monitor_id() + - # ", Code: " + str(self.last_execution.get_error_code()) + - # ", Message: " + str(self.last_execution.get_message())) - - # self.monitor_information.set_response_message( - # self.last_execution.get_response_message(self)) - - # self.handle_tasks(self.monitor_information) - else: - self.__log.info('job ' + self.get_monitor_id() + ' disabled') - - def get_host(self): - return self.host - - def get_hostgroups(self): - return self.hostgroups - - -class MonitorExecution: - def __init__(self, host): - self.execution_start = datetime.now() - self.execution_end = -1 - self.host = host - self.error_code = -1 - self.message = None - self.kwargs = None - - def get_host_name(self): - return self.host - - def get_message(self): - return self.message - - def get_kwargs(self): - return self.kwargs - - def set_execution_end(self): - self.execution_end = datetime.now() - - def get_error_code(self): - return self.error_code - - def was_successful(self): - return self.get_error_code() == 0 - - def set_result(self, error_code=0, message="", kwargs=None): - self.error_code = error_code - self.message = message - self.kwargs = kwargs - - def get_response_message(self, job): - msg = str(job.status) + " [" + job.service.get_config_name() + ": " + \ - str(job.get_monitor_id()) + "] " + str(job.get_hostgroup()) + " " + \ - str(job.get_host()) - if self.get_message() is not None: - msg += " " + str(self.get_message()) - if self.get_kwargs() is not None: - msg += " " + str(self.get_kwargs()) - return msg - - -class MonitorInformation: - def __init__(self, monitor_id, service): - self.monitor_id = monitor_id - # self.hostgroup = hostgroup - # self.host = host - self.service = service - - self.response_massage = None - self.period = None - self.next_run = None - self.runs = 0 - self.enabled = None - self.threshold = 0 - self.fails = 0 - self.job_overall_fails = 0 - self.job_overall_wins = 0 - self.last_execution = None - self.last_run = None - self.last_fail = None - self.last_success = None - self.last_disabled = None - self.last_enabled = None - self.last_threshold_override = None - self.last_escalation = None - self.status = "NONE" - - def inc_job_overall_fails(self): - self.job_overall_fails += 1 - - def inc_job_overall_wins(self): - self.job_overall_wins += 1 - - def get_monitor_id(self): - return self.monitor_id - - def get_response_message(self): - return self.response_massage - - def set_response_message(self, msg): - self.response_massage = msg - - def get_status(self): - return self.status - - def set_status(self, status): - self.status = status + def __str__(self): + return str(self.__dict__) diff --git a/linspector/core/monitors.py b/linspector/core/monitors.py index defeb80..44514cd 100644 --- a/linspector/core/monitors.py +++ b/linspector/core/monitors.py @@ -4,14 +4,13 @@ Copyright (c) 2022 Johannes Findeisen . All Rights Reserved. See LICENSE.txt (MIT license). """ import configparser -import copy import glob import os from linspector.core.monitor import Monitor -# monitors may could / should be added (and maybe changed) at runtime to add new monitors without +# monitors may must / should be added (and maybe changed) at runtime to add new monitors without # restarting the daemon. maybe add a reset function to each monitor to reset the monitor at runtime # when changed dynamically. class Monitors: @@ -19,7 +18,10 @@ class Monitors: self.__configuration = configuration self.__environment = environment self.__log = log + self.__notifications = notifications self.__monitors = {} + self.__services = services + self.__tasks = tasks monitor_groups = os.listdir(self.__configuration.get_configuration_path() + '/monitors/') log.debug('monitor groups: ' + str(monitor_groups)) @@ -50,10 +52,16 @@ class Monitors: monitor_file))[0] # create Monitor() object and copy monitor_configuration for each instance because - # they else refer to the same object. - self.__monitors[identifier] = Monitor(configuration, environment, identifier, - log, monitor_configuration, notifications, - services, tasks, copy.deepcopy(kwargs)) + # they else refer to the same object? copy.deepcopy(monitor_configuration)??? + self.__monitors[identifier] = Monitor(self.__configuration, + self.__environment, + identifier, + self.__log, + monitor_configuration, + self.__notifications, + self.__services, + self.__tasks, + kwargs) del kwargs diff --git a/linspector/services/vendor/avm/is_connected.py b/linspector/services/vendor/avm/is_connected.py index 57ff4d7..2fbdbaf 100644 --- a/linspector/services/vendor/avm/is_connected.py +++ b/linspector/services/vendor/avm/is_connected.py @@ -19,23 +19,23 @@ class IsConnectedService(Service): self.__environment = environment self.__log = log - def execute(self, identifier, service, **kwargs): + def execute(self, identifier, monitor, service, **kwargs): self.__log.debug('identifier=' + identifier + 'service=' + service + ' object=' + str(self) + ' kwargs=' + str(kwargs)) try: - fc = FritzStatus(address=kwargs['host'], + fc = FritzStatus(address=monitor.get_host(), password=kwargs['password']) - except Exception: + except Exception as err: self.__log.error('identifier=' + identifier + - ' host=' + str(kwargs['host']) + + ' host=' + monitor.get_host() + ' service=' + service + - ' failed ') + ' error=' + str(err)) return False self.__log.info('identifier=' + identifier + - ' host=' + str(kwargs['host']) + + ' host=' + monitor.get_host() + ' service=' + service + ' status=' + ('OK' if fc.is_connected else 'ERROR'))