From e8fcf3acd43e8064580c4e1012351ad5ca644c46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Zimmermann?= <101292599+ekneg54@users.noreply.github.com> Date: Fri, 21 Jun 2024 09:05:38 +0200 Subject: [PATCH] configuration overwrites with default values (#613) * use last non default value instead of using the last falsy value which asumes, that all attributes have a falsy default we return the last non default value instead. * update changelog --- CHANGELOG.md | 3 ++ logprep/util/configuration.py | 13 +++++-- tests/unit/util/test_configuration.py | 50 +++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6960591ea..2305d06c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,11 +9,14 @@ This release limits the maximum python version to `3.12.3` because of the issue ### Breaking ### Features ### Improvements + * a result object was added which is returned by every processor * includes generated extra_data, warnings and errors ### Bugfix +* fixes a bug where it could happen that a config value could be overwritten by a default in a later configuration in a multi source config scenario + ## 12.0.0 ### Breaking diff --git a/logprep/util/configuration.py b/logprep/util/configuration.py index 7bd3bcdf5..d5c8423bf 100644 --- a/logprep/util/configuration.py +++ b/logprep/util/configuration.py @@ -712,7 +712,7 @@ def _set_attributes_from_configs(self) -> None: setattr( self, attribute.name, - self._get_last_non_falsy_value(self._configs, attribute.name), + self._get_last_non_default_value(self._configs, attribute.name), ) versions = (config.version for config in self._configs if config.version) self.version = ", ".join(versions) @@ -790,11 +790,18 @@ def _resolve_directories(rule_sources: list) -> list: return resolved_sources @staticmethod - def _get_last_non_falsy_value(configs: list["Configuration"], attribute: str) -> Any: + def _get_last_non_default_value(configs: list["Configuration"], attribute: str) -> Any: if configs: + config = configs[0] + attrs_attribute = [attr for attr in config.__attrs_attrs__ if attr.name == attribute][0] + default_for_attribute = ( + attrs_attribute.default.factory() + if hasattr(attrs_attribute.default, "factory") + else attrs_attribute.default + ) values = [getattr(config, attribute) for config in configs] for value in reversed(values): - if value: + if value != default_for_attribute: return value return values[-1] return getattr(Configuration(), attribute) diff --git a/tests/unit/util/test_configuration.py b/tests/unit/util/test_configuration.py index 58456f912..3c067d58a 100644 --- a/tests/unit/util/test_configuration.py +++ b/tests/unit/util/test_configuration.py @@ -1215,6 +1215,56 @@ def test_verify_credentials_file_raises_for_unexpected_key(self, config_path, tm ): _ = Configuration.from_sources([str(config_path)]) + def test_no_config_parameter_is_overwritten_with_a_default(self, tmp_path): + prometheus_multiproc_dir: Path = tmp_path / "prometheus_multiproc_dir" + prometheus_multiproc_dir.mkdir() + exporter_config = tmp_path / "exporter-config" + exporter_config.write_text( + """ +metrics: + enabled: true + port: 8000 +""" + ) + input_config = tmp_path / "input-config" + input_config.write_text( + """ +input: + stdin: + type: file_input + logfile_path: /proc/1/fdinfo/0 + start: end + watch_file: true + interval: 1 +""" + ) + + output_config = tmp_path / "output-config" + output_config.write_text( + """ +output: + console: + type: console_output +""" + ) + with mock.patch.dict( + "os.environ", {"PROMETHEUS_MULTIPROC_DIR": str(prometheus_multiproc_dir)} + ): + config1 = Configuration.from_sources( + [str(input_config), str(output_config), str(exporter_config)] + ) + assert config1.metrics.enabled + + config1 = Configuration.from_sources( + [str(exporter_config), str(input_config), str(output_config)] + ) + assert config1.metrics.enabled + + config1 = Configuration.from_sources( + [str(input_config), str(exporter_config), str(output_config)] + ) + assert config1.metrics.enabled + def test_verify_calls_processor_setup(self, config_path): config = Configuration.from_sources([str(config_path)]) with mock.patch("logprep.abc.processor.Processor.setup") as mocked_setup: