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
This commit is contained in:
Hemna 2022-02-21 16:04:33 -05:00
parent e739441268
commit 1c052a63c0
8 changed files with 93 additions and 27 deletions

View File

@ -55,7 +55,8 @@ def process_standard_options(f: F) -> F:
ctx.obj["quiet"] = kwargs["quiet"] ctx.obj["quiet"] = kwargs["quiet"]
ctx.obj["config"] = aprsd_config.parse_config(kwargs["config_file"]) ctx.obj["config"] = aprsd_config.parse_config(kwargs["config_file"])
log.setup_logging( log.setup_logging(
ctx.obj["config"], ctx.obj["loglevel"], ctx.obj["config"],
ctx.obj["loglevel"],
ctx.obj["quiet"], ctx.obj["quiet"],
) )

View File

@ -5,7 +5,8 @@ import time
import aprslib import aprslib
from aprslib.exceptions import LoginError 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 from aprsd.clients import aprsis, kiss
@ -76,7 +77,21 @@ class APRSISClient(Client):
@staticmethod @staticmethod
def is_enabled(config): def is_enabled(config):
# Defaults to True if the enabled flag is non existent # 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 @staticmethod
def transport(config): def transport(config):
@ -133,6 +148,26 @@ class KISSClient(Client):
return False 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 @staticmethod
def transport(config): def transport(config):
if config.get("kiss.serial.enabled", default=False): if config.get("kiss.serial.enabled", default=False):
@ -195,7 +230,26 @@ class ClientFactory:
"""Make sure at least one client is enabled.""" """Make sure at least one client is enabled."""
enabled = False enabled = False
for key in self._builders.keys(): 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 return enabled

View File

@ -70,6 +70,10 @@ def server(ctx, flush):
LOG.error("No Clients are enabled in config.") LOG.error("No Clients are enabled in config.")
sys.exit(-1) 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 # Creates the client object
LOG.info("Creating client connection") LOG.info("Creating client connection")
client.factory.create().client client.factory.create().client

View File

@ -7,7 +7,7 @@ import sys
import click import click
import yaml import yaml
from aprsd import utils from aprsd import exception, utils
home = str(Path.home()) home = str(Path.home())
@ -63,6 +63,7 @@ DEFAULT_CONFIG_DICT = {
"port": 14580, "port": 14580,
}, },
"kiss": { "kiss": {
"callsign": "NOCALL",
"tcp": { "tcp": {
"enabled": False, "enabled": False,
"host": "direwolf.ip.address", "host": "direwolf.ip.address",
@ -174,22 +175,15 @@ class Config(collections.UserDict):
def check_option(self, path, default_fail=None): def check_option(self, path, default_fail=None):
"""Make sure the config option doesn't have default value.""" """Make sure the config option doesn't have default value."""
if not self.exists(path): if not self.exists(path):
raise Exception( if type(path) is list:
"Option '{}' was not in config file".format( path = ".".join(path)
path, raise exception.MissingConfigOption(path)
),
)
val = self.get(path) val = self.get(path)
if val == default_fail: if val == default_fail:
# We have to fail and bail if the user hasn't edited # We have to fail and bail if the user hasn't edited
# this config option. # this config option.
raise Exception( raise exception.ConfigOptionBogusDefault(path, default_fail)
"Config file needs to be changed from provided"
" defaults for '{}'".format(
path,
),
)
def add_config_comments(raw_yaml): def add_config_comments(raw_yaml):
@ -330,13 +324,7 @@ def parse_config(config_file):
) )
check_option( check_option(
config, config,
"aprs.login", ["aprsd"],
default_fail=DEFAULT_CONFIG_DICT["aprs"]["login"],
)
check_option(
config,
["aprs", "password"],
default_fail=DEFAULT_CONFIG_DICT["aprs"]["password"],
) )
# Ensure they change the admin password # Ensure they change the admin password

13
aprsd/exception.py Normal file
View File

@ -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}'"
)

View File

@ -33,10 +33,10 @@ def setup_logging(config, loglevel, quiet):
rich_logging = True rich_logging = True
log_file = config["aprsd"].get("logfile", None) 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: 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 = RotatingFileHandler(log_file, maxBytes=(10248576 * 5), backupCount=4)
fh.setFormatter(log_formatter) fh.setFormatter(log_formatter)
LOG.addHandler(fh) LOG.addHandler(fh)

View File

@ -109,11 +109,17 @@ class KeepAliveThread(APRSDThread):
current, peak = tracemalloc.get_traced_memory() current, peak = tracemalloc.get_traced_memory()
stats_obj.set_memory(current) stats_obj.set_memory(current)
stats_obj.set_memory_peak(peak) stats_obj.set_memory_peak(peak)
try:
login = self.config["aprs"]["login"]
except KeyError:
login = self.config["ham"]["callsign"]
keepalive = ( keepalive = (
"{} - Uptime {} RX:{} TX:{} Tracker:{} Msgs TX:{} RX:{} " "{} - Uptime {} RX:{} TX:{} Tracker:{} Msgs TX:{} RX:{} "
"Last:{} Email: {} - RAM Current:{} Peak:{} Threads:{}" "Last:{} Email: {} - RAM Current:{} Peak:{} Threads:{}"
).format( ).format(
self.config["aprs"]["login"], login,
utils.strfdelta(stats_obj.uptime), utils.strfdelta(stats_obj.uptime),
pl.total_recv, pl.total_recv,
pl.total_tx, pl.total_tx,

View File

@ -61,7 +61,7 @@ commands =
[flake8] [flake8]
max-line-length = 99 max-line-length = 99
show-source = True show-source = True
ignore = E713,E501,W503 ignore = E713,E501,W503,N818
extend-ignore = E203,W503 extend-ignore = E203,W503
extend-exclude = venv extend-exclude = venv
exclude = .venv,.git,.tox,dist,doc,.ropeproject exclude = .venv,.git,.tox,dist,doc,.ropeproject