diff --git a/atst/app.py b/atst/app.py index 1b60f64c..e9daabd6 100644 --- a/atst/app.py +++ b/atst/app.py @@ -200,23 +200,21 @@ def make_config(direct_config=None): ENV_CONFIG_FILENAME = os.path.join( os.path.dirname(__file__), "../config/", "{}.ini".format(ENV.lower()) ) - OVERRIDE_CONFIG_FILENAME = os.getenv("OVERRIDE_CONFIG_FULLPATH") + OVERRIDE_CONFIG_DIRECTORY = os.getenv("OVERRIDE_CONFIG_DIRECTORY") config = ConfigParser(allow_no_value=True) config.optionxform = str config_files = [BASE_CONFIG_FILENAME, ENV_CONFIG_FILENAME] - if OVERRIDE_CONFIG_FILENAME: - config_files.append(OVERRIDE_CONFIG_FILENAME) # ENV_CONFIG will override values in BASE_CONFIG. config.read(config_files) + if OVERRIDE_CONFIG_DIRECTORY: + apply_config_from_directory(OVERRIDE_CONFIG_DIRECTORY, config) + # Check for ENV variables as a final source of overrides - for confsetting in config.options("default"): - env_override = os.getenv(confsetting.upper()) - if env_override: - config.set("default", confsetting, env_override) + apply_config_from_environment(config) # override if a dictionary of options has been given if direct_config: @@ -244,6 +242,36 @@ def make_config(direct_config=None): return map_config(config) +def apply_config_from_directory(config_dir, config, section="default"): + """ + Loop files in a directory, check if the names correspond to + known config values, and apply the file contents as the value + for that setting if they do. + """ + for confsetting in os.listdir(config_dir): + if confsetting in config.options(section): + full_path = os.path.join(config_dir, confsetting) + with open(full_path, "r") as conf_file: + config.set(section, confsetting, conf_file.read().strip()) + + return config + + +def apply_config_from_environment(config, section="default"): + """ + Loops all the configuration settins in a given section of a + config object and checks whether those settings also exist as + environment variables. If so, it applies the environment + variables value as the new configuration setting value. + """ + for confsetting in config.options(section): + env_override = os.getenv(confsetting.upper()) + if env_override: + config.set(section, confsetting, env_override) + + return config + + def make_redis(app, config): r = redis.Redis.from_url(config["REDIS_URI"]) app.redis = r diff --git a/tests/test_app.py b/tests/test_app.py index 222f4a4f..937a15e2 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -1,8 +1,13 @@ import os +from configparser import ConfigParser import pytest -from atst.app import make_crl_validator +from atst.app import ( + make_crl_validator, + apply_config_from_directory, + apply_config_from_environment, +) @pytest.fixture @@ -22,3 +27,43 @@ def test_make_crl_validator_creates_crl_dir(app, tmpdir, replace_crl_dir_config) replace_crl_dir_config(crl_dir) make_crl_validator(app) assert os.path.isdir(crl_dir) + + +@pytest.fixture +def config_object(): + config = ConfigParser() + config.optionxform = str + config.read_string("[default]\nFOO=BALONEY") + return config + + +def test_apply_config_from_directory(tmpdir, config_object): + config_setting = tmpdir.join("FOO") + with open(config_setting, "w") as conf_file: + conf_file.write("MAYO") + + apply_config_from_directory(tmpdir, config_object) + assert config_object.get("default", "FOO") == "MAYO" + + +def test_apply_config_from_directory_skips_unknown_settings(tmpdir, config_object): + config_setting = tmpdir.join("FLARF") + with open(config_setting, "w") as conf_file: + conf_file.write("MAYO") + + apply_config_from_directory(tmpdir, config_object) + assert "FLARF" not in config_object.options("default") + + +def test_apply_config_from_environment(monkeypatch, config_object): + monkeypatch.setenv("FOO", "MAYO") + apply_config_from_environment(config_object) + assert config_object.get("default", "FOO") == "MAYO" + + +def test_apply_config_from_environment_skips_unknown_settings( + monkeypatch, config_object +): + monkeypatch.setenv("FLARF", "MAYO") + apply_config_from_environment(config_object) + assert "FLARF" not in config_object.options("default")