95976f4cf4
Before, the main_config (e.g. 'configuration.py' or 'ldap_config.py') were loaded twice. The first load was hard-coded and correct. The second load was during the discovery phase for dynamic configurations. This has now been fixed. During the discovery for dynamic configurations, the main_config file is now excluded. Thanks @tobiasge for discovering this bug.
85 lines
2.4 KiB
Python
85 lines
2.4 KiB
Python
## Generic Parts
|
|
# These functions are providing the functionality to load
|
|
# arbitrary configuration files.
|
|
#
|
|
# They can be imported by other code (see `ldap_config.py` for an example).
|
|
|
|
import importlib.util
|
|
import sys
|
|
from os import scandir
|
|
from os.path import abspath, isfile
|
|
|
|
|
|
def _filename(f):
|
|
return f.name
|
|
|
|
|
|
def _import(module_name, path, loaded_configurations):
|
|
spec = importlib.util.spec_from_file_location("", path)
|
|
module = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(module)
|
|
sys.modules[module_name] = module
|
|
|
|
loaded_configurations.insert(0, module)
|
|
|
|
print(f"🧬 loaded config '{path}'")
|
|
|
|
|
|
def read_configurations(config_module, config_dir, main_config):
|
|
loaded_configurations = []
|
|
|
|
main_config_path = abspath(f"{config_dir}/{main_config}.py")
|
|
if isfile(main_config_path):
|
|
_import(f"{config_module}.{main_config}", main_config_path, loaded_configurations)
|
|
else:
|
|
print(f"⚠️ Main configuration '{main_config_path}' not found.")
|
|
|
|
with scandir(config_dir) as it:
|
|
for f in sorted(it, key=_filename):
|
|
if not f.is_file():
|
|
continue
|
|
|
|
if f.name.startswith("__"):
|
|
continue
|
|
|
|
if not f.name.endswith(".py"):
|
|
continue
|
|
|
|
if f.name == f"{main_config}.py":
|
|
continue
|
|
|
|
if f.name == f"{config_dir}.py":
|
|
continue
|
|
|
|
module_name = f"{config_module}.{f.name[:-len('.py')]}".replace(".", "_")
|
|
_import(module_name, f.path, loaded_configurations)
|
|
|
|
if len(loaded_configurations) == 0:
|
|
print(f"‼️ No configuration files found in '{config_dir}'.")
|
|
raise ImportError(f"No configuration files found in '{config_dir}'.")
|
|
|
|
return loaded_configurations
|
|
|
|
|
|
## Specific Parts
|
|
# This section's code actually loads the various configuration files
|
|
# into the module with the given name.
|
|
# It contains the logic to resolve arbitrary configuration options by
|
|
# levaraging dynamic programming using `__getattr__`.
|
|
|
|
|
|
_loaded_configurations = read_configurations(
|
|
config_dir="/etc/netbox/config/",
|
|
config_module="netbox.configuration",
|
|
main_config="configuration",
|
|
)
|
|
|
|
|
|
def __getattr__(name):
|
|
for config in _loaded_configurations:
|
|
try:
|
|
return getattr(config, name)
|
|
except:
|
|
pass
|
|
raise AttributeError
|