phi/src/phi/config.py

126 lines
3.7 KiB
Python

import os.path
import pkg_resources
import yaml
NAME = "phi"
DEFAULT_CONFIG = {
"core": {"listen": {"host": "localhost", "port": 8080}},
"ldap": {
"host": "localhost",
"port": 389,
"encryption": "TLSv1.2",
"ciphers": "HIGH",
"validate": True,
"ca_certs": pkg_resources.resource_filename(NAME, "openldap/cert.pem"),
"username": None,
"password": None,
"base_dn": None,
"attribute_id": "uid",
"attribute_mail": "mail",
},
"logging": {
"version": 1,
"formatters": {"default": {"format": "[%(name)s %(levelname)s] %(message)s"}},
"handlers": {
"console": {
"class": "logging.StreamHandler",
"formatter": "default",
"stream": "ext://sys.stdout",
},
"file": {
"class": "logging.FileHandler",
"formatter": "default",
"filename": "phi.log",
},
},
"loggers": {
"phi": {"level": "INFO", "handlers": ["console", "file"],},
"aiohttp": {"level": "INFO", "handlers": ["console", "file"],},
"ldap3": {"level": "WARNING", "handlers": ["console", "file"],},
},
},
}
DUMMY_CONFIG = {"core": {}, "ldap": {}, "logging": {}}
CONFIG_FILE = "config.yml"
CONFIG_PATHS = [
"./",
"~/.config/" + NAME + "/",
"/usr/local/etc/" + NAME + "/",
"/etc/" + NAME + "/",
]
CONFIG_FILES = [os.path.join(p, CONFIG_FILE) for p in CONFIG_PATHS]
def get_config(config_path=None):
"""Return the path of the found configuration file and its content
:param config_path: optional path to a config file.
:returns: (path, config)
:rtype: (str, dict)
"""
if config_path:
with open(config_path) as c:
config = yaml.safe_load(c)
return config_path, config
for f in CONFIG_FILES:
try:
with open(f, "r") as c:
config = yaml.safe_load(c)
return (f, config)
except FileNotFoundError:
# Skip to the next file.
# We only care if the file is preset but it's not
# accessible or if the file is not present at all
# in any of CONFIG_PATHS.
pass
return None, DUMMY_CONFIG
def merge_config(cli_config, file_config):
"""
Merge the cli-provided and file-provided config.
"""
return recursive_merge(cli_config, file_config)
def _init_with_shape_of(element):
if isinstance(element, dict):
return {}
elif isinstance(element, list):
return []
return None
def recursive_merge(main_config, aux_config):
def _recursive_merge(main, aux, default, key, _ret_config):
if isinstance(default, dict):
_sub_conf = {}
for k, v in default.items():
_main = main[k] if k in main else _init_with_shape_of(v)
_aux = aux[k] if k in aux else _init_with_shape_of(v)
_recursive_merge(_main, _aux, v, k, _sub_conf)
_ret_config[key] = _sub_conf
elif isinstance(default, list):
_main = main.copy()
if aux is not None:
_main.extend(aux)
_ret_config[key] = list(set(_main))
elif isinstance(default, bool):
_ret_config[key] = default and aux and main
else:
if main is not None:
_ret_config[key] = main
elif aux is not None:
_ret_config[key] = aux
else:
_ret_config[key] = default
_config = {}
_recursive_merge(main_config, aux_config, DEFAULT_CONFIG, "ROOT", _config)
return _config["ROOT"]