From 1c052a63c0ba896d43c06f1a06d73b73d2d2370e Mon Sep 17 00:00:00 2001 From: Hemna Date: Mon, 21 Feb 2022 16:04:33 -0500 Subject: [PATCH] Fixed up config option checking for KISS This patch updates the config option checking for required fields in the config yaml file. Specifically for the existence of the aprsd: section and the required fields for the 3 supported client types apris, kiss serial, kiss tcp --- aprsd/cli_helper.py | 3 ++- aprsd/client.py | 60 +++++++++++++++++++++++++++++++++++++++++--- aprsd/cmds/server.py | 4 +++ aprsd/config.py | 26 ++++++------------- aprsd/exception.py | 13 ++++++++++ aprsd/log.py | 4 +-- aprsd/threads.py | 8 +++++- tox.ini | 2 +- 8 files changed, 93 insertions(+), 27 deletions(-) create mode 100644 aprsd/exception.py diff --git a/aprsd/cli_helper.py b/aprsd/cli_helper.py index 45a5b94..a52f260 100644 --- a/aprsd/cli_helper.py +++ b/aprsd/cli_helper.py @@ -55,7 +55,8 @@ def process_standard_options(f: F) -> F: ctx.obj["quiet"] = kwargs["quiet"] ctx.obj["config"] = aprsd_config.parse_config(kwargs["config_file"]) log.setup_logging( - ctx.obj["config"], ctx.obj["loglevel"], + ctx.obj["config"], + ctx.obj["loglevel"], ctx.obj["quiet"], ) diff --git a/aprsd/client.py b/aprsd/client.py index 3d796a5..06dc1cd 100644 --- a/aprsd/client.py +++ b/aprsd/client.py @@ -5,7 +5,8 @@ import time import aprslib from aprslib.exceptions import LoginError -from aprsd import trace +from aprsd import config as aprsd_config +from aprsd import exception, trace from aprsd.clients import aprsis, kiss @@ -76,7 +77,21 @@ class APRSISClient(Client): @staticmethod def is_enabled(config): # Defaults to True if the enabled flag is non existent - return config["aprs"].get("enabled", True) + try: + return config["aprs"].get("enabled", True) + except KeyError: + return False + + @staticmethod + def is_configured(config): + if APRSISClient.is_enabled(config): + # Ensure that the config vars are correctly set + config.check_option("aprs.login") + config.check_option("aprs.password") + config.check_option("aprs.host") + return True + + return True @staticmethod def transport(config): @@ -133,6 +148,26 @@ class KISSClient(Client): return False + @staticmethod + def is_configured(config): + # Ensure that the config vars are correctly set + if KISSClient.is_enabled(config): + config.check_option( + "kiss.callsign", + default_fail=aprsd_config.DEFAULT_CONFIG_DICT["kiss"]["callsign"], + ) + transport = KISSClient.transport(config) + if transport == TRANSPORT_SERIALKISS: + config.check_option("kiss.serial") + config.check_option("kiss.serial.device") + elif transport == TRANSPORT_TCPKISS: + config.check_option("kiss.tcp") + config.check_option("kiss.tcp.host") + config.check_option("kiss.tcp.port") + + return True + return True + @staticmethod def transport(config): if config.get("kiss.serial.enabled", default=False): @@ -195,7 +230,26 @@ class ClientFactory: """Make sure at least one client is enabled.""" enabled = False for key in self._builders.keys(): - enabled |= self._builders[key].is_enabled(self.config) + try: + enabled |= self._builders[key].is_enabled(self.config) + except KeyError: + pass + + return enabled + + def is_client_configured(self): + enabled = False + for key in self._builders.keys(): + try: + enabled |= self._builders[key].is_configured(self.config) + except KeyError: + pass + except exception.MissingConfigOptionException as ex: + LOG.error(ex.message) + return False + except exception.ConfigOptionBogusDefaultException as ex: + LOG.error(ex.message) + return False return enabled diff --git a/aprsd/cmds/server.py b/aprsd/cmds/server.py index f271f86..b173bdb 100644 --- a/aprsd/cmds/server.py +++ b/aprsd/cmds/server.py @@ -70,6 +70,10 @@ def server(ctx, flush): LOG.error("No Clients are enabled in config.") sys.exit(-1) + if not client.factory.is_client_configured(): + LOG.error("APRS client is not properly configured in config file.") + sys.exit(-1) + # Creates the client object LOG.info("Creating client connection") client.factory.create().client diff --git a/aprsd/config.py b/aprsd/config.py index 054d5b7..5a2b636 100644 --- a/aprsd/config.py +++ b/aprsd/config.py @@ -7,7 +7,7 @@ import sys import click import yaml -from aprsd import utils +from aprsd import exception, utils home = str(Path.home()) @@ -63,6 +63,7 @@ DEFAULT_CONFIG_DICT = { "port": 14580, }, "kiss": { + "callsign": "NOCALL", "tcp": { "enabled": False, "host": "direwolf.ip.address", @@ -174,22 +175,15 @@ class Config(collections.UserDict): def check_option(self, path, default_fail=None): """Make sure the config option doesn't have default value.""" if not self.exists(path): - raise Exception( - "Option '{}' was not in config file".format( - path, - ), - ) + if type(path) is list: + path = ".".join(path) + raise exception.MissingConfigOption(path) val = self.get(path) if val == default_fail: # We have to fail and bail if the user hasn't edited # this config option. - raise Exception( - "Config file needs to be changed from provided" - " defaults for '{}'".format( - path, - ), - ) + raise exception.ConfigOptionBogusDefault(path, default_fail) def add_config_comments(raw_yaml): @@ -330,13 +324,7 @@ def parse_config(config_file): ) check_option( config, - "aprs.login", - default_fail=DEFAULT_CONFIG_DICT["aprs"]["login"], - ) - check_option( - config, - ["aprs", "password"], - default_fail=DEFAULT_CONFIG_DICT["aprs"]["password"], + ["aprsd"], ) # Ensure they change the admin password diff --git a/aprsd/exception.py b/aprsd/exception.py new file mode 100644 index 0000000..7de4bf7 --- /dev/null +++ b/aprsd/exception.py @@ -0,0 +1,13 @@ +class MissingConfigOptionException(Exception): + """Missing a config option.""" + def __init__(self, config_option): + self.message = f"Option '{config_option}' was not in config file" + + +class ConfigOptionBogusDefaultException(Exception): + """Missing a config option.""" + def __init__(self, config_option, default_fail): + self.message = ( + f"Config file option '{config_option}' needs to be " + f"changed from provided default of '{default_fail}'" + ) diff --git a/aprsd/log.py b/aprsd/log.py index 339737f..96135f9 100644 --- a/aprsd/log.py +++ b/aprsd/log.py @@ -33,10 +33,10 @@ def setup_logging(config, loglevel, quiet): rich_logging = True log_file = config["aprsd"].get("logfile", None) + log_format = config["aprsd"].get("logformat", aprsd_config.DEFAULT_LOG_FORMAT) + log_formatter = logging.Formatter(fmt=log_format, datefmt=date_format) if log_file: - log_format = config["aprsd"].get("logformat", aprsd_config.DEFAULT_LOG_FORMAT) - log_formatter = logging.Formatter(fmt=log_format, datefmt=date_format) fh = RotatingFileHandler(log_file, maxBytes=(10248576 * 5), backupCount=4) fh.setFormatter(log_formatter) LOG.addHandler(fh) diff --git a/aprsd/threads.py b/aprsd/threads.py index 5defdd6..c81275e 100644 --- a/aprsd/threads.py +++ b/aprsd/threads.py @@ -109,11 +109,17 @@ class KeepAliveThread(APRSDThread): current, peak = tracemalloc.get_traced_memory() stats_obj.set_memory(current) stats_obj.set_memory_peak(peak) + + try: + login = self.config["aprs"]["login"] + except KeyError: + login = self.config["ham"]["callsign"] + keepalive = ( "{} - Uptime {} RX:{} TX:{} Tracker:{} Msgs TX:{} RX:{} " "Last:{} Email: {} - RAM Current:{} Peak:{} Threads:{}" ).format( - self.config["aprs"]["login"], + login, utils.strfdelta(stats_obj.uptime), pl.total_recv, pl.total_tx, diff --git a/tox.ini b/tox.ini index 0fb906b..5a28948 100644 --- a/tox.ini +++ b/tox.ini @@ -61,7 +61,7 @@ commands = [flake8] max-line-length = 99 show-source = True -ignore = E713,E501,W503 +ignore = E713,E501,W503,N818 extend-ignore = E203,W503 extend-exclude = venv exclude = .venv,.git,.tox,dist,doc,.ropeproject