def test_split_phase(self, set_time): set_time(0.0) with CPUTracker() as tracker0: set_time(3.0) with CPUTracker() as tracker1: set_time(5.0) with CPUTracker() as tracker2: set_time(11.0) assert sum(tracker.duration.run_time for tracker in (tracker0, tracker1, tracker2)) == 11.0
def test_nested_phases(self, set_time): set_time(0.0) with CPUTracker() as tracker1: set_time(3.0) with CPUTracker() as tracker2: set_time(5.0) with CPUTracker() as tracker3: set_time(13.0) assert tracker1.duration.run_time == 13.0 assert tracker2.duration.run_time == 13.0 - 3.0 assert tracker3.duration.run_time == 13.0 - 5.0
def test_sequential_phases(self, set_time): set_time(0.0) with CPUTracker() as tracker1: set_time(3.0) with CPUTracker() as tracker2: set_time(5.0) with CPUTracker() as tracker3: set_time(11.0) assert tracker1.duration.run_time == 3.0 assert tracker2.duration.run_time == 5.0 - 3.0 assert tracker3.duration.run_time == 11.0 - 5.0
def fetch_all( sources: Iterable[Source], *, file_cache_max_age: file_cache.MaxAge, mode: Mode, ) -> Sequence[Tuple[Source, FetcherMessage]]: console.verbose("%s+%s %s\n", tty.yellow, tty.normal, "Fetching data".upper()) out: List[Tuple[Source, FetcherMessage]] = [] for source in sources: console.vverbose(" Source: %s/%s\n" % (source.source_type, source.fetcher_type)) source.file_cache_max_age = file_cache_max_age with CPUTracker() as tracker: raw_data = source.fetch(mode) out.append( ( source, FetcherMessage.from_raw_data( raw_data, tracker.duration, source.fetcher_type, ), ) ) return out
def run_fetcher(entry: Dict[str, Any], mode: Mode) -> protocol.FetcherMessage: """ Entrypoint to obtain data from fetcher objects. """ try: fetcher_type = FetcherType[entry["fetcher_type"]] except KeyError as exc: raise RuntimeError from exc logger.debug("Executing fetcher: %s", entry["fetcher_type"]) try: fetcher_params = entry["fetcher_params"] except KeyError as exc: return protocol.FetcherMessage.error(fetcher_type, exc) try: with CPUTracker() as tracker, fetcher_type.from_json(fetcher_params) as fetcher: raw_data = fetcher.fetch(mode) except Exception as exc: raw_data = result.Error(exc) return protocol.FetcherMessage.from_raw_data( raw_data, tracker.duration, fetcher_type, )
def fetch_all( nodes: Iterable[Tuple[HostName, Optional[HostAddress], Sequence[Source]]], *, max_cachefile_age: int, host_config: HostConfig, ) -> Iterator[FetcherMessage]: console.verbose("%s+%s %s\n", tty.yellow, tty.normal, "Fetching data".upper()) # TODO(ml): It is not clear to me in which case it is possible for the following to hold true # for any source in nodes: # - hostname != source.hostname # - ipaddress != source.ipaddress # If this is impossible, then we do not need the Tuple[HostName, HostAddress, ...]. for _hostname, _ipaddress, sources in nodes: for source in sources: console.vverbose(" Source: %s/%s\n" % (source.source_type, source.fetcher_type)) source.file_cache_max_age = max_cachefile_age with CPUTracker() as tracker: raw_data = source.fetch() yield FetcherMessage.from_raw_data( raw_data, tracker.duration, source.fetcher_type, )
def test_multiple_sources_from_the_same_host( self, hostname, ipaddress, mode, config_cache, host_config, ): sources = [ ProgramSource.ds( hostname, ipaddress, mode=mode, template="", ), TCPSource( hostname, ipaddress, mode=mode, ), ] mhs = MultiHostSections() update_host_sections( mhs, make_nodes( config_cache, host_config, ipaddress, mode=mode, sources=sources, ), max_cachefile_age=0, selected_raw_sections=None, host_config=host_config, fetcher_messages=[ FetcherMessage.from_raw_data( result.OK(source.default_raw_data), L3Stats(CPUTracker()), source.fetcher_type, ) for source in sources ], ) 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_controller_success(self): payload = AgentPayload(69 * b"\0") stats = L3Stats(CPUTracker()) header = FetcherHeader( FetcherType.TCP, PayloadType.AGENT, status=42, payload_length=len(payload), stats_length=len(stats), ) message = FetcherMessage(header, payload, stats) assert make_payload_answer(message) == (b"fetch:SUCCESS: :240 :" + header + payload + stats)
def run_fetcher(entry: Dict[str, Any], mode: Mode) -> FetcherMessage: """ Entrypoint to obtain data from fetcher objects. """ try: fetcher_type = FetcherType[entry["fetcher_type"]] except KeyError as exc: raise RuntimeError from exc log.logger.debug("Executing fetcher: %s", entry["fetcher_type"]) try: fetcher_params = entry["fetcher_params"] except KeyError as exc: stats = L3Stats(CPUTracker()) payload = ErrorPayload(exc) return FetcherMessage( FetcherHeader( fetcher_type, PayloadType.ERROR, status=logging.CRITICAL, payload_length=len(payload), stats_length=len(stats), ), payload, stats, ) try: with CPUTracker() as tracker, fetcher_type.from_json( fetcher_params) as fetcher: raw_data = fetcher.fetch(mode) except Exception as exc: raw_data = result.Error(exc) return FetcherMessage.from_raw_data( raw_data, L3Stats(tracker), fetcher_type, )
def _run_fetchers_from_file(file_name: Path, mode: Mode, timeout: int) -> None: """ Writes to the stdio next data: Count Type Content Action ----- ----- ------- ------ 1 Success Answer Fetcher Blob Send to the checker 0..n Failure Answer Exception of failed fetcher Log 1 Waiting Answer empty End IO *) Fetcher blob contains all answers from all fetcher objects including failed **) file_name is serial/host_name.json ***) timeout is not used at the moment""" with file_name.open() as f: data = json.load(f) fetchers = data["fetchers"] # CONTEXT: AT the moment we call fetcher-executors sequentially (due to different reasons). # Possibilities: # Sequential: slow fetcher may block other fetchers. # Asyncio: every fetcher must be asyncio-aware. This is ok, but even estimation requires time # Threading: some fetcher may be not thread safe(snmp, for example). May be dangerous. # Multiprocessing: CPU and memory(at least in terms of kernel) hungry. Also duplicates # functionality of the Microcore. messages: List[FetcherMessage] = [] with timeout_control(timeout): try: # fill as many messages as possible before timeout exception raised for entry in fetchers: messages.append(run_fetcher(entry, mode)) except MKTimeout as exc: # fill missing entries with timeout errors messages.extend([ _make_fetcher_timeout_message( FetcherType[entry["fetcher_type"]], L3Stats(CPUTracker()), exc, ) for entry in fetchers[len(messages):] ]) log.logger.debug("Produced %d messages:", len(messages)) for message in messages: log.logger.debug(" message: %s", message.header) write_bytes(make_payload_answer(*messages)) for msg in filter( lambda msg: msg.header.payload_type is PayloadType.ERROR, messages, ): log.logger.log(msg.header.status, "Error in %s fetcher: %s", msg.header.fetcher_type.name, msg.raw_data.error)
def _run_fetcher(fetcher: Fetcher, mode: Mode) -> protocol.FetcherMessage: """Entrypoint to obtain data from fetcher objects.""" logger.debug("Fetch from %s", fetcher) with CPUTracker() as tracker: try: with fetcher: raw_data = fetcher.fetch(mode) except Exception as exc: raw_data = result.Error(exc) return protocol.FetcherMessage.from_raw_data( raw_data, tracker.duration, FetcherType.from_fetcher(fetcher), )
def fetch_all( *, sources: Iterable[Source], file_cache_max_age: file_cache.MaxAge, mode: Mode, ) -> Iterator[FetcherMessage]: console.verbose("%s+%s %s\n", tty.yellow, tty.normal, "Fetching data".upper()) for source in sources: console.vverbose(" Source: %s/%s\n" % (source.source_type, source.fetcher_type)) source.file_cache_max_age = file_cache_max_age with CPUTracker() as tracker: raw_data = source.fetch(mode) yield FetcherMessage.from_raw_data( raw_data, tracker.duration, source.fetcher_type, )
def test_one_snmp_source(self, hostname, ipaddress, mode, config_cache, host_config): mhs = MultiHostSections() update_host_sections( mhs, make_nodes( config_cache, host_config, ipaddress, mode=mode, sources=[ SNMPSource.snmp( hostname, ipaddress, mode=mode, ), ], ), max_cachefile_age=0, selected_raw_sections=None, host_config=host_config, fetcher_messages=[ FetcherMessage.from_raw_data( result.OK({}), L3Stats(CPUTracker()), FetcherType.SNMP, ), ], ) 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, cluster, nodes, config_cache, host_config, mode): mhs = MultiHostSections() update_host_sections( mhs, make_nodes( config_cache, host_config, None, mode=mode, sources=(), ), max_cachefile_age=0, selected_raw_sections=None, host_config=host_config, fetcher_messages=[ # We do not pass sources explicitly but still append Piggyback. FetcherMessage.from_raw_data( result.OK(b""), L3Stats(CPUTracker()), FetcherType.PIGGYBACK, ), ], ) 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_nonsnmp_source(self, hostname, ipaddress, mode, config_cache, host_config, source): source = source(hostname, ipaddress, mode=mode) assert source.source_type is SourceType.HOST mhs = MultiHostSections() update_host_sections( mhs, make_nodes( config_cache, host_config, ipaddress, mode=mode, sources=[source], ), max_cachefile_age=0, selected_raw_sections=None, host_config=host_config, fetcher_messages=[ FetcherMessage.from_raw_data( result.OK(source.default_raw_data), L3Stats(CPUTracker()), source.fetcher_type, ), ], ) 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 tracker(self): return CPUTracker()
def do_check( hostname: HostName, ipaddress: Optional[HostAddress], *, # The following arguments *must* remain optional for Nagios and the `DiscoCheckExecutor`. # See Also: `cmk.base.discovery.check_discovery()` fetcher_messages: Sequence[FetcherMessage] = (), run_only_plugin_names: Optional[Set[CheckPluginName]] = None, selected_sections: checkers.SectionNameCollection = checkers.NO_SELECTION, submit_to_core: bool = True, show_perfdata: bool = False, ) -> Tuple[int, List[ServiceDetails], List[ServiceAdditionalDetails], List[str]]: console.verbose("Checkmk 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() mode = checkers.Mode.CHECKING if selected_sections is checkers.NO_SELECTION else checkers.Mode.FORCE_SECTIONS status: ServiceState = 0 infotexts: List[ServiceDetails] = [] long_infotexts: List[ServiceAdditionalDetails] = [] perfdata: List[str] = [] try: license_usage.try_history_update() # 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) # When monitoring Checkmk clusters, the cluster nodes are responsible for fetching all # information from the monitored host and cache the result for the cluster checks to be # performed on the cached information. # # This means that in case of SNMP nodes, they need to take the clustered services of the # node into account, fetch the needed sections and cache them for the cluster host. # # But later, when checking the node services, the node has to only deal with the unclustered # services. # # TODO: clean this up. The fetched sections are computed in the checkers # _make_configured_snmp_sections now. # belongs_to_cluster = len(config_cache.clusters_of(hostname)) > 0 services_to_fetch = _get_services_to_fetch( host_name=hostname, belongs_to_cluster=belongs_to_cluster, config_cache=config_cache, ) services_to_check = _filter_clustered_services( config_cache=config_cache, host_name=hostname, belongs_to_cluster=belongs_to_cluster, services=services_to_fetch, run_only_plugin_names=run_only_plugin_names, ) nodes = checkers.make_nodes( config_cache, host_config, ipaddress, mode, checkers.make_sources( host_config, ipaddress, mode=mode, selected_sections=selected_sections, ), ) if not fetcher_messages: # Note: `fetch_all(sources)` is almost always called in similar # code in discovery and inventory. The only other exception # is `cmk.base.discovery.check_discovery(...)`. This does # not seem right. fetcher_messages = list( checkers.fetch_all( nodes, max_cachefile_age=host_config.max_cachefile_age, host_config=host_config, )) with CPUTracker() as tracker: mhs = MultiHostSections() result = checkers.update_host_sections( mhs, nodes, max_cachefile_age=host_config.max_cachefile_age, host_config=host_config, fetcher_messages=fetcher_messages, selected_sections=selected_sections, ) num_success, plugins_missing_data = _do_all_checks_on_host( config_cache, host_config, ipaddress, multi_host_sections=mhs, services=services_to_check, submit_to_core=submit_to_core, show_perfdata=show_perfdata, ) if run_only_plugin_names is None: inventory.do_inventory_actions_during_checking_for( config_cache, host_config, ipaddress, multi_host_sections=mhs, ) for source, host_sections in result: source_state, source_output, source_perfdata = source.summarize( host_sections) 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) total_times = tracker.duration for msg in fetcher_messages: total_times += msg.stats.duration infotexts.append("execution time %.1f sec" % total_times.process.elapsed) if config.check_mk_perfdata_with_times: perfdata += [ "execution_time=%.3f" % total_times.process.elapsed, "user_time=%.3f" % total_times.process.user, "system_time=%.3f" % total_times.process.system, "children_user_time=%.3f" % total_times.process.children_user, "children_system_time=%.3f" % total_times.process.children_system, ] summary: DefaultDict[str, Snapshot] = defaultdict(Snapshot.null) for msg in fetcher_messages if fetcher_messages else (): if msg.fetcher_type in ( FetcherType.PIGGYBACK, FetcherType.PROGRAM, FetcherType.SNMP, FetcherType.TCP, ): summary[{ FetcherType.PIGGYBACK: "agent", FetcherType.PROGRAM: "ds", FetcherType.SNMP: "snmp", FetcherType.TCP: "agent", }[msg.fetcher_type]] += msg.stats.duration for phase, duration in summary.items(): perfdata.append("cmk_time_%s=%.3f" % (phase, duration.idle)) else: perfdata.append("execution_time=%.3f" % total_times.process.elapsed) return status, infotexts, long_infotexts, perfdata finally: if _checkresult_file_fd is not None: _close_checkresult_file()
def stats(self): return L3Stats(CPUTracker())
def from_bytes(cls, data: bytes) -> "L3Stats": return L3Stats(CPUTracker.deserialize(json.loads(data.decode("ascii"))["cpu_tracker"]))
def _execute_checkmk_checks( *, hostname: HostName, ipaddress: Optional[HostAddress], fetcher_messages: Sequence[FetcherMessage] = (), run_plugin_names: Container[CheckPluginName], selected_sections: SectionNameCollection, dry_run: bool, show_perfdata: bool, ) -> ActiveCheckResult: config_cache = config.get_config_cache() host_config = config_cache.get_host_config(hostname) exit_spec = host_config.exit_code_spec() mode = Mode.CHECKING if selected_sections is NO_SELECTION else Mode.FORCE_SECTIONS try: license_usage.try_history_update() # 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 = config.lookup_ip_address(host_config) services = config.resolve_service_dependencies( host_name=hostname, services=sorted( check_table.get_check_table(hostname).values(), key=lambda service: service.description, ), ) with CPUTracker() as tracker: broker, source_results = make_broker( config_cache=config_cache, host_config=host_config, ip_address=ipaddress, mode=mode, selected_sections=selected_sections, file_cache_max_age=host_config.max_cachefile_age, fetcher_messages=fetcher_messages, force_snmp_cache_refresh=False, on_scan_error=OnError.RAISE, ) num_success, plugins_missing_data = check_host_services( config_cache=config_cache, host_config=host_config, ipaddress=ipaddress, parsed_sections_broker=broker, services=services, run_plugin_names=run_plugin_names, dry_run=dry_run, show_perfdata=show_perfdata, ) if run_plugin_names is EVERYTHING: inventory.do_inventory_actions_during_checking_for( config_cache, host_config, ipaddress, parsed_sections_broker=broker, ) timed_results = [ *check_sources( source_results=source_results, mode=mode, include_ok_results=True, ), *check_parsing_errors(errors=broker.parsing_errors(), ), *_check_plugins_missing_data( plugins_missing_data, exit_spec, bool(num_success), ), ] return ActiveCheckResult.from_subresults( *timed_results, _timing_results(tracker, fetcher_messages), ) finally: _submit_to_core.finalize()
def test_single_phase(self, set_time): set_time(0.0) with CPUTracker() as tracker: set_time(2.0) assert tracker.duration.run_time == 2.0
def _run_fetchers_from_file( config_path: VersionedConfigPath, host_name: HostName, timeout: int, mode: Mode, ) -> None: """Writes to the stdio next data: Count Answer Content Action ----- ------ ------- ------ 1 Result Fetcher Blob Send to the checker 0..n Log Message to be logged Log 1 End of reply empty End IO """ messages: List[protocol.FetcherMessage] = [] with CPUTracker() as cpu_tracker, Timeout( timeout, message=f'Fetcher for host "{host_name}" timed out after {timeout} seconds', ) as timeout_manager: fetchers = tuple(_parse_config(config_path, host_name)) try: # fill as many messages as possible before timeout exception raised for fetcher in fetchers: messages.append(_run_fetcher(fetcher, mode)) except MKTimeout as exc: # fill missing entries with timeout errors messages.extend( protocol.FetcherMessage.timeout( FetcherType.from_fetcher(fetcher), exc, Snapshot.null(), ) for fetcher in fetchers[len(messages) :] ) if timeout_manager.signaled: messages = _replace_netsnmp_obfuscated_timeout(messages, timeout_manager.message) logger.debug("Produced %d messages", len(messages)) write( protocol.CMCMessage.result_answer( messages, serial=config_path.serial, host_name=host_name, timeout=timeout, duration=cpu_tracker.duration, ) ) for msg in filter( lambda msg: msg.header.payload_type is protocol.PayloadType.ERROR, messages, ): logger.log( msg.header.status, "Error in %s fetcher: %r", msg.header.fetcher_type.name, msg.raw_data.error, ) logger.debug( "".join( traceback.format_exception( msg.raw_data.error.__class__, msg.raw_data.error, msg.raw_data.error.__traceback__, ) ) )
def _execute_checkmk_checks( *, hostname: HostName, ipaddress: Optional[HostAddress], fetched: Sequence[Tuple[Source, FetcherMessage]], run_plugin_names: Container[CheckPluginName], selected_sections: SectionNameCollection, dry_run: bool, show_perfdata: bool, ) -> ActiveCheckResult: config_cache = config.get_config_cache() host_config = config_cache.get_host_config(hostname) exit_spec = host_config.exit_code_spec() try: license_usage.try_history_update() services = config.resolve_service_dependencies( host_name=hostname, services=sorted( check_table.get_check_table(hostname).values(), key=lambda service: service.description, ), ) broker, source_results = make_broker( fetched=fetched, selected_sections=selected_sections, file_cache_max_age=host_config.max_cachefile_age, ) with CPUTracker() as tracker: num_success, plugins_missing_data = check_host_services( config_cache=config_cache, host_config=host_config, ipaddress=ipaddress, parsed_sections_broker=broker, services=services, run_plugin_names=run_plugin_names, dry_run=dry_run, show_perfdata=show_perfdata, ) if run_plugin_names is EVERYTHING: inventory.do_inventory_actions_during_checking_for( config_cache, host_config, parsed_sections_broker=broker, ) timed_results = [ *check_sources( source_results=source_results, include_ok_results=True, ), *check_parsing_errors(errors=broker.parsing_errors(), ), *_check_plugins_missing_data( plugins_missing_data, exit_spec, bool(num_success), ), ] return ActiveCheckResult.from_subresults( *timed_results, _timing_results(tracker.duration, [fetched_entry[1] for fetched_entry in fetched]), ) finally: _submit_to_core.finalize()
def do_check( hostname: HostName, ipaddress: Optional[HostAddress], *, # The following arguments *must* remain optional for Nagios and the `DiscoCheckExecutor`. # See Also: `cmk.base.discovery.check_discovery()` fetcher_messages: Sequence[FetcherMessage] = (), run_plugin_names: Container[CheckPluginName] = EVERYTHING, selected_sections: SectionNameCollection = NO_SELECTION, dry_run: bool = False, show_perfdata: bool = False, ) -> Tuple[int, List[ServiceDetails], List[ServiceAdditionalDetails], List[str]]: console.vverbose("Checkmk 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() mode = Mode.CHECKING if selected_sections is NO_SELECTION else Mode.FORCE_SECTIONS status: ServiceState = 0 infotexts: List[ServiceDetails] = [] long_infotexts: List[ServiceAdditionalDetails] = [] perfdata: List[str] = [] try: license_usage.try_history_update() # 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 = config.lookup_ip_address(host_config) services_to_check = _get_services_to_check( config_cache=config_cache, host_name=hostname, run_plugin_names=run_plugin_names, ) with CPUTracker() as tracker: broker, source_results = make_broker( config_cache=config_cache, host_config=host_config, ip_address=ipaddress, mode=mode, selected_sections=selected_sections, file_cache_max_age=host_config.max_cachefile_age, fetcher_messages=fetcher_messages, force_snmp_cache_refresh=False, on_scan_error="raise", ) num_success, plugins_missing_data = _do_all_checks_on_host( config_cache, host_config, ipaddress, parsed_sections_broker=broker, services=services_to_check, dry_run=dry_run, show_perfdata=show_perfdata, ) if run_plugin_names is EVERYTHING: inventory.do_inventory_actions_during_checking_for( config_cache, host_config, ipaddress, parsed_sections_broker=broker, ) for source, host_sections in source_results: source_state, source_output = source.summarize(host_sections) if source_output != "": status = worst_service_state(status, source_state, default=3) infotexts.append("[%s] %s" % (source.id, source_output)) 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) total_times = tracker.duration for msg in fetcher_messages: total_times += msg.stats.duration infotexts.append("execution time %.1f sec" % total_times.process.elapsed) if config.check_mk_perfdata_with_times: perfdata += [ "execution_time=%.3f" % total_times.process.elapsed, "user_time=%.3f" % total_times.process.user, "system_time=%.3f" % total_times.process.system, "children_user_time=%.3f" % total_times.process.children_user, "children_system_time=%.3f" % total_times.process.children_system, ] summary: DefaultDict[str, Snapshot] = defaultdict(Snapshot.null) for msg in fetcher_messages if fetcher_messages else (): if msg.fetcher_type in ( FetcherType.PIGGYBACK, FetcherType.PROGRAM, FetcherType.SNMP, FetcherType.TCP, ): summary[{ FetcherType.PIGGYBACK: "agent", FetcherType.PROGRAM: "ds", FetcherType.SNMP: "snmp", FetcherType.TCP: "agent", }[msg.fetcher_type]] += msg.stats.duration for phase, duration in summary.items(): perfdata.append("cmk_time_%s=%.3f" % (phase, duration.idle)) else: perfdata.append("execution_time=%.3f" % total_times.process.elapsed) return status, infotexts, long_infotexts, perfdata finally: _submit_to_core.finalize()
def test_get_host_sections_cluster(mode, 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 check(_, *args, **kwargs): return result.OK(AgentHostSections(sections={section_name: [[str(section_name)]]})) monkeypatch.setattr( ip_lookup, "lookup_ip_address", lookup_ip_address, ) monkeypatch.setattr( _checkers, "_make_piggybacked_sections", make_piggybacked_sections, ) monkeypatch.setattr( Source, "parse", check, ) 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 = MultiHostSections() sources = make_sources(host_config, address, mode=mode) update_host_sections( mhs, make_nodes( config_cache, host_config, address, mode=mode, sources=sources, ), max_cachefile_age=host_config.max_cachefile_age, selected_raw_sections=None, host_config=host_config, fetcher_messages=[ FetcherMessage.from_raw_data( result.OK(source.default_raw_data), L3Stats(CPUTracker()), source.fetcher_type, ) for source in sources ], ) 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 stats_length(self): return len(L3Stats(CPUTracker()))