Пример #1
0
def _find_host_candidates(
    broker: ParsedSectionsBroker,
    preliminary_candidates: List[checking_classes.CheckPlugin],
    parsed_sections_of_interest: Set[ParsedSectionName],
) -> Set[CheckPluginName]:

    available_parsed_sections = broker.filter_available(
        parsed_sections_of_interest,
        SourceType.HOST,
    )

    return {
        plugin.name
        for plugin in preliminary_candidates
        # *filter out* all names of management only check plugins
        if not plugin.name.is_management_name() and any(
            section in available_parsed_sections
            for section in plugin.sections)
    }
Пример #2
0
def _discover_host_labels_for_source_type(
    *,
    host_key: HostKey,
    parsed_sections_broker: ParsedSectionsBroker,
    on_error: OnError,
) -> Mapping[str, HostLabel]:

    host_labels = {}
    try:
        parsed_results = parsed_sections_broker.all_parsing_results(host_key)

        console.vverbose("Trying host label discovery with: %s\n" %
                         ", ".join(str(r.section.name) for r in parsed_results))
        for (section_data, _cache_info), section_plugin in parsed_results:

            kwargs = {'section': section_data}

            host_label_params = config.get_host_label_parameters(host_key.hostname, section_plugin)
            if host_label_params is not None:
                kwargs["params"] = host_label_params

            try:
                for label in section_plugin.host_label_function(**kwargs):
                    console.vverbose(f"  {label.name}: {label.value} ({section_plugin.name})\n")
                    host_labels[label.name] = HostLabel(
                        label.name,
                        label.value,
                        section_plugin.name,
                    )
            except (KeyboardInterrupt, MKTimeout):
                raise
            except Exception as exc:
                if on_error is OnError.RAISE:
                    raise
                if on_error is OnError.WARN:
                    console.error(
                        f"Host label discovery of '{section_plugin.name}' failed: {exc}\n")

    except KeyboardInterrupt:
        raise MKGeneralException("Interrupted by Ctrl-C.")

    return host_labels
Пример #3
0
    def test_multiple_sources_from_different_hosts(self, hostname, ipaddress, mode, config_cache, host_config):
        sources = [
            ProgramSource.ds(hostname + "0", ipaddress, mode=mode, template=""),
            TCPSource(hostname + "1", ipaddress, mode=mode),
            TCPSource(hostname + "2", ipaddress, mode=mode),
        ]

        nodes = make_nodes(
            config_cache,
            host_config,
            ipaddress,
            mode=mode,
            sources=sources,
        )

        broker = ParsedSectionsBroker(_collect_host_sections(
            nodes=nodes,
            file_cache_max_age=0,
            fetcher_messages=[
                FetcherMessage.from_raw_data(
                    result.OK(source.default_raw_data),
                    Snapshot.null(),
                    source.fetcher_type,
                )
                for _h, _i, sources in nodes for source in sources
            ],
            selected_sections=NO_SELECTION,
        )[0])
        assert len(broker) == 1

        key = HostKey(hostname, ipaddress, SourceType.HOST)
        assert key in broker

        section = broker[key]

        assert len(section.sections) == len(sources)
        for source in sources:
            # yapf: disable
            assert (
                section.sections[SectionName("section_name_%s" % source.hostname)]
                == [["section_content"]])
Пример #4
0
def test_get_section_content(hostname, host_entries, cluster_node_keys, expected_result):

    parsed_sections_broker = ParsedSectionsBroker({
        HostKey(nodename, "127.0.0.1",
                SourceType.HOST): SectionsParser(host_sections=AgentHostSections(
                    sections={SectionName("section_plugin_name"): node_section_content}))
        for nodename, node_section_content in host_entries
    })

    mhs = _MultiHostSections(parsed_sections_broker)

    section_content = mhs.get_section_content(
        HostKey(hostname, "127.0.0.1", SourceType.HOST),
        HOST_ONLY,
        "section_plugin_name",
        False,
        cluster_node_keys=cluster_node_keys,
        check_legacy_info={},  # only for parse_function lookup, not needed in this test
    )
    assert expected_result == section_content

    section_content = mhs.get_section_content(
        HostKey(hostname, "127.0.0.1", SourceType.HOST),
        HOST_PRECEDENCE,
        "section_plugin_name",
        False,
        cluster_node_keys=cluster_node_keys,
        check_legacy_info={},  # only for parse_function lookup, not needed in this test
    )
    assert expected_result == section_content

    section_content = mhs.get_section_content(
        HostKey(hostname, "127.0.0.1", SourceType.MANAGEMENT),
        MGMT_ONLY,
        "section_plugin_name",
        False,
        cluster_node_keys=None if cluster_node_keys is None else
        [HostKey(hn, ip, SourceType.MANAGEMENT) for (hn, ip, _st) in cluster_node_keys],
        check_legacy_info={},  # only for parse_function lookup, not needed in this test
    )
    assert section_content is None
Пример #5
0
def _find_mgmt_candidates(
    broker: ParsedSectionsBroker,
    preliminary_candidates: List[checking_classes.CheckPlugin],
    parsed_sections_of_interest: Set[ParsedSectionName],
) -> Set[CheckPluginName]:

    available_parsed_sections = {
        s.parsed_section_name
        for s in broker.determine_applicable_sections(
            parsed_sections_of_interest,
            SourceType.MANAGEMENT,
        )
    }

    return {
        # *create* all management only names of the plugins
        plugin.name.create_management_name()
        for plugin in preliminary_candidates
        if any(section in available_parsed_sections
               for section in plugin.sections)
    }
Пример #6
0
    def test_one_snmp_source(self, hostname, ipaddress, mode, config_cache,
                             host_config):
        broker = ParsedSectionsBroker(
            _collect_host_sections(
                nodes=make_nodes(
                    config_cache,
                    host_config,
                    ipaddress,
                    mode=mode,
                    sources=[
                        SNMPSource.snmp(
                            hostname,
                            ipaddress,
                            mode=mode,
                            selected_sections=NO_SELECTION,
                            force_cache_refresh=False,
                            on_scan_error="raise",
                        ),
                    ],
                ),
                file_cache_max_age=0,
                fetcher_messages=[
                    FetcherMessage.from_raw_data(
                        result.OK({}),
                        Snapshot.null(),
                        FetcherType.SNMP,
                    ),
                ],
                selected_sections=NO_SELECTION,
            )[0])
        assert len(broker) == 1

        key = HostKey(hostname, ipaddress, SourceType.HOST)
        assert key in broker

        section = broker[key]

        assert len(section.sections) == 1
        assert section.sections[SectionName("section_name_%s" %
                                            hostname)] == [["section_content"]]
Пример #7
0
def test_get_section_cluster_kwargs(required_sections, expected_result):

    node1_sections = AgentHostSections(
        sections={
            SectionName("one"): NODE_1,
            SectionName("two"): NODE_1,
            SectionName("three"): NODE_1
        })

    node2_sections = AgentHostSections(sections={
        SectionName("two"): NODE_2,
        SectionName("three"): NODE_2,
    })

    parsed_sections_broker = ParsedSectionsBroker({
        HostKey("node1", "127.0.0.1", SourceType.HOST): (
            ParsedSectionsResolver(section_plugins=[
                SECTION_ONE, SECTION_TWO, SECTION_THREE, SECTION_FOUR
            ], ),
            SectionsParser(host_sections=node1_sections),
        ),
        HostKey("node2", "127.0.0.1", SourceType.HOST): (
            ParsedSectionsResolver(section_plugins=[
                SECTION_ONE, SECTION_TWO, SECTION_THREE, SECTION_FOUR
            ], ),
            SectionsParser(host_sections=node2_sections),
        ),
    })

    kwargs = get_section_cluster_kwargs(
        parsed_sections_broker,
        [
            HostKey("node1", "127.0.0.1", SourceType.HOST),
            HostKey("node2", "127.0.0.1", SourceType.HOST),
        ],
        [ParsedSectionName(n) for n in required_sections],
    )

    assert expected_result == kwargs
Пример #8
0
    def test_no_sources(self, cluster, nodes, config_cache, host_config, mode):
        made_nodes = make_nodes(
            config_cache,
            host_config,
            None,
            mode=mode,
            sources=(),
        )

        broker = ParsedSectionsBroker(_collect_host_sections(
            nodes=made_nodes,
            file_cache_max_age=0,
            fetcher_messages=[
                # We do not pass sources explicitly but still append Piggyback.
                FetcherMessage.from_raw_data(
                    result.OK(AgentRawData(b"")),
                    Snapshot.null(),
                    FetcherType.PIGGYBACK,
                ) for _n in made_nodes
            ],
            selected_sections=NO_SELECTION,
        )[0])
        assert len(broker) == len(nodes)

        key_clu = HostKey(cluster, None, SourceType.HOST)
        assert key_clu not in broker

        for hostname, addr in nodes.items():
            key = HostKey(hostname, addr, SourceType.HOST)
            assert key in broker

            section = broker[key]
            # yapf: disable
            assert (section.sections[SectionName("section_name_%s" % hostname)]
                    == [["section_content_%s" % hostname]])
            assert not section.cache_info
            assert not section.piggybacked_raw_data
Пример #9
0
def test__find_candidates():
    broker = ParsedSectionsBroker({
        # we just care about the keys here, content set to arbitrary values that can be parsed.
        # section names are chosen arbitrarily.
        HostKey("test_node", "1.2.3.4", SourceType.HOST):
        SectionsParser(
            host_sections=AgentHostSections({
                SectionName("kernel"): [],  # host only
                SectionName("uptime"): [['123']],  # host & mgmt
            }), ),
        HostKey("test_node", "1.2.3.4", SourceType.MANAGEMENT):
        SectionsParser(
            host_sections=SNMPHostSections({
                # host & mgmt:
                SectionName("uptime"): [['123']],  # type: ignore[dict-item]
                # mgmt only:
                SectionName("liebert_fans"):
                [[['Fan', '67', 'umin']]],  # type: ignore[dict-item]
                # is already mgmt_ prefixed:
                SectionName("mgmt_snmp_info"):
                [[['a', 'b', 'c', 'd']]],  # type: ignore[dict-item]
            }), ),
    })

    preliminary_candidates = list(
        agent_based_register.iter_all_check_plugins())
    parsed_sections_of_interest = {
        parsed_section_name
        for plugin in preliminary_candidates
        for parsed_section_name in plugin.sections
    }

    assert discovery._discovered_services._find_host_candidates(
        broker,
        preliminary_candidates,
        parsed_sections_of_interest,
    ) == {
        CheckPluginName('docker_container_status_uptime'),
        CheckPluginName("kernel"),
        CheckPluginName('kernel_performance'),
        CheckPluginName('kernel_util'),
        CheckPluginName("uptime"),
    }

    assert discovery._discovered_services._find_mgmt_candidates(
        broker,
        preliminary_candidates,
        parsed_sections_of_interest,
    ) == {
        CheckPluginName('mgmt_docker_container_status_uptime'),
        CheckPluginName("mgmt_liebert_fans"),
        CheckPluginName("mgmt_uptime"),
    }

    assert discovery._discovered_services._find_candidates(
        broker,
        run_plugin_names=EVERYTHING,
    ) == {
        CheckPluginName('docker_container_status_uptime'),
        CheckPluginName("kernel"),
        CheckPluginName('kernel_performance'),
        CheckPluginName('kernel_util'),
        CheckPluginName('mgmt_docker_container_status_uptime'),
        CheckPluginName("mgmt_liebert_fans"),
        CheckPluginName("mgmt_uptime"),
        CheckPluginName("uptime"),
    }
Пример #10
0
def get_aggregated_result(
    parsed_sections_broker: ParsedSectionsBroker,
    host_config: config.HostConfig,
    ipaddress: Optional[HostAddress],
    service: Service,
    plugin: Optional[checking_classes.CheckPlugin],
    params_function: Callable[[], Parameters],
    *,
    value_store_manager: item_state.ValueStoreManager,
) -> AggregatedResult:
    """Run the check function and aggregate the subresults

    This function is also called during discovery.
    """
    if plugin is None:
        return AggregatedResult(
            submit=True,
            data_received=True,
            result=CHECK_NOT_IMPLEMENTED,
            cache_info=None,
        )

    check_function = (plugin.cluster_check_function
                      if host_config.is_cluster else plugin.check_function)

    source_type = (SourceType.MANAGEMENT
                   if service.check_plugin_name.is_management_name() else SourceType.HOST)

    config_cache = config.get_config_cache()

    kwargs = {}
    try:
        kwargs = parsed_sections_broker.get_section_cluster_kwargs(
            config_cache.get_clustered_service_node_keys(
                host_config.hostname,
                source_type,
                service.description,
            ) or [],
            plugin.sections,
        ) if host_config.is_cluster else parsed_sections_broker.get_section_kwargs(
            HostKey(host_config.hostname, ipaddress, source_type),
            plugin.sections,
        )

        if not kwargs and not service.check_plugin_name.is_management_name():
            # in 1.6 some plugins where discovered for management boards, but with
            # the regular host plugins name. In this case retry with the source type
            # forced to MANAGEMENT:
            kwargs = parsed_sections_broker.get_section_cluster_kwargs(
                config_cache.get_clustered_service_node_keys(
                    host_config.hostname,
                    SourceType.MANAGEMENT,
                    service.description,
                ) or [],
                plugin.sections,
            ) if host_config.is_cluster else parsed_sections_broker.get_section_kwargs(
                HostKey(host_config.hostname, ipaddress, SourceType.MANAGEMENT),
                plugin.sections,
            )

        if not kwargs:  # no data found
            return AggregatedResult(
                submit=False,
                data_received=False,
                result=RECEIVED_NO_DATA,
                cache_info=None,
            )

        if service.item is not None:
            kwargs["item"] = service.item

        if plugin.check_default_parameters is not None:
            kwargs["params"] = params_function()

        with plugin_contexts.current_host(host_config.hostname), \
            plugin_contexts.current_service(service), \
            value_store_manager.namespace(service.id()):
            result = _aggregate_results(check_function(**kwargs))

    except (item_state.MKCounterWrapped, checking_classes.IgnoreResultsError) as e:
        msg = str(e) or "No service summary available"
        return AggregatedResult(
            submit=False,
            data_received=True,
            result=(0, msg, []),
            cache_info=None,
        )

    except MKTimeout:
        raise

    except Exception:
        if cmk.utils.debug.enabled():
            raise
        table = check_table.get_check_table(host_config.hostname, skip_autochecks=True)
        result = 3, cmk.base.crash_reporting.create_check_crash_dump(
            host_name=host_config.hostname,
            service_name=service.description,
            plugin_name=service.check_plugin_name,
            plugin_kwargs=kwargs,
            is_manual=service.id() in table,
        ), []

    return AggregatedResult(
        submit=True,
        data_received=True,
        result=result,
        cache_info=parsed_sections_broker.get_cache_info(plugin.sections),
    )
Пример #11
0
def _realhost_scenario(monkeypatch):
    hostname = "test-realhost"
    ipaddress = "1.2.3.4"
    ts = Scenario().add_host(hostname, ipaddress=ipaddress)
    ts.set_ruleset("inventory_df_rules", [{
        'value': {
            'ignore_fs_types': ['tmpfs', 'nfs', 'smbfs', 'cifs', 'iso9660'],
            'never_ignore_mountpoints': ['~.*/omd/sites/[^/]+/tmp$']
        },
        'condition': {
            'host_labels': {
                'cmk/check_mk_server': 'yes'
            }
        }
    }])
    ts.apply(monkeypatch)

    def fake_lookup_ip_address(*_a, **_kw):
        return ipaddress

    monkeypatch.setattr(ip_lookup, "lookup_ip_address", fake_lookup_ip_address)

    DiscoveredHostLabelsStore(hostname).save({
        'existing_label': {
            'plugin_name': 'foo',
            'value': 'bar',
        },
        'another_label': {
            'plugin_name': 'labels',
            'value': 'true',
        }
    })

    broker = ParsedSectionsBroker({
        HostKey(hostname=hostname,
                ipaddress=ipaddress,
                source_type=SourceType.HOST):
        AgentHostSections(
            sections={
                SectionName("labels"): [
                    [
                        '{"cmk/check_mk_server":"yes"}',
                    ],
                ],
                SectionName("df"): [
                    [
                        '/dev/sda1',
                        'vfat',
                        '523248',
                        '3668',
                        '519580',
                        '1%',
                        '/boot/test-efi',
                    ],
                    [
                        'tmpfs',
                        'tmpfs',
                        '8152916',
                        '244',
                        '8152672',
                        '1%',
                        '/opt/omd/sites/test-heute/tmp',
                    ],
                ],
            })
    })

    return RealHostScenario(hostname, ipaddress, broker)
Пример #12
0
def check_discovery(
    host_name: HostName,
    ipaddress: Optional[HostAddress],
    *,
    # The next argument *must* remain optional for the DiscoCheckExecutor.
    #   See Also: `cmk.base.checking.do_check()`.
    fetcher_messages: Sequence[FetcherMessage] = (),
) -> Tuple[int, List[str], List[str], List[Tuple]]:

    # Note: '--cache' is set in core_cmc, nagios template or even on CL and means:
    # 1. use caches as default:
    #    - Set FileCacheFactory.maybe = True (set max_cachefile_age, else 0)
    #    - Set FileCacheFactory.use_outdated = True
    # 2. Then these settings are used to read cache file or not

    config_cache = config.get_config_cache()
    host_config = config_cache.get_host_config(host_name)
    discovery_parameters = DiscoveryParameters(
        on_error="raise",
        load_labels=True,
        save_labels=False,
        only_host_labels=False,
    )

    params = host_config.discovery_check_parameters
    if params is None:
        params = host_config.default_discovery_check_parameters()

    # In case of keepalive discovery we always have an ipaddress. When called as non keepalive
    # ipaddress is always None
    if ipaddress is None and not host_config.is_cluster:
        ipaddress = config.lookup_ip_address(host_config)

    nodes = sources.make_nodes(
        config_cache,
        host_config,
        ipaddress,
        Mode.DISCOVERY,
        sources.make_sources(host_config, ipaddress, mode=Mode.DISCOVERY),
    )
    use_caches = cmk.core_helpers.cache.FileCacheFactory.maybe
    max_cachefile_age = config.discovery_max_cachefile_age() if use_caches else 0
    if not fetcher_messages:
        # Note: *Not* calling `fetch_all(sources)` here is probably buggy.
        #       Also See: `cmk.base.checking.do_check()`
        fetcher_messages = list(
            sources.fetch_all(
                nodes,
                max_cachefile_age=max_cachefile_age,
                host_config=host_config,
            ))

    parsed_sections_broker = ParsedSectionsBroker()
    result = sources.update_host_sections(
        parsed_sections_broker,
        nodes,
        max_cachefile_age=max_cachefile_age,
        host_config=host_config,
        fetcher_messages=fetcher_messages,
        selected_sections=NO_SELECTION,
    )

    services, host_label_discovery_result = _get_host_services(
        host_config,
        ipaddress,
        parsed_sections_broker,
        discovery_parameters,
    )

    status, infotexts, long_infotexts, perfdata, need_rediscovery = _aggregate_subresults(
        _check_service_lists(host_name, services, params),
        _check_host_labels(host_label_discovery_result, params),
        _check_data_sources(result),
    )

    if need_rediscovery:
        if host_config.is_cluster and host_config.nodes:
            for nodename in host_config.nodes:
                _set_rediscovery_flag(nodename)
        else:
            _set_rediscovery_flag(host_name)
        infotexts.append(u"rediscovery scheduled")

    return status, infotexts, long_infotexts, perfdata
Пример #13
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 fake_lookup_ip_address(host_config, family=None):
        return hosts[host_config.hostname]

    def check(_, *args, **kwargs):
        return result.OK(AgentHostSections(sections={section_name: [[str(section_name)]]}))

    monkeypatch.setattr(
        config,
        "lookup_ip_address",
        fake_lookup_ip_address,
    )
    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())

    nodes = make_nodes(
        config_cache,
        host_config,
        address,
        mode=mode,
        sources=make_sources(host_config, address, mode=mode)
    )

    broker = ParsedSectionsBroker(_collect_host_sections(
        nodes=nodes,
        file_cache_max_age=host_config.max_cachefile_age,
        fetcher_messages=[
                FetcherMessage.from_raw_data(
                    result.OK(source.default_raw_data),
                    Snapshot.null(),
                    source.fetcher_type,
                )
                for _h, _i, sources in nodes for source in sources
            ],
        selected_sections=NO_SELECTION,
    )[0])
    assert len(broker) == 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 broker
        section = broker[key]
        assert len(section.sections) == 1
        assert next(iter(section.sections)) == section_name
        assert not section.cache_info
        assert not section.piggybacked_raw_data
Пример #14
0
def get_aggregated_result(
    parsed_sections_broker: ParsedSectionsBroker,
    host_config: config.HostConfig,
    ipaddress: Optional[HostAddress],
    service: Service,
    plugin: Optional[checking_classes.CheckPlugin],
    # missleading. These are prams that *may* be *partially* time specific
    timespecific_parameters: LegacyCheckParameters,
    *,
    value_store_manager: value_store.ValueStoreManager,
    persist_value_store_changes: bool,
) -> AggregatedResult:
    """Run the check function and aggregate the subresults

    This function is also called during discovery.
    """
    if plugin is None:
        return AggregatedResult(
            submit=True,
            data_received=True,
            result=CHECK_NOT_IMPLEMENTED,
            cache_info=None,
        )

    config_cache = config.get_config_cache()
    check_function = (
        _cluster_modes.get_cluster_check_function(
            *config_cache.get_clustered_service_configuration(
                host_config.hostname,
                service.description,
            ),
            plugin=plugin,
            service_id=service.id(),
            persist_value_store_changes=persist_value_store_changes,
        )
        if host_config.is_cluster
        else plugin.check_function
    )
    source_type = (
        SourceType.MANAGEMENT if service.check_plugin_name.is_management_name() else SourceType.HOST
    )
    try:
        kwargs = (
            get_section_cluster_kwargs(
                parsed_sections_broker,
                config_cache.get_clustered_service_node_keys(
                    host_config.hostname,
                    source_type,
                    service.description,
                )
                or [],
                plugin.sections,
            )
            if host_config.is_cluster
            else get_section_kwargs(
                parsed_sections_broker,
                HostKey(host_config.hostname, ipaddress, source_type),
                plugin.sections,
            )
        )
        if not kwargs and not service.check_plugin_name.is_management_name():
            # in 1.6 some plugins where discovered for management boards, but with
            # the regular host plugins name. In this case retry with the source type
            # forced to MANAGEMENT:
            kwargs = (
                get_section_cluster_kwargs(
                    parsed_sections_broker,
                    config_cache.get_clustered_service_node_keys(
                        host_config.hostname,
                        SourceType.MANAGEMENT,
                        service.description,
                    )
                    or [],
                    plugin.sections,
                )
                if host_config.is_cluster
                else get_section_kwargs(
                    parsed_sections_broker,
                    HostKey(host_config.hostname, ipaddress, SourceType.MANAGEMENT),
                    plugin.sections,
                )
            )
        if not kwargs:  # no data found
            return AggregatedResult(
                submit=False,
                data_received=False,
                result=RECEIVED_NO_DATA,
                cache_info=None,
            )

        kwargs = {
            **kwargs,
            **({} if service.item is None else {"item": service.item}),
            **(
                {}
                if plugin.check_default_parameters is None
                else {"params": _final_read_only_check_parameters(timespecific_parameters)}
            ),
        }
        with plugin_contexts.current_host(host_config.hostname), plugin_contexts.current_service(
            service
        ), value_store_manager.namespace(service.id()):
            result = _aggregate_results(check_function(**kwargs))

    except (item_state.MKCounterWrapped, checking_classes.IgnoreResultsError) as e:
        msg = str(e) or "No service summary available"
        return AggregatedResult(
            submit=False,
            data_received=True,
            result=(0, msg, []),
            cache_info=None,
        )
    except MKTimeout:
        raise
    except Exception:
        if cmk.utils.debug.enabled():
            raise
        table = check_table.get_check_table(host_config.hostname, skip_autochecks=True)
        result = (
            3,
            cmk.base.crash_reporting.create_check_crash_dump(
                host_name=host_config.hostname,
                service_name=service.description,
                plugin_name=service.check_plugin_name,
                plugin_kwargs=globals().get("kwargs", {}),
                is_manual=service.id() in table,
            ),
            [],
        )

    return AggregatedResult(
        submit=True,
        data_received=True,
        result=result,
        cache_info=parsed_sections_broker.get_cache_info(plugin.sections),
    )
Пример #15
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: SectionNameCollection = NO_SELECTION,
    dry_run: bool = False,
    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 = 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)

        # 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 = sources.make_nodes(
            config_cache,
            host_config,
            ipaddress,
            mode,
            sources.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(
                sources.fetch_all(
                    nodes,
                    max_cachefile_age=host_config.max_cachefile_age,
                    host_config=host_config,
                ))

        with CPUTracker() as tracker:
            broker = ParsedSectionsBroker()
            result = sources.update_host_sections(
                broker,
                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,
                parsed_sections_broker=broker,
                services=services_to_check,
                dry_run=dry_run,
                show_perfdata=show_perfdata,
            )

            if run_only_plugin_names is None:
                inventory.do_inventory_actions_during_checking_for(
                    config_cache,
                    host_config,
                    ipaddress,
                    parsed_sections_broker=broker,
                )

            for source, host_sections in result:
                source_state, source_output = source.summarize(host_sections)
                if source_output != "":
                    status = max(status, source_state)
                    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()
Пример #16
0
def _cluster_scenario(monkeypatch):
    hostname = "test-clusterhost"
    ipaddress = "1.2.3.4"
    node1_hostname = 'test-node1'
    node2_hostname = 'test-node2'

    def fake_lookup_ip_address(*_a, **_kw):
        return ipaddress

    monkeypatch.setattr(ip_lookup, "lookup_ip_address", fake_lookup_ip_address)

    ts = Scenario()
    ts.add_host(node1_hostname)
    ts.add_host(node2_hostname)
    ts.add_cluster(hostname, nodes=[node1_hostname, node2_hostname])
    ts.set_ruleset("inventory_df_rules", [{
        'value': {
            'ignore_fs_types': ['tmpfs', 'nfs', 'smbfs', 'cifs', 'iso9660'],
            'never_ignore_mountpoints': ['~.*/omd/sites/[^/]+/tmp$']
        },
        'condition': {
            'host_labels': {
                'cmk/check_mk_server': 'yes'
            }
        }
    }])
    ts.set_ruleset("clustered_services", [([], [node1_hostname], ['fs_'])])
    host_config = ts.apply(monkeypatch).get_host_config(hostname)

    DiscoveredHostLabelsStore(node1_hostname).save({
        'node1_existing_label': {
            'plugin_name': 'node1_plugin',
            'value': 'true',
        }
    })

    DiscoveredHostLabelsStore(hostname).save({
        'existing_label': {
            'plugin_name': 'foo',
            'value': 'bar',
        },
        'another_label': {
            'plugin_name': 'labels',
            'value': 'true',
        }
    })

    broker = ParsedSectionsBroker({
        HostKey(hostname=node1_hostname,
                ipaddress=ipaddress,
                source_type=SourceType.HOST):
        SectionsParser(host_sections=AgentHostSections(sections={
            SectionName("labels"): [
                [
                    '{"cmk/check_mk_server":"yes"}',
                ],
            ],
            SectionName("df"): [
                [
                    '/dev/sda1',
                    'vfat',
                    '523248',
                    '3668',
                    '519580',
                    '1%',
                    '/boot/test-efi',
                ],
                [
                    'tmpfs',
                    'tmpfs',
                    '8152916',
                    '244',
                    '8152672',
                    '1%',
                    '/opt/omd/sites/test-heute/tmp',
                ],
            ],
        }, ), ),
        HostKey(hostname=node2_hostname,
                ipaddress=ipaddress,
                source_type=SourceType.HOST):
        SectionsParser(host_sections=AgentHostSections(sections={
            SectionName("labels"): [
                [
                    '{"node2_live_label":"true"}',
                ],
            ],
            SectionName("df"): [
                [
                    '/dev/sda1',
                    'vfat',
                    '523248',
                    '3668',
                    '519580',
                    '1%',
                    '/boot/test-efi',
                ],
                [
                    'tmpfs',
                    'tmpfs',
                    '8152916',
                    '244',
                    '8152672',
                    '1%',
                    '/opt/omd/sites/test-heute2/tmp',
                ],
            ],
        }, ), ),
    })

    return ClusterScenario(
        host_config,
        ipaddress,
        broker,
        node1_hostname,
        node2_hostname,
    )
Пример #17
0
def _discover_host_labels_for_source_type(
    *,
    host_key: HostKey,
    parsed_sections_broker: ParsedSectionsBroker,
    discovery_parameters: DiscoveryParameters,
) -> Mapping[str, HostLabel]:

    try:
        host_data = parsed_sections_broker[host_key]
    except KeyError:
        return {}

    host_labels = {}
    try:
        # We do *not* process all available raw sections. Instead we see which *parsed*
        # sections would result from them, and then process those.
        parse_sections = {
            agent_based_register.get_section_plugin(rs).parsed_section_name
            for rs in host_data.sections
        }
        applicable_sections = parsed_sections_broker.determine_applicable_sections(
            parse_sections,
            host_key.source_type,
        )

        console.vverbose("Trying host label discovery with: %s\n" %
                         ", ".join(str(s.name) for s in applicable_sections))
        for section_plugin in _sort_sections_by_label_priority(
                applicable_sections):

            kwargs = {
                'section':
                parsed_sections_broker.get_parsed_section(
                    host_key, section_plugin.parsed_section_name),
            }

            host_label_params = config.get_host_label_parameters(
                host_key.hostname, section_plugin)
            if host_label_params is not None:
                kwargs["params"] = host_label_params

            try:
                for label in section_plugin.host_label_function(**kwargs):
                    console.vverbose(
                        f"  {label.name}: {label.value} ({section_plugin.name})\n"
                    )
                    host_labels[label.name] = HostLabel(
                        label.name,
                        label.value,
                        section_plugin.name,
                    )
            except (KeyboardInterrupt, MKTimeout):
                raise
            except Exception as exc:
                if cmk.utils.debug.enabled(
                ) or discovery_parameters.on_error == "raise":
                    raise
                if discovery_parameters.on_error == "warn":
                    console.error("Host label discovery of '%s' failed: %s\n" %
                                  (section_plugin.name, exc))

    except KeyboardInterrupt:
        raise MKGeneralException("Interrupted by Ctrl-C.")

    return host_labels
Пример #18
0
def get_check_preview(
    *,
    host_name: HostName,
    max_cachefile_age: int,
    use_cached_snmp_data: bool,
    on_error: str,
) -> Tuple[CheckPreviewTable, DiscoveredHostLabels]:
    """Get the list of service of a host or cluster and guess the current state of
    all services if possible"""
    config_cache = config.get_config_cache()
    host_config = config_cache.get_host_config(host_name)

    ip_address = None if host_config.is_cluster else config.lookup_ip_address(host_config)
    discovery_parameters = DiscoveryParameters(
        on_error=on_error,
        load_labels=False,
        save_labels=False,
        only_host_labels=False,
    )

    _set_cache_opts_of_checkers(use_cached_snmp_data=use_cached_snmp_data)
    nodes = sources.make_nodes(
        config_cache, host_config, ip_address, Mode.DISCOVERY,
        sources.make_sources(
            host_config,
            ip_address,
            mode=Mode.DISCOVERY,
            on_scan_error=on_error,
        ))

    parsed_sections_broker = ParsedSectionsBroker()
    sources.update_host_sections(
        parsed_sections_broker,
        nodes,
        max_cachefile_age=max_cachefile_age,
        host_config=host_config,
        fetcher_messages=list(
            sources.fetch_all(
                nodes,
                max_cachefile_age=max_cachefile_age,
                host_config=host_config,
            )),
        selected_sections=NO_SELECTION,
    )

    grouped_services, host_label_result = _get_host_services(
        host_config,
        ip_address,
        parsed_sections_broker,
        discovery_parameters,
    )

    table: CheckPreviewTable = []
    for check_source, services_with_nodes in grouped_services.items():
        for service, found_on_nodes in services_with_nodes:
            plugin = agent_based_register.get_check_plugin(service.check_plugin_name)
            params = _preview_params(host_name, service, plugin, check_source)

            if check_source in ['legacy', 'active', 'custom']:
                exitcode = None
                output = u"WAITING - %s check, cannot be done offline" % check_source.title()
                ruleset_name: Optional[RulesetName] = None
            else:

                ruleset_name = (str(plugin.check_ruleset_name)
                                if plugin and plugin.check_ruleset_name else None)
                wrapped_params = (Parameters(wrap_parameters(params)) if plugin and
                                  plugin.check_default_parameters is not None else None)

                exitcode, output, _perfdata = checking.get_aggregated_result(
                    parsed_sections_broker,
                    host_config,
                    ip_address,
                    service,
                    plugin,
                    lambda p=wrapped_params: p,  # type: ignore[misc]  # "type of lambda"
                ).result

            # Service discovery never uses the perfdata in the check table. That entry
            # is constantly discarded, yet passed around(back and forth) as part of the
            # discovery result in the request elements. Some perfdata VALUES are not parsable
            # by ast.literal_eval such as "inf" it lead to ValueErrors. Thus keep perfdata empty
            perfdata: List[MetricTuple] = []
            table.append((
                _preview_check_source(host_name, service, check_source),
                str(service.check_plugin_name),
                ruleset_name,
                service.item,
                service.parameters,
                params,
                service.description,
                exitcode,
                output,
                perfdata,
                service.service_labels.to_dict(),
                found_on_nodes,
            ))

    return table, DiscoveredHostLabels(
        *{
            # TODO (mo): According to unit tests, this is what was done prior to refactoring.
            # Im not sure this is desired. If it is, it should be explained.
            **{l.name: l for l in host_label_result.vanished},
            **{l.name: l for l in host_label_result.present},
        }.values())
Пример #19
0
def get_aggregated_result(
    parsed_sections_broker: ParsedSectionsBroker,
    host_config: config.HostConfig,
    ipaddress: Optional[HostAddress],
    service: Service,
    plugin: Optional[checking_classes.CheckPlugin],
    timespecific_parameters: Union[LegacyCheckParameters,
                                   TimespecificParameters],
    *,
    value_store_manager: value_store.ValueStoreManager,
    persist_value_store_changes: bool,
) -> AggregatedResult:
    """Run the check function and aggregate the subresults

    This function is also called during discovery.
    """
    if plugin is None:
        return AggregatedResult(
            submit=True,
            data_received=True,
            result=ServiceCheckResult.check_not_implemented(),
            cache_info=None,
        )

    config_cache = config.get_config_cache()
    check_function = (_cluster_modes.get_cluster_check_function(
        *config_cache.get_clustered_service_configuration(
            host_config.hostname,
            service.description,
        ),
        plugin=plugin,
        service_id=service.id(),
        persist_value_store_changes=persist_value_store_changes,
    ) if host_config.is_cluster else plugin.check_function)

    section_kws, error_result = _get_monitoring_data_kwargs_handle_pre20_services(
        parsed_sections_broker,
        host_config,
        config_cache,
        ipaddress,
        service,
        plugin.sections,
    )
    if not section_kws:  # no data found
        return AggregatedResult(
            submit=False,
            data_received=False,
            result=error_result,
            cache_info=None,
        )

    item_kw = {} if service.item is None else {"item": service.item}
    params_kw = ({} if plugin.check_default_parameters is None else {
        "params":
        _final_read_only_check_parameters(timespecific_parameters)
    })

    try:
        with plugin_contexts.current_host(
                host_config.hostname), plugin_contexts.current_service(
                    service), value_store_manager.namespace(service.id()):
            result = _aggregate_results(
                check_function(
                    **item_kw,
                    **params_kw,
                    **section_kws,
                ))

    except (item_state.MKCounterWrapped,
            checking_classes.IgnoreResultsError) as e:
        msg = str(e) or "No service summary available"
        return AggregatedResult(
            submit=False,
            data_received=True,
            result=ServiceCheckResult(output=msg),
            cache_info=None,
        )
    except MKTimeout:
        raise
    except Exception:
        if cmk.utils.debug.enabled():
            raise
        table = check_table.get_check_table(host_config.hostname,
                                            skip_autochecks=True)
        result = ServiceCheckResult(
            3,
            cmk.base.crash_reporting.create_check_crash_dump(
                host_name=host_config.hostname,
                service_name=service.description,
                plugin_name=service.check_plugin_name,
                plugin_kwargs={
                    **item_kw,
                    **params_kw,
                    **section_kws
                },
                is_manual=service.id() in table,
            ),
        )

    return AggregatedResult(
        submit=True,
        data_received=True,
        result=result,
        cache_info=parsed_sections_broker.get_cache_info(plugin.sections),
    )
Пример #20
0
def do_discovery(
    arg_hostnames: Set[HostName],
    *,
    selected_sections: SectionNameCollection,
    run_only_plugin_names: Optional[Set[CheckPluginName]],
    arg_only_new: bool,
    only_host_labels: bool = False,
) -> None:
    config_cache = config.get_config_cache()
    use_caches = not arg_hostnames or cmk.core_helpers.cache.FileCacheFactory.maybe
    on_error = "raise" if cmk.utils.debug.enabled() else "warn"

    discovery_parameters = DiscoveryParameters(
        on_error=on_error,
        load_labels=arg_only_new,
        save_labels=True,
        only_host_labels=only_host_labels,
    )

    host_names = _preprocess_hostnames(arg_hostnames, config_cache, only_host_labels)

    mode = Mode.DISCOVERY if selected_sections is NO_SELECTION else Mode.FORCE_SECTIONS

    # Now loop through all hosts
    for host_name in sorted(host_names):
        host_config = config_cache.get_host_config(host_name)
        section.section_begin(host_name)
        try:
            ipaddress = config.lookup_ip_address(host_config)
            nodes = sources.make_nodes(
                config_cache,
                host_config,
                ipaddress,
                mode,
                sources.make_sources(
                    host_config,
                    ipaddress,
                    mode=mode,
                    selected_sections=selected_sections,
                    on_scan_error=on_error,
                ),
            )
            max_cachefile_age = config.discovery_max_cachefile_age() if use_caches else 0

            parsed_sections_broker = ParsedSectionsBroker()
            sources.update_host_sections(
                parsed_sections_broker,
                nodes,
                max_cachefile_age=max_cachefile_age,
                host_config=host_config,
                fetcher_messages=list(
                    sources.fetch_all(
                        nodes,
                        max_cachefile_age=max_cachefile_age,
                        host_config=host_config,
                    )),
                selected_sections=selected_sections,
            )
            _do_discovery_for(
                host_name,
                ipaddress,
                parsed_sections_broker,
                run_only_plugin_names,
                arg_only_new,
                discovery_parameters,
            )

        except Exception as e:
            if cmk.utils.debug.enabled():
                raise
            section.section_error("%s" % e)
        finally:
            cmk.utils.cleanup.cleanup_globals()
Пример #21
0
def _do_inv_for_realhost(
    host_config: config.HostConfig,
    ipaddress: Optional[HostAddress],
    *,
    parsed_sections_broker: ParsedSectionsBroker,
    run_plugin_names: Container[InventoryPluginName],
    retentions_tracker: RetentionsTracker,
) -> InventoryTrees:
    tree_aggregator = TreeAggregator()

    _set_cluster_property(tree_aggregator.trees.inventory, host_config)

    section.section_step("Executing inventory plugins")
    for inventory_plugin in agent_based_register.iter_all_inventory_plugins():
        if inventory_plugin.name not in run_plugin_names:
            continue

        for source_type in (SourceType.HOST, SourceType.MANAGEMENT):
            kwargs = get_section_kwargs(
                parsed_sections_broker,
                HostKey(host_config.hostname, ipaddress, source_type),
                inventory_plugin.sections,
            )
            if not kwargs:
                console.vverbose(
                    " %s%s%s%s: skipped (no data)\n",
                    tty.yellow,
                    tty.bold,
                    inventory_plugin.name,
                    tty.normal,
                )
                continue

            # 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 = {
                    **kwargs,
                    "params":
                    host_config.inventory_parameters(
                        inventory_plugin.inventory_ruleset_name),
                }

            exception = tree_aggregator.aggregate_results(
                inventory_generator=inventory_plugin.inventory_function(
                    **kwargs),
                retentions_tracker=retentions_tracker,
                raw_cache_info=parsed_sections_broker.get_cache_info(
                    inventory_plugin.sections),
                is_legacy_plugin=inventory_plugin.module is None,
            )

            if exception:
                console.warning(
                    " %s%s%s%s: failed: %s",
                    tty.red,
                    tty.bold,
                    inventory_plugin.name,
                    tty.normal,
                    exception,
                )
            else:
                console.verbose(" %s%s%s%s", tty.green, tty.bold,
                                inventory_plugin.name, tty.normal)
                console.vverbose(": ok\n")

    console.verbose("\n")
    return tree_aggregator.trees
Пример #22
0
def discover_on_host(
    *,
    config_cache: config.ConfigCache,
    host_config: config.HostConfig,
    mode: str,
    service_filters: Optional[_ServiceFilters],
    on_error: str,
    use_cached_snmp_data: bool,
    max_cachefile_age: int,
) -> DiscoveryResult:

    console.verbose("  Doing discovery with mode '%s'...\n" % mode)

    host_name = host_config.hostname
    result = DiscoveryResult()
    discovery_parameters = DiscoveryParameters(
        on_error=on_error,
        load_labels=(mode != "remove"),
        save_labels=(mode != "remove"),
        only_host_labels=(mode == "only-host-labels"),
    )

    if host_name not in config_cache.all_active_hosts():
        result.error_text = ""
        return result

    _set_cache_opts_of_checkers(use_cached_snmp_data=use_cached_snmp_data)

    try:
        # in "refresh" mode we first need to remove all previously discovered
        # checks of the host, so that _get_host_services() does show us the
        # new discovered check parameters.
        if mode == "refresh":
            result.self_removed += host_config.remove_autochecks()  # this is cluster-aware!

        if host_config.is_cluster:
            ipaddress = None
        else:
            ipaddress = config.lookup_ip_address(host_config)

        nodes = sources.make_nodes(
            config_cache,
            host_config,
            ipaddress,
            Mode.DISCOVERY,
            sources.make_sources(
                host_config,
                ipaddress,
                mode=Mode.DISCOVERY,
                on_scan_error=on_error,
            ),
        )

        parsed_sections_broker = ParsedSectionsBroker()
        sources.update_host_sections(
            parsed_sections_broker,
            nodes,
            max_cachefile_age=max_cachefile_age,
            host_config=host_config,
            fetcher_messages=list(
                sources.fetch_all(
                    nodes,
                    max_cachefile_age=max_cachefile_age,
                    host_config=host_config,
                )),
            selected_sections=NO_SELECTION,
        )

        # Compute current state of new and existing checks
        services, host_labels = _get_host_services(
            host_config,
            ipaddress,
            parsed_sections_broker,
            discovery_parameters,
        )

        old_services = services.get("old", [])

        # Create new list of checks
        new_services = _get_post_discovery_services(host_name, services, service_filters or
                                                    _ServiceFilters.accept_all(), result, mode)
        host_config.set_autochecks(new_services)

        result.diff_text = make_object_diff(
            _make_services_audit_log_object([x.service for x in old_services]),
            _make_services_audit_log_object([x.service for x in new_services]))

    except MKTimeout:
        raise  # let general timeout through

    except Exception as e:
        if cmk.utils.debug.enabled():
            raise
        result.error_text = str(e)

    else:
        if mode != "remove":
            result.self_new_host_labels = len(host_labels.new)
            result.self_total_host_labels = len(host_labels.present)

    result.self_total = result.self_new + result.self_kept
    return result