def test_multiple_sources_from_different_hosts(self, hostname, ipaddress, config_cache, host_config): sources = [ DSProgramDataSource( hostname + "0", ipaddress, configurator=DSProgramConfigurator(hostname + "0", ipaddress, template="",),), TCPDataSource(hostname + "1", ipaddress), TCPDataSource(hostname + "2", ipaddress), ] mhs = make_host_sections( config_cache, host_config, ipaddress, sources=sources, max_cachefile_age=0, selected_raw_sections=None, ) assert len(mhs) == 1 key = HostKey(hostname, ipaddress, SourceType.HOST) assert key in mhs section = mhs[key] assert isinstance(section, AgentHostSections) assert len(section.sections) == len(sources) for source in sources: # yapf: disable assert ( section.sections[SectionName("section_name_%s" % source.hostname)] == [["section_content"]])
def test_no_sources(self, cluster, nodes, config_cache, host_config): mhs = make_host_sections( config_cache, host_config, None, sources=[], max_cachefile_age=0, selected_raw_sections=None, ) assert len(mhs) == len(nodes) key_clu = HostKey(cluster, None, SourceType.HOST) assert key_clu not in mhs for hostname, addr in nodes.items(): key = HostKey(hostname, addr, SourceType.HOST) assert key in mhs section = mhs[key] # yapf: disable assert (section.sections[SectionName("section_name_%s" % hostname)] == [["section_content"]]) assert not section.cache_info assert not section.piggybacked_raw_data assert not section.persisted_sections
def test_one_snmp_source(self, hostname, ipaddress, mode, config_cache, host_config): mhs = make_host_sections( config_cache, host_config, ipaddress, mode=mode, sources=[ SNMPDataSource(configurator=SNMPConfigurator.snmp( hostname, ipaddress, mode=mode, ),), ], max_cachefile_age=0, selected_raw_sections=None, ) assert len(mhs) == 1 key = HostKey(hostname, ipaddress, SourceType.HOST) assert key in mhs section = mhs[key] assert isinstance(section, SNMPHostSections) assert len(section.sections) == 1 assert section.sections[SectionName("section_name_%s" % hostname)] == [["section_content"]]
def test_no_sources(self, hostname, ipaddress, mode, config_cache, host_config): mhs = make_host_sections( config_cache, host_config, ipaddress, mode=mode, sources=[], max_cachefile_age=0, selected_raw_sections=None, ) # The length is not zero because the function always sets, # at least, a piggy back section. assert len(mhs) == 1 key = HostKey(hostname, ipaddress, SourceType.HOST) assert key in mhs section = mhs[key] assert isinstance(section, AgentHostSections) # Public attributes from ABCHostSections: assert not section.sections assert not section.cache_info assert not section.piggybacked_raw_data assert not section.persisted_sections
def test_multiple_sources_from_the_same_host( self, hostname, ipaddress, mode, config_cache, host_config, ): sources = [ ProgramDataSource(configurator=ProgramConfigurator.ds( hostname, ipaddress, mode=mode, template="", ),), TCPDataSource(configurator=TCPConfigurator( hostname, ipaddress, mode=mode, ),), ] mhs = make_host_sections( config_cache, host_config, ipaddress, mode=mode, sources=sources, max_cachefile_age=0, selected_raw_sections=None, ) assert len(mhs) == 1 key = HostKey(hostname, ipaddress, SourceType.HOST) assert key in mhs section = mhs[key] assert isinstance(section, AgentHostSections) assert len(section.sections) == 1 # yapf: disable assert (section.sections[SectionName("section_name_%s" % hostname)] == len(sources) * [["section_content"]])
def test_one_nonsnmp_source(self, hostname, ipaddress, config_cache, host_config, source): source = source(hostname, ipaddress) assert source.source_type is SourceType.HOST mhs = make_host_sections( config_cache, host_config, ipaddress, sources=[source], max_cachefile_age=0, selected_raw_sections=None, ) assert len(mhs) == 1 key = HostKey(hostname, ipaddress, source.source_type) assert key in mhs section = mhs[key] assert isinstance(section, AgentHostSections) assert len(section.sections) == 1 assert section.sections[SectionName("section_name_%s" % hostname)] == [["section_content"]]
def test_get_host_sections_cluster(monkeypatch, mocker): hostname = "testhost" hosts = { "host0": "10.0.0.0", "host1": "10.0.0.1", "host2": "10.0.0.2", } address = "1.2.3.4" tags = {"agent": "no-agent"} section_name = SectionName("test_section") config_cache = make_scenario(hostname, tags).apply(monkeypatch) host_config = config.HostConfig.make_host_config(hostname) def lookup_ip_address(host_config, family=None, for_mgmt_board=False): return hosts[host_config.hostname] def make_piggybacked_sections(hc): if hc.nodes == host_config.nodes: return {section_name: True} return {} def run(_, *, selected_raw_sections): sections = {} if selected_raw_sections is not None and section_name in selected_raw_sections: sections = {section_name: [[str(section_name)]]} return AgentHostSections(sections=sections) monkeypatch.setattr( ip_lookup, "lookup_ip_address", lookup_ip_address, ) monkeypatch.setattr( _data_sources, "_make_piggybacked_sections", make_piggybacked_sections, ) monkeypatch.setattr( ABCDataSource, "run", run, ) mocker.patch.object( cmk.utils.piggyback, "remove_source_status_file", autospec=True, ) mocker.patch.object( cmk.utils.piggyback, "_store_status_file_of", autospec=True, ) # Create a cluster host_config.nodes = list(hosts.keys()) mhs = make_host_sections( config_cache, host_config, address, make_sources(host_config, address), max_cachefile_age=host_config.max_cachefile_age, selected_raw_sections=None, ) assert len(mhs) == len(hosts) == 3 cmk.utils.piggyback._store_status_file_of.assert_not_called() # type: ignore[attr-defined] assert cmk.utils.piggyback.remove_source_status_file.call_count == 3 # type: ignore[attr-defined] for host, addr in hosts.items(): remove_source_status_file = cmk.utils.piggyback.remove_source_status_file remove_source_status_file.assert_any_call(host) # type: ignore[attr-defined] key = HostKey(host, addr, SourceType.HOST) assert key in mhs section = mhs[key] assert len(section.sections) == 1 assert next(iter(section.sections)) == section_name assert not section.cache_info assert not section.piggybacked_raw_data assert not section.persisted_sections
def do_check( hostname: HostName, ipaddress: Optional[HostAddress], only_check_plugin_names: Optional[Set[CheckPluginName]] = None ) -> Tuple[int, List[ServiceDetails], List[ServiceAdditionalDetails], List[str]]: cpu_tracking.start("busy") console.verbose("Check_MK version %s\n", cmk_version.__version__) config_cache = config.get_config_cache() host_config = config_cache.get_host_config(hostname) exit_spec = host_config.exit_code_spec() status: ServiceState = 0 infotexts: List[ServiceDetails] = [] long_infotexts: List[ServiceAdditionalDetails] = [] perfdata: List[str] = [] try: # In case of keepalive we always have an ipaddress (can be 0.0.0.0 or :: when # address is unknown). When called as non keepalive ipaddress may be None or # is already an address (2nd argument) if ipaddress is None and not host_config.is_cluster: ipaddress = ip_lookup.lookup_ip_address(host_config) item_state.load(hostname) services = _get_filtered_services( host_name=hostname, belongs_to_cluster=len(config_cache.clusters_of(hostname)) > 0, config_cache=config_cache, only_check_plugins=only_check_plugin_names, ) # see which raw sections we may need selected_raw_sections = _get_relevant_raw_sections(services, host_config) sources = data_sources.make_sources( host_config, ipaddress, ) mhs = data_sources.make_host_sections( config_cache, host_config, ipaddress, sources=sources, selected_raw_sections=selected_raw_sections, max_cachefile_age=host_config.max_cachefile_age, ) num_success, plugins_missing_data = _do_all_checks_on_host( config_cache, host_config, ipaddress, multi_host_sections=mhs, services=services, only_check_plugins=only_check_plugin_names, ) inventory.do_inventory_actions_during_checking_for( config_cache, host_config, ipaddress, sources=sources, multi_host_sections=mhs, ) if _submit_to_core: item_state.save(hostname) for source in sources: source_state, source_output, source_perfdata = source.get_summary_result_for_checking() if source_output != "": status = max(status, source_state) infotexts.append("[%s] %s" % (source.id, source_output)) perfdata.extend([_convert_perf_data(p) for p in source_perfdata]) if plugins_missing_data: missing_data_status, missing_data_infotext = _check_plugins_missing_data( plugins_missing_data, exit_spec, bool(num_success), ) status = max(status, missing_data_status) infotexts.append(missing_data_infotext) cpu_tracking.end() phase_times = cpu_tracking.get_times() total_times = phase_times["TOTAL"] run_time = total_times[4] infotexts.append("execution time %.1f sec" % run_time) if config.check_mk_perfdata_with_times: perfdata += [ "execution_time=%.3f" % run_time, "user_time=%.3f" % total_times[0], "system_time=%.3f" % total_times[1], "children_user_time=%.3f" % total_times[2], "children_system_time=%.3f" % total_times[3], ] for phase, times in phase_times.items(): if phase in ["agent", "snmp", "ds"]: t = times[4] - sum(times[:4]) # real time - CPU time perfdata.append("cmk_time_%s=%.3f" % (phase, t)) else: perfdata.append("execution_time=%.3f" % run_time) return status, infotexts, long_infotexts, perfdata finally: if _checkresult_file_fd is not None: _close_checkresult_file() # "ipaddress is not None": At least when working with a cluster host it seems the ipaddress # may be None. This needs to be understood in detail and cleaned up. As the InlineSNMP # stats feature is a very rarely used debugging feature, the analyzation and fix is # postponed now. if config.record_inline_snmp_stats \ and ipaddress is not None \ and host_config.snmp_config(ipaddress).is_inline_snmp_host: inline.snmp_stats_save()
def _do_inv_for_realhost( config_cache: config.ConfigCache, host_config: config.HostConfig, sources: data_sources.DataSources, multi_host_sections: Optional[MultiHostSections], hostname: HostName, ipaddress: Optional[HostAddress], inventory_tree: StructuredDataTree, status_data_tree: StructuredDataTree, ) -> None: for source in sources: if isinstance(source, data_sources.snmp.SNMPDataSource): source.detector.on_error = "raise" # default source.detector.do_snmp_scan = True data_sources.snmp.SNMPDataSource.disable_data_source_cache() source.set_use_snmpwalk_cache(False) source.set_ignore_check_interval(True) if multi_host_sections is not None: # Status data inventory already provides filled multi_host_sections object. # SNMP data source: If 'do_status_data_inv' is enabled there may be # sections for inventory plugins which were not fetched yet. host_sections = multi_host_sections.setdefault( HostKey(hostname, ipaddress, source.source_type), SNMPHostSections(), ) source.set_fetched_raw_section_names( set(host_sections.sections)) host_sections.update(source.run(selected_raw_sections=None)) if multi_host_sections is None: multi_host_sections = data_sources.make_host_sections( config_cache, host_config, ipaddress, sources, max_cachefile_age=host_config.max_cachefile_age, selected_raw_sections=None, ) section.section_step("Executing inventory plugins") import cmk.base.inventory_plugins as inventory_plugins # pylint: disable=import-outside-toplevel console.verbose("Plugins:") for section_name, plugin in inventory_plugins.sorted_inventory_plugins(): section_content = multi_host_sections.get_section_content( HostKey(hostname, ipaddress, SourceType.HOST), check_api_utils.HOST_PRECEDENCE, section_name, for_discovery=False, ) if not section_content: # section not present (None or []) # Note: this also excludes existing sections without info.. continue if all([x in [[], {}, None] for x in section_content]): # Inventory plugins which get parsed info from related # check plugin may have more than one return value, eg # parse function of oracle_tablespaces returns ({}, {}) continue console.verbose(" %s%s%s%s" % (tty.green, tty.bold, section_name, tty.normal)) # Inventory functions can optionally have a second argument: parameters. # These are configured via rule sets (much like check parameters). inv_function = plugin["inv_function"] kwargs = cmk.utils.misc.make_kwargs_for( inv_function, inventory_tree=inventory_tree, status_data_tree=status_data_tree) non_kwargs = set( cmk.utils.misc.getfuncargs(inv_function)) - set(kwargs) args = [section_content] if len(non_kwargs) == 2: args += [host_config.inventory_parameters(section_name)] inv_function(*args, **kwargs) console.verbose("\n")
def _do_inv_for_realhost( config_cache: config.ConfigCache, host_config: config.HostConfig, sources: data_sources.DataSources, multi_host_sections: Optional[MultiHostSections], hostname: HostName, ipaddress: Optional[HostAddress], inventory_tree: StructuredDataTree, status_data_tree: StructuredDataTree, ) -> None: for source in sources: if isinstance(source, data_sources.snmp.SNMPDataSource): # TODO(ml): This modifies the SNMP fetcher config dynamically. configurator = cast(data_sources.snmp.SNMPConfigurator, source.configurator) configurator.on_snmp_scan_error = "raise" # default configurator.do_snmp_scan = True data_sources.FileCacheConfigurator.snmp_disabled = True configurator.use_snmpwalk_cache = False configurator.ignore_check_interval = True if multi_host_sections is not None: # Status data inventory already provides filled multi_host_sections object. # SNMP data source: If 'do_status_data_inv' is enabled there may be # sections for inventory plugins which were not fetched yet. host_sections = multi_host_sections.setdefault( # TODO(ml): are # hostname == source.hostname # ipaddress == source.ipaddress # ? HostKey(hostname, ipaddress, source.configurator.source_type), SNMPHostSections(), ) # TODO(ml): This modifies the SNMP fetcher config dynamically. # Can the fetcher handle that on its own? configurator.prefetched_sections = host_sections.sections host_sections.update(source.run(selected_raw_sections=None)) if multi_host_sections is None: multi_host_sections = data_sources.make_host_sections( config_cache, host_config, ipaddress, data_sources.Mode.INVENTORY, sources, max_cachefile_age=host_config.max_cachefile_age, selected_raw_sections=None, ) section.section_step("Executing inventory plugins") console.verbose("Plugins:") for inventory_plugin in agent_based_register.iter_all_inventory_plugins(): kwargs = multi_host_sections.get_section_kwargs( HostKey(hostname, ipaddress, SourceType.HOST), inventory_plugin.sections, ) if not kwargs: continue console.verbose(" %s%s%s%s" % (tty.green, tty.bold, inventory_plugin.name, tty.normal)) # Inventory functions can optionally have a second argument: parameters. # These are configured via rule sets (much like check parameters). if inventory_plugin.inventory_ruleset_name is not None: kwargs["params"] = host_config.inventory_parameters( str(inventory_plugin.inventory_ruleset_name)) # TODO (mo): keep type! _aggregate_inventory_results( inventory_plugin.inventory_function(**kwargs), inventory_tree, status_data_tree, ) console.verbose("\n")