Beispiel #1
0
    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
Beispiel #2
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
Beispiel #3
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
Beispiel #4
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
Beispiel #5
0
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,
    )
Beispiel #6
0
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,
            )
Beispiel #7
0
    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"]])
Beispiel #8
0
 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)
Beispiel #9
0
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,
    )
Beispiel #10
0
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)
Beispiel #11
0
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),
    )
Beispiel #12
0
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,
        )
Beispiel #13
0
    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"]]
Beispiel #14
0
    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
Beispiel #15
0
    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"]]
Beispiel #16
0
 def tracker(self):
     return CPUTracker()
Beispiel #17
0
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()
Beispiel #18
0
 def stats(self):
     return L3Stats(CPUTracker())
Beispiel #19
0
 def from_bytes(cls, data: bytes) -> "L3Stats":
     return L3Stats(CPUTracker.deserialize(json.loads(data.decode("ascii"))["cpu_tracker"]))
Beispiel #20
0
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()
Beispiel #21
0
    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
Beispiel #22
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__,
                )
            )
        )
Beispiel #23
0
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()
Beispiel #24
0
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()
Beispiel #25
0
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
Beispiel #26
0
 def stats_length(self):
     return len(L3Stats(CPUTracker()))