diff --git a/bin/check_mk b/bin/check_mk index 3e2204c4175..c880a082f26 100755 --- a/bin/check_mk +++ b/bin/check_mk @@ -45,6 +45,10 @@ from cmk.utils.log import console import cmk.base.utils from cmk.base import config, profiling +from cmk.base.api.agent_based.register import ( + extract_known_discovery_rulesets, + get_previously_loaded_plugins, +) from cmk.base.modes import modes from cmk import trace @@ -144,7 +148,7 @@ try: # certain operation modes that does not need them and should not be harmed # by a broken configuration if mode_name not in modes.non_config_options(): - config.load() + config.load(extract_known_discovery_rulesets(get_previously_loaded_plugins())) done, exit_status = False, 0 if mode_name is not None and mode_args is not None: diff --git a/bin/cmk-validate-config b/bin/cmk-validate-config index 9806c1fff0d..03f6677c1f4 100755 --- a/bin/cmk-validate-config +++ b/bin/cmk-validate-config @@ -9,6 +9,10 @@ from cmk.utils import paths from cmk.utils.redis import disable_redis from cmk.base import config +from cmk.base.api.agent_based.register import ( + extract_known_discovery_rulesets, + get_previously_loaded_plugins, +) from cmk.gui import main_modules from cmk.gui.utils.script_helpers import gui_context @@ -24,9 +28,10 @@ def main() -> int: local_checks_dir=paths.local_checks_dir, checks_dir=paths.checks_dir, ) + plugins = get_previously_loaded_plugins() # Watch out: always load the plugins before loading the config. # The validation step will not be executed otherwise. - config.load() + config.load(discovery_rulesets=extract_known_discovery_rulesets(plugins)) result = validate_mk_files() diff --git a/cmk/base/api/agent_based/register/__init__.py b/cmk/base/api/agent_based/register/__init__.py index a846b8e58c0..e45e512494f 100644 --- a/cmk/base/api/agent_based/register/__init__.py +++ b/cmk/base/api/agent_based/register/__init__.py @@ -5,11 +5,9 @@ from ._config import ( AgentBasedPlugins, - get_discovery_ruleset, - get_host_label_ruleset, + extract_known_discovery_rulesets, + get_previously_collected_discovery_rules, get_previously_loaded_plugins, - is_stored_ruleset, - iter_all_discovery_rulesets, set_discovery_ruleset, ) from ._discover import load_all_plugins, load_selected_plugins @@ -18,13 +16,11 @@ __all__ = [ "AgentBasedPlugins", + "extract_known_discovery_rulesets", "get_check_plugin", - "get_discovery_ruleset", - "get_host_label_ruleset", "get_previously_loaded_plugins", + "get_previously_collected_discovery_rules", "filter_relevant_raw_sections", - "is_stored_ruleset", - "iter_all_discovery_rulesets", "load_all_plugins", "load_selected_plugins", "sections_needing_redetection", diff --git a/cmk/base/api/agent_based/register/_config.py b/cmk/base/api/agent_based/register/_config.py index 1c08c8a6263..49927303ec4 100644 --- a/cmk/base/api/agent_based/register/_config.py +++ b/cmk/base/api/agent_based/register/_config.py @@ -3,7 +3,7 @@ # This file is part of Checkmk (https://checkmk.com). It is subject to the terms and # conditions defined in the file COPYING, which is part of this source code package. -from collections.abc import Iterable, Mapping, Sequence +from collections.abc import Collection, Mapping, Sequence from dataclasses import dataclass from cmk.utils.rulesets import RuleSetName @@ -56,12 +56,24 @@ def get_previously_loaded_plugins() -> AgentBasedPlugins: ) -def add_check_plugin(check_plugin: CheckPlugin) -> None: - registered_check_plugins[check_plugin.name] = check_plugin +def extract_known_discovery_rulesets(plugins: AgentBasedPlugins) -> Collection[RuleSetName]: + return { + r + for r in ( + *(p.discovery_ruleset_name for p in plugins.check_plugins.values()), + *(p.host_label_ruleset_name for p in plugins.agent_sections.values()), + *(p.host_label_ruleset_name for p in plugins.snmp_sections.values()), + ) + if r is not None + } -def add_discovery_ruleset(ruleset_name: RuleSetName) -> None: - stored_rulesets.setdefault(ruleset_name, []) +def get_previously_collected_discovery_rules() -> Mapping[RuleSetName, Sequence[RuleSpec]]: + return stored_rulesets + + +def add_check_plugin(check_plugin: CheckPlugin) -> None: + registered_check_plugins[check_plugin.name] = check_plugin def add_inventory_plugin(inventory_plugin: InventoryPlugin) -> None: @@ -75,16 +87,6 @@ def add_section_plugin(section_plugin: SectionPlugin) -> None: registered_snmp_sections[section_plugin.name] = section_plugin -def get_discovery_ruleset(ruleset_name: RuleSetName) -> Sequence[RuleSpec]: - """Returns all rulesets of a given name""" - return stored_rulesets.get(ruleset_name, []) - - -def get_host_label_ruleset(ruleset_name: RuleSetName) -> Sequence[RuleSpec]: - """Returns all rulesets of a given name""" - return stored_rulesets.get(ruleset_name, []) - - def get_inventory_plugin(plugin_name: InventoryPluginName) -> InventoryPlugin | None: """Returns the registered inventory plug-in""" return registered_inventory_plugins.get(plugin_name) @@ -102,14 +104,6 @@ def is_registered_section_plugin(section_name: SectionName) -> bool: return section_name in registered_snmp_sections or section_name in registered_agent_sections -def is_stored_ruleset(ruleset_name: RuleSetName) -> bool: - return ruleset_name in stored_rulesets - - -def iter_all_discovery_rulesets() -> Iterable[RuleSetName]: - return stored_rulesets.keys() - - def set_discovery_ruleset( ruleset_name: RuleSetName, rules: Sequence[RuleSpec], diff --git a/cmk/base/api/agent_based/register/_discover.py b/cmk/base/api/agent_based/register/_discover.py index a2664b1d69a..61b20ee461f 100644 --- a/cmk/base/api/agent_based/register/_discover.py +++ b/cmk/base/api/agent_based/register/_discover.py @@ -31,7 +31,6 @@ from ._config import ( add_check_plugin, - add_discovery_ruleset, add_inventory_plugin, add_section_plugin, get_inventory_plugin, @@ -129,8 +128,6 @@ def register_agent_section( raise ValueError(f"duplicate section definition: {section_plugin.name}") add_section_plugin(section_plugin) - if section_plugin.host_label_ruleset_name is not None: - add_discovery_ruleset(section_plugin.host_label_ruleset_name) def register_snmp_section( @@ -150,8 +147,6 @@ def register_snmp_section( raise ValueError(f"duplicate section definition: {section_plugin.name}") add_section_plugin(section_plugin) - if section_plugin.host_label_ruleset_name is not None: - add_discovery_ruleset(section_plugin.host_label_ruleset_name) def register_check_plugin(check: CheckPlugin, location: PluginLocation) -> None: @@ -185,8 +180,6 @@ def register_check_plugin(check: CheckPlugin, location: PluginLocation) -> None: raise ValueError(f"duplicate check plug-in definition: {plugin.name}") add_check_plugin(plugin) - if plugin.discovery_ruleset_name is not None: - add_discovery_ruleset(plugin.discovery_ruleset_name) def register_inventory_plugin(inventory: InventoryPlugin, location: PluginLocation) -> None: diff --git a/cmk/base/automation_helper/_app.py b/cmk/base/automation_helper/_app.py index ac645c2cbd9..35faa07aa11 100644 --- a/cmk/base/automation_helper/_app.py +++ b/cmk/base/automation_helper/_app.py @@ -27,6 +27,10 @@ from cmk.automations.results import ABCAutomationResult from cmk.base import config +from cmk.base.api.agent_based.register import ( + extract_known_discovery_rulesets, + get_previously_loaded_plugins, +) from cmk.base.automations import AutomationError from ._cache import Cache, CacheError @@ -41,7 +45,9 @@ class HealthCheckResponse(BaseModel, frozen=True): def reload_automation_config() -> None: cache_manager.clear() - config.load(validate_hosts=False) + plugins = get_previously_loaded_plugins() + discovery_rulesets = extract_known_discovery_rulesets(plugins) + config.load(discovery_rulesets, validate_hosts=False) def clear_caches_before_each_call() -> None: @@ -93,6 +99,7 @@ async def lifespan(_: FastAPI) -> AsyncGenerator[None, None]: local_checks_dir=paths.local_checks_dir, checks_dir=paths.checks_dir ) tty.reinit() + reload_config() reloader_task = asyncio.create_task( diff --git a/cmk/base/automations/__init__.py b/cmk/base/automations/__init__.py index ca4817d635f..c2f2d0ca443 100644 --- a/cmk/base/automations/__init__.py +++ b/cmk/base/automations/__init__.py @@ -22,6 +22,10 @@ from cmk.automations.results import ABCAutomationResult from cmk.base import config, profiling +from cmk.base.api.agent_based.register import ( + extract_known_discovery_rulesets, + get_previously_loaded_plugins, +) from cmk import trace @@ -120,8 +124,11 @@ def _execute( ) if not called_from_automation_helper and automation.needs_config: + discovery_rulesets = extract_known_discovery_rulesets( + get_previously_loaded_plugins() + ) with tracer.span("load_config"): - config.load(validate_hosts=False) + config.load(discovery_rulesets, validate_hosts=False) with tracer.span(f"execute_automation[{cmd}]"): result = automation.execute(args, called_from_automation_helper) diff --git a/cmk/base/automations/check_mk.py b/cmk/base/automations/check_mk.py index 93d60c96ed2..b4272ad4bb8 100644 --- a/cmk/base/automations/check_mk.py +++ b/cmk/base/automations/check_mk.py @@ -287,6 +287,7 @@ def execute( config_cache = config.get_config_cache() plugins = agent_based_register.get_previously_loaded_plugins() + discovery_rules = agent_based_register.get_previously_collected_discovery_rules() ruleset_matcher = config_cache.ruleset_matcher autochecks_config = config.AutochecksConfigurer(config_cache, plugins.check_plugins) @@ -354,9 +355,12 @@ def section_error_handling( host_label_plugins=HostLabelPluginMapper( ruleset_matcher=ruleset_matcher, sections={**plugins.agent_sections, **plugins.snmp_sections}, + discovery_rules=discovery_rules, ), plugins=DiscoveryPluginMapper( - ruleset_matcher=ruleset_matcher, check_plugins=plugins.check_plugins + ruleset_matcher=ruleset_matcher, + check_plugins=plugins.check_plugins, + discovery_rules=discovery_rules, ), autochecks_config=autochecks_config, settings=settings, @@ -644,6 +648,7 @@ def _execute_discovery( config_cache = config.get_config_cache() hosts_config = config.make_hosts_config() plugins = agent_based_register.get_previously_loaded_plugins() + discovery_rules = agent_based_register.get_previously_collected_discovery_rules() ruleset_matcher = config_cache.ruleset_matcher autochecks_config = config.AutochecksConfigurer(config_cache, plugins.check_plugins) parser = CMKParser( @@ -691,13 +696,16 @@ def _execute_discovery( host_label_plugins=HostLabelPluginMapper( ruleset_matcher=ruleset_matcher, sections={**plugins.agent_sections, **plugins.snmp_sections}, + discovery_rules=discovery_rules, ), check_plugins=check_plugins, compute_check_parameters=_make_compute_check_parameters_of_autocheck( ruleset_matcher, plugins.check_plugins ), discovery_plugins=DiscoveryPluginMapper( - ruleset_matcher=ruleset_matcher, check_plugins=plugins.check_plugins + ruleset_matcher=ruleset_matcher, + check_plugins=plugins.check_plugins, + discovery_rules=discovery_rules, ), autochecks_config=autochecks_config, enforced_services=config_cache.enforced_services_table( @@ -747,10 +755,11 @@ def _execute_autodiscovery( if not (autodiscovery_queue := AutoQueue(autodiscovery_dir)): return {}, False + ab_plugins = agent_based_register.get_previously_loaded_plugins() + discovery_rules = agent_based_register.get_previously_collected_discovery_rules() if not called_from_automation_helper: - config.load() + config.load(discovery_rules) config_cache = config.get_config_cache() - ab_plugins = agent_based_register.get_previously_loaded_plugins() autochecks_config = config.AutochecksConfigurer(config_cache, ab_plugins.check_plugins) ip_address_of = config.ConfiguredIPLookup( config_cache, @@ -787,9 +796,12 @@ def _execute_autodiscovery( host_label_plugins = HostLabelPluginMapper( ruleset_matcher=ruleset_matcher, sections={**ab_plugins.agent_sections, **ab_plugins.snmp_sections}, + discovery_rules=discovery_rules, ) plugins = DiscoveryPluginMapper( - ruleset_matcher=ruleset_matcher, check_plugins=ab_plugins.check_plugins + ruleset_matcher=ruleset_matcher, + check_plugins=ab_plugins.check_plugins, + discovery_rules=discovery_rules, ) on_error = OnError.IGNORE @@ -1454,7 +1466,7 @@ def execute( servicedesc = args[1] config_cache = config.get_config_cache() config_cache.ruleset_matcher.ruleset_optimizer.set_all_processed_hosts({host_name}) - plugins = get_previously_loaded_plugins() + plugins = agent_based_register.get_previously_loaded_plugins() return ( AnalyseServiceResult( service_info=found.service_info, @@ -1971,7 +1983,7 @@ def execute( # that could be too much for the command line variable_names = ast.literal_eval(sys.stdin.read()) - config.load(with_conf_d=False) + config.load(discovery_rulesets=(), with_conf_d=False) missing_variables = [v for v in variable_names if not hasattr(config, v)] @@ -1980,7 +1992,11 @@ def execute( local_checks_dir=local_checks_dir, checks_dir=checks_dir, ) - config.load(with_conf_d=False) + plugins = agent_based_register.get_previously_loaded_plugins() + config.load( + discovery_rulesets=agent_based_register.extract_known_discovery_rulesets(plugins), + with_conf_d=False, + ) result = {} for varname in variable_names: diff --git a/cmk/base/checkers.py b/cmk/base/checkers.py index 29b2e159831..8f3b176ad5e 100644 --- a/cmk/base/checkers.py +++ b/cmk/base/checkers.py @@ -500,10 +500,12 @@ def __init__( *, ruleset_matcher: RulesetMatcher, sections: Mapping[SectionName, AgentSectionPluginAPI | SNMPSectionPluginAPI], + discovery_rules: Mapping[RuleSetName, Sequence[RuleSpec]], ) -> None: super().__init__() self.ruleset_matcher: Final = ruleset_matcher self._sections = sections + self._discovery_rules: Final = discovery_rules def __getitem__(self, __key: SectionName) -> HostLabelPlugin: plugin = self._sections.get(__key) @@ -516,7 +518,7 @@ def __getitem__(self, __key: SectionName) -> HostLabelPlugin: default_parameters=plugin.host_label_default_parameters, ruleset_name=plugin.host_label_ruleset_name, ruleset_type=plugin.host_label_ruleset_type, - rules_getter_function=agent_based_register.get_host_label_ruleset, + rules_getter_function=lambda n: self._discovery_rules.get(n, []), ), ) if plugin is not None @@ -1038,10 +1040,12 @@ def __init__( *, ruleset_matcher: RulesetMatcher, check_plugins: Mapping[CheckPluginName, CheckPluginAPI], + discovery_rules: Mapping[RuleSetName, Sequence[RuleSpec]], ) -> None: super().__init__() self.ruleset_matcher: Final = ruleset_matcher self._check_plugins: Final = check_plugins + self._discovery_rules: Final = discovery_rules def __getitem__(self, __key: CheckPluginName) -> DiscoveryPlugin: # `get_check_plugin()` is not an error. Both check plug-ins and @@ -1074,7 +1078,7 @@ def __discovery_function( default_parameters=plugin.discovery_default_parameters, ruleset_name=plugin.discovery_ruleset_name, ruleset_type=plugin.discovery_ruleset_type, - rules_getter_function=agent_based_register.get_discovery_ruleset, + rules_getter_function=lambda n: self._discovery_rules.get(n, []), ), ) diff --git a/cmk/base/config.py b/cmk/base/config.py index fa144e70382..c145adc3429 100644 --- a/cmk/base/config.py +++ b/cmk/base/config.py @@ -567,7 +567,10 @@ def register(name: str, default_value: Any) -> None: # '----------------------------------------------------------------------' +# This function still mostly manipulates a global state. +# Passing the discovery rulesets as an argument is a first step to make it more functional. def load( + discovery_rulesets: Iterable[RuleSetName], with_conf_d: bool = True, validate_hosts: bool = True, ) -> None: @@ -577,7 +580,7 @@ def load( _initialize_derived_config_variables() - _perform_post_config_loading_actions() + _perform_post_config_loading_actions(discovery_rulesets) if validate_hosts: config_cache = get_config_cache() @@ -595,7 +598,9 @@ def load( sys.exit(3) -def load_packed_config(config_path: ConfigPath) -> None: +# This function still mostly manipulates a global state. +# Passing the discovery rulesets as an argument is a first step to make it more functional. +def load_packed_config(config_path: ConfigPath, discovery_rulesets: Iterable[RuleSetName]) -> None: """Load the configuration for the CMK helpers of CMC These files are written by PackedConfig(). @@ -611,22 +616,20 @@ def load_packed_config(config_path: ConfigPath) -> None: """ _initialize_config() globals().update(PackedConfigStore.from_serial(config_path).read()) - _perform_post_config_loading_actions() + _perform_post_config_loading_actions(discovery_rulesets) def _initialize_config() -> None: load_default_config() -def _perform_post_config_loading_actions() -> None: +def _perform_post_config_loading_actions(discovery_rulesets: Iterable[RuleSetName]) -> None: """These tasks must be performed after loading the Check_MK base configuration""" # First cleanup things (needed for e.g. reloading the config) cache_manager.clear_all() global_dict = globals() - _collect_parameter_rulesets_from_globals( - global_dict, agent_based_register.iter_all_discovery_rulesets() - ) + _collect_parameter_rulesets_from_globals(global_dict, discovery_rulesets) _transform_plugin_names_from_160_to_170(global_dict) get_config_cache().initialize() @@ -808,9 +811,15 @@ def get_derived_config_variable_names() -> set[str]: return {"service_service_levels", "host_service_levels"} -def save_packed_config(config_path: ConfigPath, config_cache: ConfigCache) -> None: +def save_packed_config( + config_path: ConfigPath, + config_cache: ConfigCache, + discovery_rules: Mapping[RuleSetName, Sequence[RuleSpec]], +) -> None: """Create and store a precompiled configuration for Checkmk helper processes""" - PackedConfigStore.from_serial(config_path).write(PackedConfigGenerator(config_cache).generate()) + PackedConfigStore.from_serial(config_path).write( + PackedConfigGenerator(config_cache, discovery_rules).generate() + ) class PackedConfigGenerator: @@ -840,8 +849,11 @@ class PackedConfigGenerator: "extra_nagios_conf", ] - def __init__(self, config_cache: ConfigCache) -> None: + def __init__( + self, config_cache: ConfigCache, discovery_rules: Mapping[RuleSetName, Sequence[RuleSpec]] + ) -> None: self._config_cache = config_cache + self._discovery_rules = discovery_rules def generate(self) -> Mapping[str, Any]: helper_config: dict[str, Any] = {} @@ -926,18 +938,7 @@ def filter_extra_service_conf( helper_config[varname] = val - # - # Add discovery rules - # - - for ruleset_name in agent_based_register.iter_all_discovery_rulesets(): - value = agent_based_register.get_discovery_ruleset(ruleset_name) - if not value: - continue - - helper_config[str(ruleset_name)] = value - - return helper_config + return helper_config | {str(k): v for k, v in self._discovery_rules.items()} class PackedConfigStore: diff --git a/cmk/base/core.py b/cmk/base/core.py index 69479358aec..93e854e735a 100644 --- a/cmk/base/core.py +++ b/cmk/base/core.py @@ -23,7 +23,10 @@ import cmk.base.nagios_utils from cmk.base import core_config -from cmk.base.api.agent_based.register import get_previously_loaded_plugins +from cmk.base.api.agent_based.register import ( + get_previously_collected_discovery_rules, + get_previously_loaded_plugins, +) from cmk.base.config import ConfigCache, ConfiguredIPLookup from cmk.base.core_config import MonitoringCore @@ -93,6 +96,7 @@ def do_restart( core=core, config_cache=config_cache, plugins=get_previously_loaded_plugins(), + discovery_rules=get_previously_collected_discovery_rules(), ip_address_of=ip_address_of, all_hosts=all_hosts, hosts_to_update=hosts_to_update, diff --git a/cmk/base/core_config.py b/cmk/base/core_config.py index 0802c869bf9..1991ea7a5af 100644 --- a/cmk/base/core_config.py +++ b/cmk/base/core_config.py @@ -8,7 +8,7 @@ import shutil import socket import sys -from collections.abc import Callable, Collection, Iterable, Iterator, Mapping +from collections.abc import Callable, Collection, Iterable, Iterator, Mapping, Sequence from contextlib import contextmanager, nullcontext, suppress from pathlib import Path from typing import Literal @@ -27,6 +27,8 @@ from cmk.utils.licensing.handler import LicensingHandler from cmk.utils.licensing.helper import get_licensed_state_file_path from cmk.utils.paths import configuration_lockfile +from cmk.utils.rulesets import RuleSetName +from cmk.utils.rulesets.ruleset_matcher import RuleSpec from cmk.utils.servicename import Item, ServiceName from cmk.utils.tags import TagGroupID, TagID @@ -65,6 +67,7 @@ def create_config( config_path: VersionedConfigPath, config_cache: ConfigCache, plugins: agent_based_register.AgentBasedPlugins, + discovery_rules: Mapping[RuleSetName, Sequence[RuleSpec]], ip_address_of: config.ConfiguredIPLookup[ip_lookup.CollectFailedHosts], passwords: Mapping[str, str], hosts_to_update: set[HostName] | None = None, @@ -77,6 +80,7 @@ def create_config( ip_address_of, licensing_handler, plugins, + discovery_rules, passwords, hosts_to_update, ) @@ -89,6 +93,7 @@ def _create_config( ip_address_of: config.ConfiguredIPLookup[ip_lookup.CollectFailedHosts], licensing_handler: LicensingHandler, plugins: agent_based_register.AgentBasedPlugins, + discovery_rules: Mapping[RuleSetName, Sequence[RuleSpec]], passwords: Mapping[str, str], hosts_to_update: set[HostName] | None = None, ) -> None: @@ -259,6 +264,7 @@ def do_create_config( core: MonitoringCore, config_cache: ConfigCache, plugins: agent_based_register.AgentBasedPlugins, + discovery_rules: Mapping[RuleSetName, Sequence[RuleSpec]], ip_address_of: config.ConfiguredIPLookup[ip_lookup.CollectFailedHosts], all_hosts: Iterable[HostName], hosts_to_update: set[HostName] | None = None, @@ -289,6 +295,7 @@ def do_create_config( core, config_cache, plugins, + discovery_rules, ip_address_of, hosts_to_update=hosts_to_update, duplicates=duplicates, @@ -382,6 +389,7 @@ def _create_core_config( core: MonitoringCore, config_cache: ConfigCache, plugins: agent_based_register.AgentBasedPlugins, + discovery_rules: Mapping[RuleSetName, Sequence[RuleSpec]], ip_address_of: config.ConfiguredIPLookup[ip_lookup.CollectFailedHosts], hosts_to_update: set[HostName] | None = None, *, @@ -402,6 +410,7 @@ def _create_core_config( config_path, config_cache, plugins, + discovery_rules, ip_address_of, hosts_to_update=hosts_to_update, passwords=passwords, diff --git a/cmk/base/core_nagios/_create_config.py b/cmk/base/core_nagios/_create_config.py index 20f829de3a5..b2ec34e00ee 100644 --- a/cmk/base/core_nagios/_create_config.py +++ b/cmk/base/core_nagios/_create_config.py @@ -28,6 +28,8 @@ from cmk.utils.licensing.handler import LicensingHandler from cmk.utils.macros import replace_macros_in_str from cmk.utils.notify import NotificationHostConfig, write_notify_host_file +from cmk.utils.rulesets import RuleSetName +from cmk.utils.rulesets.ruleset_matcher import RuleSpec from cmk.utils.servicename import MAX_SERVICE_NAME_LEN, ServiceName from cmk.checkengine.checking import CheckPluginName @@ -72,6 +74,7 @@ def _create_config( ip_address_of: config.IPLookup, licensing_handler: LicensingHandler, plugins: AgentBasedPlugins, + discovery_rules: Mapping[RuleSetName, Sequence[RuleSpec]], passwords: Mapping[str, str], hosts_to_update: set[HostName] | None = None, ) -> None: @@ -82,6 +85,7 @@ def _create_config( self._precompile_hostchecks( config_path, plugins, + discovery_rules, precompile_mode=( PrecompileMode.DELAYED if config.delay_precompile else PrecompileMode.INSTANT ), @@ -129,6 +133,7 @@ def _precompile_hostchecks( self, config_path: VersionedConfigPath, plugins: AgentBasedPlugins, + discovery_rules: Mapping[RuleSetName, Sequence[RuleSpec]], *, precompile_mode: PrecompileMode, ) -> None: @@ -139,6 +144,7 @@ def _precompile_hostchecks( config_path, self._config_cache, plugins, + discovery_rules, precompile_mode=precompile_mode, ) with suppress(IOError): diff --git a/cmk/base/core_nagios/_host_check_template.py b/cmk/base/core_nagios/_host_check_template.py index 1df4996a24f..1f9bb5d4fd6 100644 --- a/cmk/base/core_nagios/_host_check_template.py +++ b/cmk/base/core_nagios/_host_check_template.py @@ -17,7 +17,11 @@ import cmk.base.utils from cmk.base import config -from cmk.base.api.agent_based.register import load_selected_plugins +from cmk.base.api.agent_based.register import ( + extract_known_discovery_rulesets, + get_previously_loaded_plugins, + load_selected_plugins, +) from cmk.base.core_nagios import HostCheckConfig from cmk.base.modes.check_mk import mode_check @@ -87,7 +91,9 @@ def main() -> int: _errors, sections, checks = config.load_and_convert_legacy_checks(CONFIG.checks_to_load) load_selected_plugins(CONFIG.locations, sections, checks, validate=debug) - config.load_packed_config(LATEST_CONFIG) + discovery_rulesets = extract_known_discovery_rulesets(get_previously_loaded_plugins()) + + config.load_packed_config(LATEST_CONFIG, discovery_rulesets) config.ipaddresses = CONFIG.ipaddresses config.ipv6addresses = CONFIG.ipv6addresses diff --git a/cmk/base/core_nagios/_precompile_host_checks.py b/cmk/base/core_nagios/_precompile_host_checks.py index 7a8606414b0..dc41b606e71 100644 --- a/cmk/base/core_nagios/_precompile_host_checks.py +++ b/cmk/base/core_nagios/_precompile_host_checks.py @@ -18,7 +18,7 @@ import re import socket import sys -from collections.abc import Iterable +from collections.abc import Iterable, Mapping, Sequence from pathlib import Path from typing import assert_never @@ -34,6 +34,8 @@ from cmk.utils.hostaddress import HostAddress, HostName from cmk.utils.ip_lookup import IPStackConfig from cmk.utils.log import console +from cmk.utils.rulesets import RuleSetName +from cmk.utils.rulesets.ruleset_matcher import RuleSpec import cmk.base.api.agent_based.register as agent_based_register import cmk.base.utils @@ -113,13 +115,14 @@ def precompile_hostchecks( config_path: VersionedConfigPath, config_cache: ConfigCache, plugins: agent_based_register.AgentBasedPlugins, + discovery_rules: Mapping[RuleSetName, Sequence[RuleSpec]], *, precompile_mode: PrecompileMode, ) -> None: console.verbose("Creating precompiled host check config...") hosts_config = config_cache.hosts_config - save_packed_config(config_path, config_cache) + save_packed_config(config_path, config_cache, discovery_rules) console.verbose("Precompiling host checks...") diff --git a/cmk/base/diagnostics.py b/cmk/base/diagnostics.py index c982c494ba3..444f8e91e16 100644 --- a/cmk/base/diagnostics.py +++ b/cmk/base/diagnostics.py @@ -17,7 +17,7 @@ import traceback import urllib.parse import uuid -from collections.abc import Iterator, Mapping +from collections.abc import Iterable, Iterator, Mapping from datetime import datetime from functools import cache from pathlib import Path @@ -61,8 +61,14 @@ from cmk.utils.local_secrets import SiteInternalSecret from cmk.utils.log import console, section from cmk.utils.paths import omd_root +from cmk.utils.rulesets import RuleSetName from cmk.utils.structured_data import load_tree, SDNodeName, SDRawTree, serialize_tree +from cmk.base.api.agent_based.register import ( + extract_known_discovery_rulesets, + get_previously_loaded_plugins, +) + if cmk_version.edition(cmk.utils.paths.omd_root) in [ cmk_version.Edition.CEE, cmk_version.Edition.CME, @@ -74,7 +80,7 @@ ) else: - def cmc_specific_attrs() -> Mapping[str, int]: + def cmc_specific_attrs(discovery_rulesets: Iterable[RuleSetName]) -> Mapping[str, int]: return {} @@ -544,7 +550,8 @@ def _collect_infos(self) -> DiagnosticsElementJSONResult: if (key := result[0][i]) not in ["license_usage_history"] } - performance_data.update(cmc_specific_attrs()) + discovery_rulesets = extract_known_discovery_rulesets(get_previously_loaded_plugins()) + performance_data.update(cmc_specific_attrs(discovery_rulesets)) return performance_data diff --git a/cmk/base/export.py b/cmk/base/export.py index 097cb43eda1..50b31ac8316 100644 --- a/cmk/base/export.py +++ b/cmk/base/export.py @@ -18,7 +18,10 @@ from cmk.checkengine.checking import CheckPluginName from cmk.base import config -from cmk.base.api.agent_based.register import get_previously_loaded_plugins +from cmk.base.api.agent_based.register import ( + extract_known_discovery_rulesets, + get_previously_loaded_plugins, +) _config_loaded = False _checks_loaded = False @@ -28,7 +31,8 @@ def _load_config() -> None: global _config_loaded if not _config_loaded: - config.load(validate_hosts=False) + plugins = get_previously_loaded_plugins() + config.load(extract_known_discovery_rulesets(plugins), validate_hosts=False) _config_loaded = True diff --git a/cmk/base/modes/check_mk.py b/cmk/base/modes/check_mk.py index 66440e26fd9..c78208ba8ca 100644 --- a/cmk/base/modes/check_mk.py +++ b/cmk/base/modes/check_mk.py @@ -1462,6 +1462,7 @@ def mode_update() -> None: core=create_core(config.monitoring_core), config_cache=config_cache, plugins=agent_based_register.get_previously_loaded_plugins(), + discovery_rules=agent_based_register.get_previously_collected_discovery_rules(), ip_address_of=ip_address_of, all_hosts=hosts_config.hosts, duplicates=sorted( @@ -1784,8 +1785,10 @@ def mode_automation(args: list[str]) -> None: def mode_notify(options: dict, args: list[str]) -> int | None: from cmk.base import notify + plugins = agent_based_register.get_previously_loaded_plugins() + discovery_rules = agent_based_register.extract_known_discovery_rulesets(plugins) with store.lock_checkmk_configuration(configuration_lockfile): - config.load(with_conf_d=True, validate_hosts=False) + config.load(discovery_rulesets=discovery_rules, with_conf_d=True, validate_hosts=False) def ensure_nagios(msg: str) -> None: if config.is_cmc(): @@ -1871,6 +1874,7 @@ def mode_check_discovery( config_cache = config.get_config_cache() plugins = agent_based_register.get_previously_loaded_plugins() + discovery_rules = agent_based_register.get_previously_collected_discovery_rules() ruleset_matcher = config_cache.ruleset_matcher ruleset_matcher.ruleset_optimizer.set_all_processed_hosts({hostname}) autochecks_config = config.AutochecksConfigurer(config_cache, plugins.check_plugins) @@ -1943,9 +1947,12 @@ def mode_check_discovery( host_label_plugins=HostLabelPluginMapper( ruleset_matcher=ruleset_matcher, sections={**plugins.agent_sections, **plugins.snmp_sections}, + discovery_rules=discovery_rules, ), plugins=DiscoveryPluginMapper( - ruleset_matcher=ruleset_matcher, check_plugins=plugins.check_plugins + ruleset_matcher=ruleset_matcher, + check_plugins=plugins.check_plugins, + discovery_rules=discovery_rules, ), autochecks_config=autochecks_config, enforced_services=config_cache.enforced_services_table( @@ -2170,6 +2177,7 @@ def mode_discover(options: _DiscoveryOptions, args: list[str]) -> None: config_cache = config.get_config_cache() hosts_config = config.make_hosts_config() plugins = agent_based_register.get_previously_loaded_plugins() + discovery_rules = agent_based_register.get_previously_collected_discovery_rules() hostnames = modes.parse_hostname_list(config_cache, hosts_config, args) if hostnames: # In case of discovery with host restriction, do not use the cache @@ -2262,9 +2270,12 @@ def section_error_handling( host_label_plugins=HostLabelPluginMapper( ruleset_matcher=config_cache.ruleset_matcher, sections={**plugins.agent_sections, **plugins.snmp_sections}, + discovery_rules=discovery_rules, ), plugins=DiscoveryPluginMapper( - ruleset_matcher=config_cache.ruleset_matcher, check_plugins=plugins.check_plugins + ruleset_matcher=config_cache.ruleset_matcher, + check_plugins=plugins.check_plugins, + discovery_rules=discovery_rules, ), run_plugin_names=run_plugin_names, ignore_plugin=config_cache.check_plugin_ignored, @@ -3061,7 +3072,8 @@ def mode_inventorize_marked_hosts(options: Mapping[str, object]) -> None: console.verbose("Autoinventory: No hosts marked by inventory check") return - config.load() + discovery_rules = agent_based_register.get_previously_collected_discovery_rules() + config.load(discovery_rules) config_cache = config.get_config_cache() plugins = agent_based_register.get_previously_loaded_plugins() parser = CMKParser( diff --git a/cmk/rrd/config.py b/cmk/rrd/config.py index 8d89eeabb7e..cc98880313d 100644 --- a/cmk/rrd/config.py +++ b/cmk/rrd/config.py @@ -49,7 +49,7 @@ def get_hosts(self) -> Sequence[HostName]: ) def _load_cee_config_cache(self) -> CEEConfigCache: - base_config.load_packed_config(LATEST_CONFIG) + base_config.load_packed_config(LATEST_CONFIG, discovery_rulesets=()) config_cache = base_config.get_config_cache() assert isinstance(config_cache, CEEConfigCache) return config_cache diff --git a/cmk/rrd/convert_rrds.py b/cmk/rrd/convert_rrds.py index 022f4832c63..1cf7da4c21c 100644 --- a/cmk/rrd/convert_rrds.py +++ b/cmk/rrd/convert_rrds.py @@ -21,7 +21,7 @@ def convert_rrds( split: bool, delete: bool, ) -> None: - config.load(with_conf_d=True) + config.load(discovery_rulesets=(), with_conf_d=True) rrd_config = RRDConfigImpl() if not hostnames: diff --git a/cmk/update_config/main.py b/cmk/update_config/main.py index ba647e0df07..2aff291f735 100644 --- a/cmk/update_config/main.py +++ b/cmk/update_config/main.py @@ -35,6 +35,10 @@ # to a specific layer in the future, but for the the moment we need to deal # with it. from cmk.base import config as base_config +from cmk.base.api.agent_based.register import ( + extract_known_discovery_rulesets, + get_previously_loaded_plugins, +) from cmk.gui import main_modules from cmk.gui.exceptions import MKUserError @@ -296,9 +300,10 @@ def _initialize_base_environment() -> None: local_checks_dir=paths.local_checks_dir, checks_dir=paths.checks_dir, ) + plugins = get_previously_loaded_plugins() # Watch out: always load the plugins before loading the config. # The validation step will not be executed otherwise. - base_config.load() + base_config.load(extract_known_discovery_rulesets(plugins)) @contextmanager diff --git a/cmk/validate_plugins.py b/cmk/validate_plugins.py index 99334ef6b40..6578fd36c6c 100644 --- a/cmk/validate_plugins.py +++ b/cmk/validate_plugins.py @@ -30,8 +30,8 @@ ) from cmk.base.api.agent_based.register import ( # pylint: disable=cmk-module-layer-violation AgentBasedPlugins, + extract_known_discovery_rulesets, get_previously_loaded_plugins, - iter_all_discovery_rulesets, ) from cmk.base.config import ( # pylint: disable=cmk-module-layer-violation load_all_plugins, @@ -304,7 +304,10 @@ def _validate_discovery_parameters_usage() -> Sequence[str]: {DiscoveryParameters: entry_point_prefixes()[DiscoveryParameters]}, raise_errors=False, ) - referenced_ruleset_names = {str(ruleset_name) for ruleset_name in iter_all_discovery_rulesets()} + referenced_ruleset_names = { + str(ruleset_name) + for ruleset_name in extract_known_discovery_rulesets(get_previously_loaded_plugins()) + } return _check_if_referenced(discovered_discovery_parameters, referenced_ruleset_names) diff --git a/tests/unit/cmk/base/test_config.py b/tests/unit/cmk/base/test_config.py index 733d035441c..27ddca88183 100644 --- a/tests/unit/cmk/base/test_config.py +++ b/tests/unit/cmk/base/test_config.py @@ -2822,7 +2822,7 @@ def folder_path_test_config_fixture(monkeypatch: MonkeyPatch) -> Iterator[None]: _add_host_in_folder(wato_lvl2_folder, "lvl2-host") _add_rule_in_folder(wato_lvl2_folder, "LVL2") - config.load() + config.load(discovery_rulesets=()) yield @@ -2915,7 +2915,7 @@ def test_explicit_setting_loading(patch_omd_site: None) -> None: for foldername, setting, values in settings: _add_explicit_setting_in_folder(wato_main_folder / foldername, setting, values) - config.load() + config.load(discovery_rulesets=()) assert config.explicit_host_conf["parents"][HostName("hostA")] == "setting1" assert config.explicit_host_conf["parents"][HostName("hostB")] == "setting2" assert config.explicit_host_conf["other"][HostName("hostA")] == "setting3" @@ -2939,7 +2939,7 @@ def test_save_packed_config(monkeypatch: MonkeyPatch, config_path: VersionedConf assert not precompiled_check_config.exists() - config.save_packed_config(config_path, config_cache) + config.save_packed_config(config_path, config_cache, {}) assert precompiled_check_config.exists() @@ -2948,7 +2948,7 @@ def test_load_packed_config(config_path: VersionedConfigPath) -> None: config.PackedConfigStore.from_serial(config_path).write({"abcd": 1}) assert "abcd" not in config.__dict__ - config.load_packed_config(config_path) + config.load_packed_config(config_path, discovery_rulesets=()) # Mypy does not understand that we add some new member for testing assert config.abcd == 1 # type: ignore[attr-defined] del config.__dict__["abcd"] diff --git a/tests/unit/cmk/base/test_core_config.py b/tests/unit/cmk/base/test_core_config.py index 8cb18f730eb..112b3a62d93 100644 --- a/tests/unit/cmk/base/test_core_config.py +++ b/tests/unit/cmk/base/test_core_config.py @@ -77,7 +77,8 @@ def test_do_create_config_nagios( create_core("nagios"), core_scenario, AgentBasedPlugins({}, {}, {}, {}), - ip_address_of, + discovery_rules={}, + ip_address_of=ip_address_of, all_hosts=[HostName("test-host")], duplicates=(), ) @@ -103,7 +104,8 @@ def test_do_create_config_nagios_collects_passwords( create_core("nagios"), core_scenario, AgentBasedPlugins({}, {}, {}, {}), - ip_address_of, + discovery_rules={}, + ip_address_of=ip_address_of, all_hosts=[HostName("test-host")], duplicates=(), ) diff --git a/tests/unit/cmk/base/test_discovery.py b/tests/unit/cmk/base/test_discovery.py index 310874986d3..acf88cd0967 100644 --- a/tests/unit/cmk/base/test_discovery.py +++ b/tests/unit/cmk/base/test_discovery.py @@ -1188,6 +1188,7 @@ def test__find_candidates( for name, p in DiscoveryPluginMapper( ruleset_matcher=config_cache.ruleset_matcher, check_plugins=agent_based_plugins.check_plugins, + discovery_rules={}, ).items() ], ) == { @@ -1310,6 +1311,7 @@ def test_commandline_discovery( snmp_backend_override=None, password_store_file=Path("/pw/store"), ) + discovery_rulesets = agent_based_register.extract_known_discovery_rulesets(agent_based_plugins) commandline_discovery( host_name=testhost, ruleset_matcher=config_cache.ruleset_matcher, @@ -1322,10 +1324,12 @@ def test_commandline_discovery( host_label_plugins=HostLabelPluginMapper( ruleset_matcher=config_cache.ruleset_matcher, sections={**agent_based_plugins.agent_sections, **agent_based_plugins.snmp_sections}, + discovery_rules={r: [] for r in discovery_rulesets}, ), plugins=DiscoveryPluginMapper( ruleset_matcher=config_cache.ruleset_matcher, check_plugins=agent_based_plugins.check_plugins, + discovery_rules={r: [] for r in discovery_rulesets}, ), run_plugin_names=EVERYTHING, ignore_plugin=lambda *args, **kw: False, @@ -1634,6 +1638,21 @@ def test__discovery_considers_host_labels( plugins = DiscoveryPluginMapper( ruleset_matcher=config_cache.ruleset_matcher, check_plugins=agent_based_plugins.check_plugins, + discovery_rules={ + RuleSetName("mssql_transactionlogs_discovery"): [], + RuleSetName("inventory_df_rules"): [ + { + "id": "nobody-cares-about-the-id-in-this-test", + "value": { + "ignore_fs_types": ["tmpfs", "nfs", "smbfs", "cifs", "iso9660"], + "never_ignore_mountpoints": ["~.*/omd/sites/[^/]+/tmp$"], + }, + "condition": { + "host_label_groups": [("and", [("and", "cmk/check_mk_server:yes")])] + }, + } + ], + }, ) plugin_names = find_plugins( providers, @@ -1797,6 +1816,10 @@ def test__discover_host_labels_and_services_on_realhost( plugins = DiscoveryPluginMapper( ruleset_matcher=config_cache.ruleset_matcher, check_plugins=agent_based_plugins.check_plugins, + discovery_rules={ + RuleSetName("mssql_transactionlogs_discovery"): [], + RuleSetName("inventory_df_rules"): [], + }, ) plugin_names = find_plugins( providers, @@ -1839,6 +1862,7 @@ def test__perform_host_label_discovery_on_realhost( **agent_based_plugins.agent_sections, **agent_based_plugins.snmp_sections, }, + discovery_rules={}, ), providers=scenario.providers, on_error=OnError.RAISE, @@ -1864,6 +1888,10 @@ def test__discover_services_on_cluster( DiscoveryPluginMapper( ruleset_matcher=cluster_scenario.config_cache.ruleset_matcher, check_plugins=agent_based_plugins.check_plugins, + discovery_rules={ + RuleSetName("mssql_transactionlogs_discovery"): [], + RuleSetName("inventory_df_rules"): [], + }, ), OnError.RAISE, ) == { @@ -1914,6 +1942,7 @@ def test__perform_host_label_discovery_on_cluster( **agent_based_plugins.agent_sections, **agent_based_plugins.snmp_sections, }, + discovery_rules={}, ), providers=scenario.providers, on_error=OnError.RAISE,