Example #1
0
def _ip_address_for_dump_host(host_config, family=None):
    if host_config.is_cluster:
        try:
            return ip_lookup.lookup_ip_address(host_config.hostname, family)
        except Exception:
            return ""

    try:
        return ip_lookup.lookup_ip_address(host_config.hostname, family)
    except Exception:
        return core_config.fallback_ip_for(host_config, family)
Example #2
0
def _ip_address_for_dump_host(host_config, family=None):
    # type: (config.HostConfig, Optional[int]) -> Optional[str]
    if host_config.is_cluster:
        try:
            return ip_lookup.lookup_ip_address(host_config.hostname, family)
        except Exception:
            return ""

    try:
        return ip_lookup.lookup_ip_address(host_config.hostname, family)
    except Exception:
        return core_config.fallback_ip_for(host_config, family)
Example #3
0
def _ip_address_for_dump_host(host_config: config.HostConfig,
                              family: Optional[int] = None) -> Optional[str]:
    if host_config.is_cluster:
        try:
            return ip_lookup.lookup_ip_address(host_config, family)
        except Exception:
            return ""

    try:
        return ip_lookup.lookup_ip_address(host_config, family)
    except Exception:
        return core_config.fallback_ip_for(host_config, family)
Example #4
0
def _ip_address_for_dump_host(
    host_config: config.HostConfig,
    *,
    family: socket.AddressFamily,
) -> Optional[str]:
    if host_config.is_cluster:
        try:
            return ip_lookup.lookup_ip_address(host_config, family=family)
        except Exception:
            return ""

    try:
        return ip_lookup.lookup_ip_address(host_config, family=family)
    except Exception:
        return ip_lookup.fallback_ip_for(family)
Example #5
0
    def get_host_sections(self, max_cachefile_age=None):
        """Gather ALL host info data for any host (hosts, nodes, clusters) in Check_MK.

        Returns a dictionary object of already parsed HostSections() constructs for each related host.
        For single hosts it's just a single entry in the dictionary. For cluster hosts it contains one
        HostSections() entry for each related node.

        Communication errors are not raised through by this functions. All agent related errors are
        caught by the source.run() method and saved in it's _exception attribute. The caller should
        use source.get_summary_result() to get the state, output and perfdata of the agent excecution
        or source.exception() to get the exception object.
        """
        console.step("Fetching data")

        # First abstract clusters/nodes/hosts
        hosts = []
        nodes = self._host_config.nodes
        if nodes is not None:
            for node_hostname in nodes:
                node_ipaddress = ip_lookup.lookup_ip_address(node_hostname)

                node_check_names = check_table.get_needed_check_names(node_hostname,
                                                                      remove_duplicates=True,
                                                                      filter_mode="only_clustered")

                node_data_sources = DataSources(node_hostname, node_ipaddress)
                node_data_sources.enforce_check_plugin_names(set(node_check_names))
                hosts.append((node_hostname, node_ipaddress, node_data_sources,
                              config.cluster_max_cachefile_age))
        else:
            hosts.append((self._hostname, self._ipaddress, self, config.check_max_cachefile_age))

        if nodes:
            import cmk.base.data_sources.abstract as abstract
            abstract.DataSource.set_may_use_cache_file()

        # Special agents can produce data for the same check_plugin_name on the same host, in this case
        # the section lines need to be extended
        multi_host_sections = MultiHostSections()
        for this_hostname, this_ipaddress, these_sources, this_max_cachefile_age in hosts:
            # In case a max_cachefile_age is given with the function call, always use this one
            # instead of the host individual one. This is only used in discovery mode.
            if max_cachefile_age is not None:
                these_sources.set_max_cachefile_age(max_cachefile_age)
            else:
                these_sources.set_max_cachefile_age(this_max_cachefile_age)

            host_sections =\
                multi_host_sections.add_or_get_host_sections(this_hostname, this_ipaddress)

            for source in these_sources.get_data_sources():
                host_sections_from_source = source.run()
                host_sections.update(host_sections_from_source)

            # Store piggyback information received from all sources of this host. This
            # also implies a removal of piggyback files received during previous calls.
            cmk.utils.piggyback.store_piggyback_raw_data(this_hostname,
                                                         host_sections.piggybacked_raw_data)

        return multi_host_sections
Example #6
0
def _do_active_inventory_for(
    *,
    host_config: config.HostConfig,
    run_only_plugin_names: Optional[Set[InventoryPluginName]],
    selected_sections: checkers.SectionNameCollection,
) -> ActiveInventoryResult:
    if host_config.is_cluster:
        return ActiveInventoryResult(
            trees=_do_inv_for_cluster(host_config),
            source_results=[],
            safe_to_write=True,
        )

    ipaddress = ip_lookup.lookup_ip_address(host_config)
    config_cache = config.get_config_cache()

    multi_host_sections, source_results = _fetch_multi_host_sections_for_inv(
        config_cache,
        host_config,
        ipaddress,
        selected_sections,
    )

    return ActiveInventoryResult(
        trees=_do_inv_for_realhost(
            host_config,
            ipaddress,
            multi_host_sections=multi_host_sections,
            run_only_plugin_names=run_only_plugin_names,
        ),
        source_results=source_results,
        safe_to_write=_safe_to_write_tree(source_results) and
        selected_sections is checkers.NO_SELECTION,
    )
Example #7
0
    def _get_host_entries(self, hostname, ipaddress):
        host_config = self._config_cache.get_host_config(hostname)
        if host_config.nodes is None:
            return [(hostname, ipaddress)]

        return [(node_hostname, ip_lookup.lookup_ip_address(node_hostname))
                for node_hostname in host_config.nodes]
Example #8
0
def do_inv(hostnames):
    # type: (List[HostName]) -> None
    store.makedirs(cmk.utils.paths.inventory_output_dir)
    store.makedirs(cmk.utils.paths.inventory_archive_dir)

    for hostname in hostnames:
        console.section_begin(hostname)
        try:
            config_cache = config.get_config_cache()
            host_config = config_cache.get_host_config(hostname)

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

            sources = data_sources.DataSources(hostname, ipaddress)
            inventory_tree, status_data_tree = _do_inv_for(
                sources,
                multi_host_sections=None,
                host_config=host_config,
                ipaddress=ipaddress,
            )
            _run_inventory_export_hooks(host_config, inventory_tree)
            _show_inventory_results_on_console(inventory_tree,
                                               status_data_tree)

        except Exception as e:
            if cmk.utils.debug.enabled():
                raise

            console.section_error("%s" % e)
        finally:
            cmk.base.cleanup.cleanup_globals()
Example #9
0
    def _make_piggy_nodes(
        host_config: HostConfig
    ) -> List[Tuple[HostName, Optional[HostAddress], "DataSources"]]:
        """Abstract clusters/nodes/hosts"""
        assert host_config.nodes is not None

        import cmk.base.data_sources.abstract as abstract  # pylint: disable=import-outside-toplevel
        abstract.DataSource.set_may_use_cache_file()

        nodes = []
        for hostname in host_config.nodes:
            ipaddress = ip_lookup.lookup_ip_address(hostname)
            check_names = check_table.get_needed_check_names(
                hostname,
                remove_duplicates=True,
                filter_mode="only_clustered",
            )
            selected_raw_sections = config.get_relevant_raw_sections(
                # TODO (mo): centralize maincheckify: CMK-4295
                CheckPluginName(maincheckify(n)) for n in check_names)
            sources = DataSources(
                hostname,
                ipaddress,
                sources=make_sources(
                    host_config,
                    ipaddress,
                    selected_raw_sections=selected_raw_sections,
                ),
            )
            nodes.append((hostname, ipaddress, sources))
        return nodes
Example #10
0
    def _get_host_entries(self, hostname, ipaddress):
        # type: (HostName, Optional[HostAddress]) -> List[Tuple[HostName, Optional[HostAddress]]]
        host_config = self._config_cache.get_host_config(hostname)
        if host_config.nodes is None:
            return [(hostname, ipaddress)]

        return [(node_hostname, ip_lookup.lookup_ip_address(node_hostname))
                for node_hostname in host_config.nodes]
Example #11
0
    def _get_host_entries(self, host_key: HostKey) -> List[HostKey]:
        host_config = self._config_cache.get_host_config(host_key.hostname)
        if host_config.nodes is None:
            return [host_key]

        return [
            HostKey(hostname, ip_lookup.lookup_ip_address(hostname),
                    host_key.source_type) for hostname in host_config.nodes
        ]
Example #12
0
def analyse_cluster_host_labels(
    *,
    host_config: config.HostConfig,
    ipaddress: Optional[str],
    parsed_sections_broker: ParsedSectionsBroker,
    discovery_parameters: DiscoveryParameters,
) -> QualifiedDiscovery[HostLabel]:
    """Discovers and processes host labels per cluster host

    Side effects:
     * prints to console (`section`)
     * may write to disk
     * may reset ruleset optimizer

    If specified in the discovery_parameters, the host labels after
    the discovery are persisted on disk.

    Some plugins discover services based on host labels, so the ruleset
    optimizer caches have to be cleared if new host labels are found.
    """
    if not host_config.nodes:
        return QualifiedDiscovery.empty()

    nodes_host_labels: Dict[str, HostLabel] = {}
    config_cache = config.get_config_cache()

    for node in host_config.nodes:
        node_config = config_cache.get_host_config(node)
        node_ipaddress = ip_lookup.lookup_ip_address(
            node_config, family=node_config.default_address_family)

        node_result = analyse_host_labels(
            host_name=node,
            ipaddress=node_ipaddress,
            parsed_sections_broker=parsed_sections_broker,
            discovery_parameters=discovery_parameters,
        )

        # keep the latest for every label.name
        nodes_host_labels.update({
            # 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 node_result.vanished},
            **{l.name: l
               for l in node_result.present},
        })

    return _analyse_host_labels(
        host_name=host_config.hostname,
        discovered_host_labels=list(nodes_host_labels.values()),
        existing_host_labels=_load_existing_host_labels(
            host_name=host_config.hostname,
            discovery_parameters=discovery_parameters,
        ),
        discovery_parameters=discovery_parameters,
    )
Example #13
0
def create_snmp_host_config(hostname):
    # type: (str) -> SNMPHostConfig
    host_config = config.get_config_cache().get_host_config(hostname)

    # ip_lookup.lookup_ipv4_address() returns Optional[str] in general, but for
    # all cases that reach the code here we seem to have "str".
    address = ip_lookup.lookup_ip_address(hostname)
    if address is None:
        raise MKGeneralException("Failed to gather IP address of %s" % hostname)

    return host_config.snmp_config(address)
Example #14
0
def ip_address_of(host_config: config.HostConfig, family: Optional[int] = None) -> Optional[str]:
    try:
        return ip_lookup.lookup_ip_address(host_config, family)
    except Exception as e:
        if host_config.is_cluster:
            return ""

        _failed_ip_lookups.append(host_config.hostname)
        if not _ignore_ip_lookup_failures:
            warning("Cannot lookup IP address of '%s' (%s). "
                    "The host will not be monitored correctly." % (host_config.hostname, e))
        return fallback_ip_for(host_config, family)
Example #15
0
    def _management_board_ipaddress(self, hostname):
        mgmt_ipaddress = self._host_config.management_address

        if mgmt_ipaddress is None:
            return None

        if not self._is_ipaddress(mgmt_ipaddress):
            try:
                return ip_lookup.lookup_ip_address(mgmt_ipaddress)
            except MKIPAddressLookupError:
                return None
        else:
            return mgmt_ipaddress
Example #16
0
def management_board_ipaddress(hostname):
    # type: (HostName) -> Optional[HostAddress]
    mgmt_ipaddress = config.get_config_cache().get_host_config(hostname).management_address

    if mgmt_ipaddress is None:
        return None

    if not _is_ipaddress(mgmt_ipaddress):
        try:
            return ip_lookup.lookup_ip_address(mgmt_ipaddress)
        except MKIPAddressLookupError:
            return None
    else:
        return mgmt_ipaddress
Example #17
0
def _make_piggyback_nodes(
        config_cache: config.ConfigCache,
        host_config: HostConfig) -> Iterable[Tuple[HostName, Optional[HostAddress], DataSources]]:
    """Abstract clusters/nodes/hosts"""
    assert host_config.nodes is not None

    nodes = []
    for hostname in host_config.nodes:
        node_config = config_cache.get_host_config(hostname)
        ipaddress = ip_lookup.lookup_ip_address(node_config)
        sources = make_sources(
            HostConfig.make_host_config(hostname),
            ipaddress,
        )
        nodes.append((hostname, ipaddress, sources))
    return nodes
Example #18
0
def _make_piggyback_nodes(
    mode: Mode,
    config_cache: config.ConfigCache,
    host_config: HostConfig,
) -> Sequence[Tuple[HostName, Optional[HostAddress], Sequence[Source]]]:
    """Abstract clusters/nodes/hosts"""
    assert host_config.nodes is not None

    nodes = []
    for hostname in host_config.nodes:
        node_config = config_cache.get_host_config(hostname)
        ipaddress = ip_lookup.lookup_ip_address(
            node_config,
            family=node_config.default_address_family,
        )
        sources = make_sources(
            HostConfig.make_host_config(hostname),
            ipaddress,
            mode=mode,
        )
        nodes.append((hostname, ipaddress, sources))
    return nodes
Example #19
0
def do_inv(hostnames: List[HostName]) -> None:
    store.makedirs(cmk.utils.paths.inventory_output_dir)
    store.makedirs(cmk.utils.paths.inventory_archive_dir)

    config_cache = config.get_config_cache()

    for hostname in hostnames:
        section.section_begin(hostname)
        try:
            host_config = config.HostConfig.make_host_config(hostname)
            if host_config.is_cluster:
                ipaddress = None
            else:
                ipaddress = ip_lookup.lookup_ip_address(host_config)

            inventory_tree, status_data_tree = _do_inv_for(
                config_cache,
                host_config,
                ipaddress,
                sources=checkers.make_sources(
                    host_config,
                    ipaddress,
                    mode=checkers.Mode.INVENTORY,
                ),
                multi_host_sections=None,
            )[:2]
            _run_inventory_export_hooks(host_config, inventory_tree)
            _show_inventory_results_on_console(inventory_tree,
                                               status_data_tree)

        except Exception as e:
            if cmk.utils.debug.enabled():
                raise

            section.section_error("%s" % e)
        finally:
            cmk.utils.cleanup.cleanup_globals()
Example #20
0
def do_inv(hostnames: List[HostName]) -> None:
    store.makedirs(cmk.utils.paths.inventory_output_dir)
    store.makedirs(cmk.utils.paths.inventory_archive_dir)

    config_cache = config.get_config_cache()

    for hostname in hostnames:
        section.section_begin(hostname)
        try:
            host_config = config.HostConfig.make_host_config(hostname)
            if host_config.is_cluster:
                ipaddress = None
            else:
                ipaddress = ip_lookup.lookup_ip_address(host_config)

            # TODO: Results are completely ignored here. We should process the results to make error
            # visible on the console
            multi_host_sections, _results = _get_multi_host_sections_for_inv(
                config_cache, host_config, ipaddress)

            inventory_tree, status_data_tree = _do_inv_for(
                host_config,
                ipaddress,
                multi_host_sections=multi_host_sections,
            )
            _run_inventory_export_hooks(host_config, inventory_tree)
            _show_inventory_results_on_console(inventory_tree,
                                               status_data_tree)

        except Exception as e:
            if cmk.utils.debug.enabled():
                raise

            section.section_error("%s" % e)
        finally:
            cmk.utils.cleanup.cleanup_globals()
Example #21
0
def _do_active_inventory_for(
    host_config: config.HostConfig, ) -> ActiveInventoryResult:
    if host_config.is_cluster:
        return ActiveInventoryResult(
            trees=_do_inv_for_cluster(host_config),
            source_results=[],
            safe_to_write=True,
        )

    ipaddress = ip_lookup.lookup_ip_address(host_config)
    config_cache = config.get_config_cache()

    multi_host_sections, source_results = _fetch_multi_host_sections_for_inv(
        config_cache, host_config, ipaddress)

    return ActiveInventoryResult(
        trees=_do_inv_for_realhost(
            host_config,
            ipaddress,
            multi_host_sections=multi_host_sections,
        ),
        source_results=source_results,
        safe_to_write=_safe_to_write_tree(source_results),
    )
Example #22
0
def do_check(
    hostname: HostName,
    ipaddress: Optional[HostAddress],
    only_check_plugin_names: Optional[Set[CheckPluginName]] = None,
    fetcher_messages: Optional[Sequence[FetcherMessage]] = None
) -> 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()

    status: ServiceState = 0
    infotexts: List[ServiceDetails] = []
    long_infotexts: List[ServiceAdditionalDetails] = []
    perfdata: List[str] = []
    try:
        with cpu_tracking.execute(), cpu_tracking.phase("busy"):
            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)

            item_state.load(hostname)

            # 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.
            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,
                only_check_plugins=only_check_plugin_names,
            )

            services_to_check = _filter_clustered_services(
                config_cache=config_cache,
                host_name=hostname,
                belongs_to_cluster=belongs_to_cluster,
                services=services_to_fetch,
            )

            # see which raw sections we may need
            selected_raw_sections = agent_based_register.get_relevant_raw_sections(
                check_plugin_names=(s.check_plugin_name for s in services_to_fetch),
                consider_inventory_plugins=host_config.do_status_data_inventory,
            )

            sources = checkers.make_sources(
                host_config,
                ipaddress,
                mode=checkers.Mode.CHECKING,
            )
            mhs = MultiHostSections()

            result = checkers.update_host_sections(
                mhs,
                checkers.make_nodes(
                    config_cache,
                    host_config,
                    ipaddress,
                    checkers.Mode.CHECKING,
                    sources,
                ),
                selected_raw_sections=selected_raw_sections,
                max_cachefile_age=host_config.max_cachefile_age,
                host_config=host_config,
                fetcher_messages=fetcher_messages,
            )

            num_success, plugins_missing_data = _do_all_checks_on_host(
                config_cache,
                host_config,
                ipaddress,
                multi_host_sections=mhs,
                services=services_to_check,
                only_check_plugins=only_check_plugin_names,
            )
            inventory.do_inventory_actions_during_checking_for(
                config_cache,
                host_config,
                ipaddress,
                sources=sources,
                multi_host_sections=mhs,
            )

            if _submit_to_core:
                item_state.save(hostname)

            for source, 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)

        for msg in fetcher_messages if fetcher_messages else ():
            cpu_tracking.update(msg.stats.cpu_times)

        phase_times = cpu_tracking.get_times()
        total_times = phase_times["busy"]

        infotexts.append("execution time %.1f sec" % total_times.run_time)
        if config.check_mk_perfdata_with_times:
            perfdata += [
                "execution_time=%.3f" % total_times.run_time,
                "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,
            ]

            for phase, times in phase_times.items():
                if phase in ["agent", "snmp", "ds"]:
                    t = times.run_time - sum(times.process[:4])  # real time - CPU time
                    perfdata.append("cmk_time_%s=%.3f" % (phase, t))
        else:
            perfdata.append("execution_time=%.3f" % total_times.run_time)

        return status, infotexts, long_infotexts, perfdata
    finally:
        if _checkresult_file_fd is not None:
            _close_checkresult_file()

        # "ipaddress is not None": At least when working with a cluster host it seems the ipaddress
        # may be None.  This needs to be understood in detail and cleaned up. As the InlineSNMP
        # stats feature is a very rarely used debugging feature, the analyzation and fix is
        # postponed now.
        if config.record_inline_snmp_stats and ipaddress is not None and host_config.snmp_config(
                ipaddress).snmp_backend == "inline":
            inline.snmp_stats_save()
Example #23
0
def do_inv_check(hostname, options):
    # type: (HostName, Dict[str, int]) -> Tuple[ServiceState, List[ServiceDetails], List[ServiceAdditionalDetails], Metric]
    _inv_hw_changes = options.get("hw-changes", 0)
    _inv_sw_changes = options.get("sw-changes", 0)
    _inv_sw_missing = options.get("sw-missing", 0)

    config_cache = config.get_config_cache()
    host_config = config_cache.get_host_config(
        hostname)  # type: config.HostConfig

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

    status = 0
    infotexts = []  # type: List[Text]
    long_infotexts = []  # type: List[Text]
    perfdata = []  # type: List[Tuple]

    sources = data_sources.DataSources(hostname, ipaddress)
    inventory_tree, status_data_tree = _do_inv_for(
        sources,
        multi_host_sections=None,
        host_config=host_config,
        ipaddress=ipaddress,
    )

    #TODO add cluster if and only if all sources do not fail?
    if _all_sources_fail(host_config, sources):
        old_tree, sources_state = None, 1
        status = max(status, sources_state)
        infotexts.append("Cannot update tree%s" %
                         check_api_utils.state_markers[sources_state])
    else:
        old_tree = _save_inventory_tree(hostname, inventory_tree)

    _run_inventory_export_hooks(host_config, inventory_tree)

    if inventory_tree.is_empty() and status_data_tree.is_empty():
        infotexts.append("Found no data")

    else:
        infotexts.append("Found %d inventory entries" %
                         inventory_tree.count_entries())

        # Node 'software' is always there because _do_inv_for creates this node for cluster info
        if not inventory_tree.get_sub_container(['software']).has_edge('packages')\
           and _inv_sw_missing:
            infotexts.append("software packages information is missing" +
                             check_api_utils.state_markers[_inv_sw_missing])
            status = max(status, _inv_sw_missing)

        if old_tree is not None:
            if not old_tree.is_equal(inventory_tree, edges=["software"]):
                infotext = "software changes"
                if _inv_sw_changes:
                    status = max(status, _inv_sw_changes)
                    infotext += check_api_utils.state_markers[_inv_sw_changes]
                infotexts.append(infotext)

            if not old_tree.is_equal(inventory_tree, edges=["hardware"]):
                infotext = "hardware changes"
                if _inv_hw_changes:
                    status = max(status, _inv_hw_changes)
                    infotext += check_api_utils.state_markers[_inv_hw_changes]

                infotexts.append(infotext)

        if not status_data_tree.is_empty():
            infotexts.append("Found %s status entries" %
                             status_data_tree.count_entries())

    for source in sources.get_data_sources():
        source_state, source_output, _source_perfdata = source.get_summary_result_for_inventory(
        )
        # Do not output informational (state = 0) things. These information are shown by the "Check_MK" service
        if source_state != 0:
            status = max(source_state, status)
            infotexts.append("[%s] %s" % (source.id(), source_output))

    return status, infotexts, long_infotexts, perfdata
Example #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_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()
Example #25
0
def do_check(hostname, ipaddress, only_check_plugin_names=None):
    # type: (HostName, Optional[HostAddress], Optional[List[CheckPluginName]]) -> Tuple[int, List[ServiceDetails], List[ServiceAdditionalDetails], List[Text]]
    cpu_tracking.start("busy")
    console.verbose("Check_MK version %s\n", six.ensure_str(cmk.__version__))

    config_cache = config.get_config_cache()
    host_config = config_cache.get_host_config(hostname)

    exit_spec = host_config.exit_code_spec()

    status = 0  # type: ServiceState
    infotexts = []  # type: List[ServiceDetails]
    long_infotexts = []  # type: List[ServiceAdditionalDetails]
    perfdata = []  # type: List[Text]
    try:
        # In case of keepalive we always have an ipaddress (can be 0.0.0.0 or :: when
        # address is unknown). When called as non keepalive ipaddress may be None or
        # is already an address (2nd argument)
        if ipaddress is None and not host_config.is_cluster:
            ipaddress = ip_lookup.lookup_ip_address(hostname)

        item_state.load(hostname)

        sources = data_sources.DataSources(hostname, ipaddress)

        num_success, missing_sections = \
            _do_all_checks_on_host(sources, host_config, ipaddress, only_check_plugin_names)

        if _submit_to_core:
            item_state.save(hostname)

        for source in sources.get_data_sources():
            source_state, source_output, source_perfdata = source.get_summary_result_for_checking(
            )
            if source_output != "":
                status = max(status, source_state)
                infotexts.append("[%s] %s" % (source.id(), source_output))
                perfdata.extend(
                    [_convert_perf_data(p) for p in source_perfdata])

        if missing_sections and num_success > 0:
            missing_sections_status, missing_sections_infotext = \
                _check_missing_sections(missing_sections, exit_spec)
            status = max(status, missing_sections_status)
            infotexts.append(missing_sections_infotext)

        elif missing_sections:
            infotexts.append("Got no information from host")
            status = max(status, cast(int, exit_spec.get("empty_output", 2)))

        cpu_tracking.end()
        phase_times = cpu_tracking.get_times()
        total_times = phase_times["TOTAL"]
        run_time = total_times[4]

        infotexts.append("execution time %.1f sec" % run_time)
        if config.check_mk_perfdata_with_times:
            perfdata += [
                "execution_time=%.3f" % run_time,
                "user_time=%.3f" % total_times[0],
                "system_time=%.3f" % total_times[1],
                "children_user_time=%.3f" % total_times[2],
                "children_system_time=%.3f" % total_times[3],
            ]

            for phase, times in phase_times.items():
                if phase in ["agent", "snmp", "ds"]:
                    t = times[4] - sum(times[:4])  # real time - CPU time
                    perfdata.append("cmk_time_%s=%.3f" % (phase, t))
        else:
            perfdata.append("execution_time=%.3f" % run_time)

        return status, infotexts, long_infotexts, perfdata
    finally:
        if _checkresult_file_fd is not None:
            _close_checkresult_file()

        # "ipaddress is not None": At least when working with a cluster host it seems the ipaddress
        # may be None.  This needs to be understood in detail and cleaned up. As the InlineSNMP
        # stats feature is a very rarely used debugging feature, the analyzation and fix is
        # postponed now.
        if config.record_inline_snmp_stats \
           and ipaddress is not None \
           and host_config.snmp_config(ipaddress).is_inline_snmp_host:
            inline_snmp.save_snmp_stats()
Example #26
0
def do_check(
    hostname: HostName,
    ipaddress: Optional[HostAddress],
    only_check_plugin_names: Optional[Set[CheckPluginName]] = None
) -> Tuple[int, List[ServiceDetails], List[ServiceAdditionalDetails], List[str]]:
    cpu_tracking.start("busy")
    console.verbose("Check_MK version %s\n", cmk_version.__version__)

    config_cache = config.get_config_cache()
    host_config = config_cache.get_host_config(hostname)

    exit_spec = host_config.exit_code_spec()

    status: ServiceState = 0
    infotexts: List[ServiceDetails] = []
    long_infotexts: List[ServiceAdditionalDetails] = []
    perfdata: List[str] = []
    try:
        # In case of keepalive we always have an ipaddress (can be 0.0.0.0 or :: when
        # address is unknown). When called as non keepalive ipaddress may be None or
        # is already an address (2nd argument)
        if ipaddress is None and not host_config.is_cluster:
            ipaddress = ip_lookup.lookup_ip_address(hostname)

        item_state.load(hostname)

        services = _get_filtered_services(
            host_name=hostname,
            belongs_to_cluster=len(config_cache.clusters_of(hostname)) > 0,
            config_cache=config_cache,
            only_check_plugins=only_check_plugin_names,
        )

        # see which raw sections we may need
        selected_raw_sections = config.get_relevant_raw_sections(
            CheckPluginName(maincheckify(s.check_plugin_name)) for s in services)

        sources = data_sources.DataSources(
            hostname,
            ipaddress,
            sources=data_sources.make_sources(
                host_config,
                ipaddress,
                selected_raw_sections=selected_raw_sections,
            ),
        )
        num_success, plugins_missing_data = _do_all_checks_on_host(
            services,
            sources,
            host_config,
            ipaddress,
            only_check_plugin_names,
        )

        if _submit_to_core:
            item_state.save(hostname)

        for source in sources:
            source_state, source_output, source_perfdata = source.get_summary_result_for_checking()
            if source_output != "":
                status = max(status, source_state)
                infotexts.append("[%s] %s" % (source.id(), source_output))
                perfdata.extend([_convert_perf_data(p) for p in source_perfdata])

        if plugins_missing_data:
            missing_data_status, missing_data_infotext = _check_plugins_missing_data(
                plugins_missing_data,
                exit_spec,
                bool(num_success),
            )
            status = max(status, missing_data_status)
            infotexts.append(missing_data_infotext)

        cpu_tracking.end()
        phase_times = cpu_tracking.get_times()
        total_times = phase_times["TOTAL"]
        run_time = total_times[4]

        infotexts.append("execution time %.1f sec" % run_time)
        if config.check_mk_perfdata_with_times:
            perfdata += [
                "execution_time=%.3f" % run_time,
                "user_time=%.3f" % total_times[0],
                "system_time=%.3f" % total_times[1],
                "children_user_time=%.3f" % total_times[2],
                "children_system_time=%.3f" % total_times[3],
            ]

            for phase, times in phase_times.items():
                if phase in ["agent", "snmp", "ds"]:
                    t = times[4] - sum(times[:4])  # real time - CPU time
                    perfdata.append("cmk_time_%s=%.3f" % (phase, t))
        else:
            perfdata.append("execution_time=%.3f" % run_time)

        return status, infotexts, long_infotexts, perfdata
    finally:
        if _checkresult_file_fd is not None:
            _close_checkresult_file()

        # "ipaddress is not None": At least when working with a cluster host it seems the ipaddress
        # may be None.  This needs to be understood in detail and cleaned up. As the InlineSNMP
        # stats feature is a very rarely used debugging feature, the analyzation and fix is
        # postponed now.
        if config.record_inline_snmp_stats \
           and ipaddress is not None \
           and host_config.snmp_config(ipaddress).is_inline_snmp_host:
            inline.snmp_stats_save()
Example #27
0
def do_inv_check(
    hostname: HostName, options: Dict[str, int]
) -> Tuple[ServiceState, List[ServiceDetails], List[ServiceAdditionalDetails],
           Metric]:
    _inv_hw_changes = options.get("hw-changes", 0)
    _inv_sw_changes = options.get("sw-changes", 0)
    _inv_sw_missing = options.get("sw-missing", 0)
    _inv_fail_status = options.get("inv-fail-status", 1)

    config_cache = config.get_config_cache()
    host_config = config.HostConfig.make_host_config(hostname)
    if host_config.is_cluster:
        ipaddress = None
    else:
        ipaddress = ip_lookup.lookup_ip_address(host_config)

    status = 0
    infotexts: List[str] = []
    long_infotexts: List[str] = []
    perfdata: List[Tuple] = []

    sources = data_sources.make_sources(host_config, ipaddress)
    inventory_tree, status_data_tree = _do_inv_for(
        config_cache,
        host_config,
        ipaddress,
        sources=sources,
        multi_host_sections=None,
    )

    #TODO add cluster if and only if all sources do not fail?
    if _all_sources_fail(host_config, ipaddress):
        old_tree, sources_state = None, 1
        status = max(status, sources_state)
        infotexts.append("Cannot update tree%s" %
                         check_api_utils.state_markers[sources_state])
    else:
        old_tree = _save_inventory_tree(hostname, inventory_tree)

    _run_inventory_export_hooks(host_config, inventory_tree)

    if inventory_tree.is_empty() and status_data_tree.is_empty():
        infotexts.append("Found no data")

    else:
        infotexts.append("Found %d inventory entries" %
                         inventory_tree.count_entries())

        # Node 'software' is always there because _do_inv_for creates this node for cluster info
        if not inventory_tree.get_sub_container(['software']).has_edge('packages')\
           and _inv_sw_missing:
            infotexts.append("software packages information is missing" +
                             check_api_utils.state_markers[_inv_sw_missing])
            status = max(status, _inv_sw_missing)

        if old_tree is not None:
            if not old_tree.is_equal(inventory_tree, edges=["software"]):
                infotext = "software changes"
                if _inv_sw_changes:
                    status = max(status, _inv_sw_changes)
                    infotext += check_api_utils.state_markers[_inv_sw_changes]
                infotexts.append(infotext)

            if not old_tree.is_equal(inventory_tree, edges=["hardware"]):
                infotext = "hardware changes"
                if _inv_hw_changes:
                    status = max(status, _inv_hw_changes)
                    infotext += check_api_utils.state_markers[_inv_hw_changes]

                infotexts.append(infotext)

        if not status_data_tree.is_empty():
            infotexts.append("Found %s status entries" %
                             status_data_tree.count_entries())

    for source in sources:
        source_state, source_output, _source_perfdata = source.get_summary_result_for_inventory(
        )
        if source_state != 0:
            # Do not output informational things (state == 0). Also do not use source states
            # which would overwrite "State when inventory fails" in the ruleset
            # "Do hardware/software Inventory".
            # These information and source states are handled by the "Check_MK" service
            status = max(_inv_fail_status, status)
            infotexts.append("[%s] %s" % (source.id, source_output))

    return status, infotexts, long_infotexts, perfdata