From a7a45bf8c3af18f194194e0f60c8a4b923f20828 Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Sun, 10 May 2026 17:40:29 -0400 Subject: [PATCH] fix: support plugin-level enabled: false in threshold config Setting enabled: false at the plugin level (e.g. memory_monitor: {enabled: false}) was silently ignored because the non-dict value was skipped by the metric parser, leaving THRESHOLD_DEFAULTS entries active. - _parse_plugin_thresholds: detect plugin-level enabled/enable flag and delete all matching entries from target_dict (covers legacy and default config paths) - _parse_multi_config named configs: inject disabled stubs from effective_defaults into raw_overrides so the merge step overwrites inherited defaults - Accept 'enable' as a tolerated alias for 'enabled' in both code paths Co-Authored-By: Claude Sonnet 4.6 --- hbd/server/threshold.py | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/hbd/server/threshold.py b/hbd/server/threshold.py index 3572e19..80b9d80 100644 --- a/hbd/server/threshold.py +++ b/hbd/server/threshold.py @@ -492,7 +492,27 @@ class ThresholdChecker: raw_overrides: Dict[str, ThresholdConfig] = {} thresholds_config = config_data["thresholds"] for plugin_name, plugin_thresholds in thresholds_config.items(): - if isinstance(plugin_thresholds, dict): + if not isinstance(plugin_thresholds, dict): + continue + plugin_enabled = plugin_thresholds.get('enabled', plugin_thresholds.get('enable', True)) + if not plugin_enabled: + # raw_overrides is empty at this point so there's nothing to delete. + # Instead, inject disabled stubs for every matching effective_default so + # the merge step overwrites the inherited defaults. + for key, tc in effective_defaults.items(): + if key.startswith(f"{plugin_name}."): + raw_overrides[key] = ThresholdConfig( + metric_path=key, + warning=tc.warning, + critical=tc.critical, + operator=tc.operator.value, + enabled=False, + ) + logger.info( + "Plugin-level disable in config '%s': disabled all thresholds for %s", + config_name, plugin_name, + ) + else: self._parse_plugin_thresholds(plugin_name, plugin_thresholds, target_dict=raw_overrides) self.threshold_raw_configs[config_name] = raw_overrides @@ -570,7 +590,16 @@ class ThresholdChecker: if plugin_name == "rtt": self._parse_rtt_thresholds(thresholds, target_dict) return - + + # Plugin-level enabled: false (also accept 'enable' as a common typo) removes all + # thresholds for this plugin — e.g. memory_monitor: {enabled: false}. + plugin_enabled = thresholds.get('enabled', thresholds.get('enable', True)) + if not plugin_enabled: + for key in [k for k in target_dict if k.startswith(f"{plugin_name}.")]: + del target_dict[key] + logger.info("Plugin-level disable: removed all thresholds for %s", plugin_name) + return + for metric_name, threshold_config in thresholds.items(): if not isinstance(threshold_config, dict): continue