generalconfig: streamlined config discovery

determine generalconfig file location in order:
  - command line argument
  - environment variable
  - git location (../cfg)
  - local location (cwd)
  - global location (/etc/frappy)

Change-Id: Ie34bcbd5188837075ee7bb7d5029d676ae72378e
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34839
Reviewed-by: Bjoern Pedersen <bjoern.pedersen@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
This commit is contained in:
Alexander Zaft 2024-10-18 13:23:13 +02:00 committed by Markus Zolliker
parent 261121297b
commit 632db924eb
2 changed files with 57 additions and 36 deletions

View File

@ -35,7 +35,15 @@ from frappy.server import Server
def parseArgv(argv):
parser = argparse.ArgumentParser(description="Manage a SECoP server")
parser = argparse.ArgumentParser(
description="Manage a SECoP server",
epilog="""The server needs some configuration, by default from the
generalConfig.cfg file. the keys confdir, logdir and piddir have to
be set.
Alternatively, one can set the environment variables FRAPPY_CONFDIR
FRAPPY_LOGDIR and FRAPPY_PIDDIR to set the required values.
"""
)
loggroup = parser.add_mutually_exclusive_group()
loggroup.add_argument("-v", "--verbose",
help="Output lots of diagnostic information",

View File

@ -37,6 +37,10 @@ from pathlib import Path
SECoP_DEFAULT_PORT = 10767
_gcfg_help = """
"""
class GeneralConfig:
"""generalConfig holds server configuration items
@ -57,11 +61,12 @@ class GeneralConfig:
:param configfile: if present, keys and values from the [FRAPPY] section are read
default values for 'piddir', 'logdir' and 'confdir' are guessed from the
location of this source file and from sys.executable.
if configfile is not given, the general config file is determined by
the env. variable FRAPPY_CONFIG_FILE or <confdir>/generalConfig.cfg is used
The following locations are searched for the generalConfig.cfg file.
- command line argument
- environment variable FRAPPY_CONFIG_FILE
- git location (../cfg)
- local location (cwd)
- global location (/etc/frappy)
if a configfile is given, the values from the FRAPPY section are
overriding above defaults
@ -69,37 +74,12 @@ class GeneralConfig:
finally, the env. variables FRAPPY_PIDDIR, FRAPPY_LOGDIR and FRAPPY_CONFDIR
are overriding these values when given
"""
configfile = self._get_file_location(configfile)
cfg = {}
mandatory = 'piddir', 'logdir', 'confdir'
repodir = Path(__file__).parents[2].expanduser().resolve()
# create default paths
if (Path(sys.executable).suffix == ".exe"
and not Path(sys.executable).name.startswith('python')):
# special MS windows environment
confdir = Path('./')
self.update_defaults(piddir=Path('./'), logdir=Path('./log'))
elif path.exists(path.join(repodir, 'cfg')):
# running from git repo
confdir = repodir / 'cfg'
# take logdir and piddir from <repodir>/cfg/generalConfig.cfg
else:
# running on installed system (typically with systemd)
self.update_defaults(
piddir=Path('/var/run/frappy'),
logdir=Path('/var/log'),
)
confdir = Path('/etc/frappy')
self.set_default('confdir', confdir)
if configfile is None:
configfile = environ.get('FRAPPY_CONFIG_FILE')
if configfile:
configfile = Path(configfile).expanduser()
if not configfile.exists():
raise FileNotFoundError(configfile)
else:
configfile = confdir / 'generalConfig.cfg'
if not configfile.exists():
configfile = None
if configfile:
parser = ConfigParser()
parser.optionxform = str
@ -113,6 +93,7 @@ class GeneralConfig:
cfg[key] = ':'.join(path.expanduser(v) for v in value.split(':'))
if cfg.get('confdir') is None:
cfg['confdir'] = configfile.parent
# environment variables will overwrite the config file
for key in mandatory:
env = environ.get(f'FRAPPY_{key.upper()}')
if env is not None:
@ -127,14 +108,46 @@ class GeneralConfig:
if missing_keys:
if configfile:
raise KeyError(f"missing value for {' and '.join(missing_keys)} in {configfile}")
raise KeyError('missing %s'
% ' and '.join('FRAPPY_%s' % k.upper() for k in missing_keys))
if len(missing_keys) < 3:
# user specified at least one env variable already
missing = ' (missing %s)' % ', '.join('FRAPPY_%s' % k.upper() for k in missing_keys)
else:
missing = ''
raise FileNotFoundError(
'Could not determine config file location for the general frappy config. '
f'Provide a config file or all required environment variables{missing}. '
'For more information, see frappy-server --help.'
)
if 'confdir' in cfg and isinstance(cfg['confdir'], Path):
cfg['confdir'] = [cfg['confdir']]
# this is not customizable
cfg['basedir'] = repodir
self._config = cfg
def _get_file_location(self, configfile):
"""Determining the defaultConfig.cfg location as documented in init()"""
# given as command line arg
if configfile and Path(configfile).exists():
return configfile
# if not given as argument, check different sources
# env variable
fromenv = environ.get('FRAPPY_CONFIG_FILE')
if fromenv and Path(fromenv).exists():
return fromenv
# from ../cfg (there if running from checkout)
repodir = Path(__file__).parents[2].expanduser().resolve()
if (repodir / 'cfg' / 'generalConfig.cfg').exists():
return repodir / 'cfg' / 'generalConfig.cfg'
localfile = Path.cwd() / 'generalConfig.cfg'
if localfile.exists():
return localfile
# TODO: leave this hardcoded?
globalfile = Path('/etc/frappy/generalConfig.cfg')
if globalfile.exists():
return globalfile
return None
def __getitem__(self, key):
"""access for keys known to exist