예제 #1
0
파일: checking.py 프로젝트: arusa/checkmk
def host_context(host_name: HostName, *, write_state: bool):
    """Make a bit of context information globally available

    So that functions called by checks know this context.
    This is used for both legacy and agent_based API.
    """
    # TODO: this is a mixture of legacy and new Check-API mechanisms. Clean this up!
    try:
        check_api_utils.set_hostname(host_name)
        item_state.load(host_name)
        yield
    finally:
        check_api_utils.reset_hostname()
        if write_state:
            item_state.save(host_name)
        item_state.cleanup_item_states()
예제 #2
0
def _discover_services(
    *,
    host_name: HostName,
    ipaddress: Optional[HostAddress],
    parsed_sections_broker: ParsedSectionsBroker,
    discovery_parameters: DiscoveryParameters,
    run_only_plugin_names: Optional[Set[CheckPluginName]],
) -> List[Service]:
    # find out which plugins we need to discover
    plugin_candidates = _find_candidates(parsed_sections_broker,
                                         run_only_plugin_names)
    section.section_step("Executing discovery plugins (%d)" %
                         len(plugin_candidates))
    console.vverbose("  Trying discovery with: %s\n" %
                     ", ".join(str(n) for n in plugin_candidates))
    # The host name must be set for the host_name() calls commonly used to determine the
    # host name for host_extra_conf{_merged,} calls in the legacy checks.
    check_api_utils.set_hostname(host_name)

    service_table: cmk.base.check_utils.CheckTable = {}
    try:
        for check_plugin_name in plugin_candidates:
            try:
                service_table.update({
                    service.id(): service
                    for service in _discover_plugins_services(
                        check_plugin_name=check_plugin_name,
                        host_name=host_name,
                        ipaddress=ipaddress,
                        parsed_sections_broker=parsed_sections_broker,
                        discovery_parameters=discovery_parameters,
                    )
                })
            except (KeyboardInterrupt, MKTimeout):
                raise
            except Exception as e:
                if discovery_parameters.on_error == "raise":
                    raise
                if discovery_parameters.on_error == "warn":
                    console.error("Discovery of '%s' failed: %s\n" %
                                  (check_plugin_name, e))

        return list(service_table.values())

    except KeyboardInterrupt:
        raise MKGeneralException("Interrupted by Ctrl-C.")
예제 #3
0
파일: snmp.py 프로젝트: sri-sysad/checkmk
    def __call__(
        self,
        snmp_config: SNMPHostConfig,
        on_error: str,
        do_snmp_scan: bool,
        for_mgmt_board: bool,
    ) -> Set[SectionName]:
        """Returns a list of raw sections that shall be processed by this source.

        The logic is only processed once. Once processed, the answer is cached.
        """
        if self._filter_function is None:
            raise MKGeneralException(
                "The check type filter function has not been set")

        if self._cached_result is not None:
            return self._cached_result

        # Make hostname globally available for scan functions.
        # This is rarely used, but e.g. the scan for if/if64 needs
        # this to evaluate if_disabled_if64_checks.
        check_api_utils.set_hostname(snmp_config.hostname)
        found_plugins = self._filter_function(
            self.sections(),
            on_error=on_error,
            do_snmp_scan=do_snmp_scan,
            binary_host=config.get_config_cache().in_binary_hostlist(
                snmp_config.hostname,
                config.snmp_without_sys_descr,
            ),
            backend=factory.backend(snmp_config),
        )
        self._cached_result = {
            SectionName(s)
            for s in config.filter_by_management_board(
                snmp_config.hostname,
                found_plugins,
                for_mgmt_board=for_mgmt_board,
                for_discovery=True,
            )
        }
        return self._cached_result
예제 #4
0
def test_get_effective_service_level(monkeypatch):
    ts = Scenario().add_host("testhost1")
    ts.add_host("testhost2")
    ts.add_host("testhost3")
    ts.set_ruleset(
        "host_service_levels",
        [
            (10, [], ["testhost2"], {}),
            (2, [], ["testhost2"], {}),
        ],
    )
    ts.set_ruleset(
        "service_service_levels",
        [
            (33, [], ["testhost1"], ["CPU load$"], {}),
        ],
    )
    ts.apply(monkeypatch)

    check_api_utils.set_service("cpu.loads", "CPU load")

    check_api_utils.set_hostname("testhost1")
    assert check_api.get_effective_service_level() == 33
    check_api_utils.set_hostname("testhost2")
    assert check_api.get_effective_service_level() == 10
    check_api_utils.set_hostname("testhost3")
    assert check_api.get_effective_service_level() == 0
예제 #5
0
def _do_all_checks_on_host(
    config_cache: config.ConfigCache,
    host_config: config.HostConfig,
    ipaddress: Optional[HostAddress],
    multi_host_sections: MultiHostSections,
    *,
    services: List[Service],
    only_check_plugins: Optional[Set[CheckPluginName]] = None,
) -> Tuple[int, List[CheckPluginName]]:
    hostname: HostName = host_config.hostname
    num_success = 0
    plugins_missing_data: Set[CheckPluginName] = set()

    check_api_utils.set_hostname(hostname)
    for service in services:
        success = execute_check(multi_host_sections, host_config, ipaddress, service)
        if success:
            num_success += 1
        else:
            plugins_missing_data.add(service.check_plugin_name)

    return num_success, sorted(plugins_missing_data)
예제 #6
0
def _do_all_checks_on_host(
    services: List[Service],
    sources: data_sources.DataSources,
    host_config: config.HostConfig,
    ipaddress: Optional[HostAddress],
    only_check_plugins: Optional[Set[CheckPluginName]] = None,
) -> Tuple[int, List[CheckPluginName]]:
    hostname: HostName = host_config.hostname

    num_success = 0
    plugins_missing_data: Set[CheckPluginName] = set()

    check_api_utils.set_hostname(hostname)

    # Gather the data from the sources
    nodes = sources.make_nodes(host_config)
    multi_host_sections = sources.get_host_sections(nodes,
                                                    max_cachefile_age=host_config.max_cachefile_age)

    for service in services:

        success = execute_check(multi_host_sections, host_config, ipaddress, service)
        if success:
            num_success += 1
        else:
            # TODO (mo): centralize maincheckify: CMK-4295
            plugins_missing_data.add(CheckPluginName(maincheckify(service.check_plugin_name)))

    import cmk.base.inventory as inventory  # pylint: disable=import-outside-toplevel
    inventory.do_inventory_actions_during_checking_for(
        sources,
        multi_host_sections,
        host_config,
        ipaddress,
    )

    return num_success, sorted(plugins_missing_data)
예제 #7
0
def _do_all_checks_on_host(sources,
                           host_config,
                           ipaddress,
                           only_check_plugin_names=None):
    # type: (data_sources.DataSources, config.HostConfig, Optional[HostAddress], Optional[List[str]]) -> Tuple[int, List[SectionName]]
    hostname = host_config.hostname  # type: HostName
    config_cache = config.get_config_cache()

    num_success, missing_sections = 0, set()

    check_api_utils.set_hostname(hostname)

    filter_mode = None

    belongs_to_cluster = len(config_cache.clusters_of(hostname)) > 0
    if belongs_to_cluster:
        filter_mode = "include_clustered"

    services = check_table.get_precompiled_check_table(hostname,
                                                       remove_duplicates=True,
                                                       filter_mode=filter_mode)

    # When check types are specified via command line, enforce them. Otherwise use the
    # list of checks defined by the check table.
    if only_check_plugin_names is None:
        only_check_plugins = {
            service.check_plugin_name
            for service in services
        }
    else:
        only_check_plugins = set(only_check_plugin_names)

    sources.enforce_check_plugin_names(only_check_plugins)

    # Gather the data from the sources
    multi_host_sections = sources.get_host_sections()

    # Filter out check types which are not used on the node
    if belongs_to_cluster:
        pos_match = set()
        neg_match = set()
        for service in services:
            if hostname != config_cache.host_of_clustered_service(
                    hostname, service.description):
                pos_match.add(service.check_plugin_name)
            else:
                neg_match.add(service.check_plugin_name)
        only_check_plugins -= (pos_match - neg_match)

    for service in services:
        if only_check_plugins is not None and service.check_plugin_name not in only_check_plugins:
            continue

        if belongs_to_cluster and hostname != config_cache.host_of_clustered_service(
                hostname, service.description):
            continue

        success = execute_check(config_cache, multi_host_sections, hostname,
                                ipaddress, service.check_plugin_name,
                                service.item, service.parameters,
                                service.description)
        if success:
            num_success += 1
        elif success is None:
            # If the service is in any timeperiod we do not want to
            # - increase num_success or
            # - add to missing sections
            continue
        else:
            missing_sections.add(
                cmk.base.check_utils.section_name_of(
                    service.check_plugin_name))

    import cmk.base.inventory as inventory  # pylint: disable=import-outside-toplevel
    inventory.do_inventory_actions_during_checking_for(sources,
                                                       multi_host_sections,
                                                       host_config, ipaddress)

    missing_section_list = sorted(missing_sections)
    return num_success, missing_section_list
예제 #8
0
def _do_all_checks_on_host(sources,
                           host_config,
                           ipaddress,
                           only_check_plugin_names=None):
    # type: (data_sources.DataSources, config.HostConfig, Optional[HostAddress], Optional[List[str]]) -> Tuple[int, List[SectionName]]
    hostname = host_config.hostname  # type: HostName
    config_cache = config.get_config_cache()

    num_success, missing_sections = 0, set()

    check_api_utils.set_hostname(hostname)

    belongs_to_cluster = len(config_cache.clusters_of(hostname)) > 0

    services = check_table.get_precompiled_check_table(
        hostname,
        remove_duplicates=True,
        filter_mode="include_clustered" if belongs_to_cluster else None,
    )

    # When check types are specified via command line, enforce them. Otherwise use the
    # list of checks defined by the check table.
    if only_check_plugin_names is None:
        only_check_plugins = {
            service.check_plugin_name
            for service in services
        }
    else:
        only_check_plugins = set(only_check_plugin_names)

    sources.enforce_check_plugin_names(only_check_plugins)

    # Gather the data from the sources
    multi_host_sections = sources.get_host_sections()

    def _is_not_of_host(host_name, service):
        return hostname != config_cache.host_of_clustered_service(
            hostname, service.description)

    # Filter out check types which are not used on the node
    if belongs_to_cluster:
        removed_plugins = {
            plugin
            for plugin in only_check_plugins if all(
                _is_not_of_host(hostname, service) for service in services
                if service.check_plugin_name == plugin)
        }
        only_check_plugins -= removed_plugins

    for service in services:
        if service.check_plugin_name not in only_check_plugins:
            continue
        if belongs_to_cluster and _is_not_of_host(hostname, service):
            continue
        if service_outside_check_period(config_cache, hostname,
                                        service.description):
            continue

        success = execute_check(multi_host_sections, hostname, ipaddress,
                                service)
        if success:
            num_success += 1
        else:
            missing_sections.add(
                cmk.base.check_utils.section_name_of(
                    service.check_plugin_name))

    import cmk.base.inventory as inventory  # pylint: disable=import-outside-toplevel
    inventory.do_inventory_actions_during_checking_for(sources,
                                                       multi_host_sections,
                                                       host_config, ipaddress)

    missing_section_list = sorted(missing_sections)
    return num_success, missing_section_list
예제 #9
0
def _create_nagios_servicedefs(cfg, config_cache, hostname, host_attrs):
    # type: (NagiosConfig, ConfigCache, HostName, ObjectAttributes) -> None
    import cmk.base.check_table as check_table  # pylint: disable=import-outside-toplevel

    host_config = config_cache.get_host_config(hostname)

    check_mk_attrs = core_config.get_service_attributes(
        hostname, "Check_MK", config_cache)

    #   _____
    #  |___ /
    #    |_ \
    #   ___) |
    #  |____/   3. Services

    def do_omit_service(hostname, description):
        # type: (HostName, ServiceName) -> bool
        if config.service_ignored(hostname, None, description):
            return True
        if hostname != config_cache.host_of_clustered_service(
                hostname, description):
            return True
        return False

    def get_dependencies(hostname, servicedesc):
        # type: (HostName, ServiceName) -> str
        result = ""
        for dep in config.service_depends_on(hostname, servicedesc):
            result += _format_nagios_object(
                "servicedependency", {
                    "use": config.service_dependency_template,
                    "host_name": hostname,
                    "service_description": dep,
                    "dependent_host_name": hostname,
                    "dependent_service_description": servicedesc,
                })

        return result

    services = check_table.get_check_table(hostname,
                                           remove_duplicates=True).values()
    have_at_least_one_service = False
    used_descriptions = {
    }  # type: Dict[ServiceName, Tuple[CheckPluginName, Item]]
    for service in sorted(services,
                          key=lambda s: (s.check_plugin_name, s.item)):
        if service.check_plugin_name not in config.check_info:
            continue  # simply ignore missing checks

        # Make sure, the service description is unique on this host
        if service.description in used_descriptions:
            cn, it = used_descriptions[service.description]
            # TODO: Remove "type: ignore" once we are on python3
            core_config.warning(
                "ERROR: Duplicate service description '%s' for host '%s'!\n"  # type: ignore[arg-type]
                " - 1st occurrance: checktype = %s, item = %r\n"
                " - 2nd occurrance: checktype = %s, item = %r\n" %
                (service.description, hostname, cn, it,
                 service.check_plugin_name, service.item))
            continue

        used_descriptions[service.description] = (service.check_plugin_name,
                                                  service.item)
        if config.check_info[service.check_plugin_name].get(
                "has_perfdata", False):
            template = config.passive_service_template_perf
        else:
            template = config.passive_service_template

        # Services Dependencies for autochecks
        cfg.write(get_dependencies(hostname, service.description))

        service_spec = {
            "use": template,
            "host_name": hostname,
            "service_description": service.description,
            "check_command": "check_mk-%s" % service.check_plugin_name,
        }

        service_spec.update(
            core_config.get_cmk_passive_service_attributes(
                config_cache, host_config, service, check_mk_attrs))
        service_spec.update(
            _extra_service_conf_of(cfg, config_cache, hostname,
                                   service.description))

        cfg.write(_format_nagios_object("service", service_spec))

        cfg.checknames_to_define.add(service.check_plugin_name)
        have_at_least_one_service = True

    # Active check for check_mk
    if have_at_least_one_service:
        service_spec = {
            "use": config.active_service_template,
            "host_name": hostname,
            "service_description": "Check_MK",
        }
        service_spec.update(check_mk_attrs)
        service_spec.update(
            _extra_service_conf_of(cfg, config_cache, hostname, "Check_MK"))
        cfg.write(_format_nagios_object("service", service_spec))

    # legacy checks via active_checks
    actchecks = []
    for plugin_name, entries in host_config.active_checks:
        cfg.active_checks_to_define.add(plugin_name)
        act_info = config.active_check_info[plugin_name]
        for params in entries:
            actchecks.append((plugin_name, act_info, params))

    if actchecks:
        cfg.write("\n\n# Active checks\n")
        for acttype, act_info, params in actchecks:
            # Make hostname available as global variable in argument functions
            check_api_utils.set_hostname(hostname)

            has_perfdata = act_info.get('has_perfdata', False)
            description = config.active_check_service_description(
                hostname, acttype, params)

            if do_omit_service(hostname, description):
                continue

            # compute argument, and quote ! and \ for Nagios
            args = core_config.active_check_arguments(
                hostname,
                description, act_info["argument_function"](params)).replace(
                    "\\", "\\\\").replace("!", "\\!")

            if description in used_descriptions:
                cn, it = used_descriptions[description]
                # If we have the same active check again with the same description,
                # then we do not regard this as an error, but simply ignore the
                # second one. That way one can override a check with other settings.
                if cn == "active(%s)" % acttype:
                    continue

                # TODO: Remove "type: ignore" once we are on python3
                core_config.warning(
                    "ERROR: Duplicate service description (active check) '%s' for host '%s'!\n"  # type: ignore[arg-type]
                    " - 1st occurrance: checktype = %s, item = %r\n"
                    " - 2nd occurrance: checktype = active(%s), item = None\n"
                    % (description, hostname, cn, it, acttype))
                continue

            used_descriptions[description] = ("active(" + acttype + ")",
                                              description)

            template = "check_mk_perf," if has_perfdata else ""

            if host_attrs["address"] in ["0.0.0.0", "::"]:
                command_name = "check-mk-custom"
                command = command_name + "!echo \"CRIT - Failed to lookup IP address and no explicit IP address configured\" && exit 2"
                cfg.custom_commands_to_define.add(command_name)
            else:
                command = "check_mk_active-%s!%s" % (acttype, args)

            service_spec = {
                "use": "%scheck_mk_default" % template,
                "host_name": hostname,
                "service_description": description,
                "check_command": _simulate_command(cfg, command),
                "active_checks_enabled": str(1),
            }
            service_spec.update(
                core_config.get_service_attributes(hostname, description,
                                                   config_cache))
            service_spec.update(
                _extra_service_conf_of(cfg, config_cache, hostname,
                                       description))
            cfg.write(_format_nagios_object("service", service_spec))

            # write service dependencies for active checks
            cfg.write(get_dependencies(hostname, description))

    # Legacy checks via custom_checks
    custchecks = host_config.custom_checks
    if custchecks:
        cfg.write("\n\n# Custom checks\n")
        for entry in custchecks:
            # entries are dicts with the following keys:
            # "service_description"        Service description to use
            # "command_line"  (optional)   Unix command line for executing the check
            #                              If this is missing, we create a passive check
            # "command_name"  (optional)   Name of Monitoring command to define. If missing,
            #                              we use "check-mk-custom"
            # "has_perfdata"  (optional)   If present and True, we activate perf_data
            description = config.get_final_service_description(
                hostname, entry["service_description"])
            has_perfdata = entry.get("has_perfdata", False)
            command_name = entry.get("command_name", "check-mk-custom")
            command_line = entry.get("command_line", "")

            if do_omit_service(hostname, description):
                continue

            if command_line:
                command_line = core_config.autodetect_plugin(
                    command_line).replace("\\", "\\\\").replace("!", "\\!")

            if "freshness" in entry:
                freshness = {
                    "check_freshness": 1,
                    "freshness_threshold": 60 * entry["freshness"]["interval"],
                }
                command_line = "echo %s && exit %d" % (_quote_nagios_string(
                    entry["freshness"]["output"]), entry["freshness"]["state"])
            else:
                freshness = {}

            cfg.custom_commands_to_define.add(command_name)

            if description in used_descriptions:
                cn, it = used_descriptions[description]
                # If we have the same active check again with the same description,
                # then we do not regard this as an error, but simply ignore the
                # second one.
                if cn == "custom(%s)" % command_name:
                    continue
                # TODO: Remove "type: ignore" once we are on python3
                core_config.warning(
                    "ERROR: Duplicate service description (custom check) '%s' for host '%s'!\n"  # type: ignore[arg-type]
                    " - 1st occurrance: checktype = %s, item = %r\n"
                    " - 2nd occurrance: checktype = custom(%s), item = %r\n" %
                    (description, hostname, cn, it, command_name, description))
                continue

            used_descriptions[description] = ("custom(%s)" % command_name,
                                              description)

            template = "check_mk_perf," if has_perfdata else ""
            command = "%s!%s" % (command_name, command_line)

            service_spec = {
                "use":
                "%scheck_mk_default" % template,
                "host_name":
                hostname,
                "service_description":
                description,
                "check_command":
                _simulate_command(cfg, command),
                "active_checks_enabled":
                str(1 if (command_line and not freshness) else 0),
            }
            service_spec.update(freshness)
            service_spec.update(
                core_config.get_service_attributes(hostname, description,
                                                   config_cache))
            service_spec.update(
                _extra_service_conf_of(cfg, config_cache, hostname,
                                       description))
            cfg.write(_format_nagios_object("service", service_spec))

            # write service dependencies for custom checks
            cfg.write(get_dependencies(hostname, description))

    service_discovery_name = config_cache.service_discovery_name()

    # Inventory checks - if user has configured them.
    params = host_config.discovery_check_parameters
    if host_config.add_service_discovery_check(params, service_discovery_name):
        service_spec = {
            "use": config.inventory_check_template,
            "host_name": hostname,
            "service_description": service_discovery_name,
        }
        service_spec.update(
            core_config.get_service_attributes(hostname,
                                               service_discovery_name,
                                               config_cache))

        service_spec.update(
            _extra_service_conf_of(cfg, config_cache, hostname,
                                   service_discovery_name))

        service_spec.update({
            "check_interval": params["check_interval"],
            "retry_interval": params["check_interval"],
        })

        cfg.write(_format_nagios_object("service", service_spec))

        if have_at_least_one_service:
            cfg.write(
                _format_nagios_object(
                    "servicedependency", {
                        "use": config.service_dependency_template,
                        "host_name": hostname,
                        "service_description": "Check_MK",
                        "dependent_host_name": hostname,
                        "dependent_service_description":
                        service_discovery_name,
                    }))

    # No check_mk service, no legacy service -> create PING service
    if not have_at_least_one_service and not actchecks and not custchecks:
        _add_ping_service(cfg, config_cache, host_config,
                          host_attrs["address"],
                          host_config.is_ipv6_primary and 6 or 4, "PING",
                          host_attrs.get("_NODEIPS"))

    if host_config.is_ipv4v6_host:
        if host_config.is_ipv6_primary:
            _add_ping_service(cfg, config_cache, host_config,
                              host_attrs["_ADDRESS_4"], 4, "PING IPv4",
                              host_attrs.get("_NODEIPS_4"))
        else:
            _add_ping_service(cfg, config_cache, host_config,
                              host_attrs["_ADDRESS_6"], 6, "PING IPv6",
                              host_attrs.get("_NODEIPS_6"))
예제 #10
0
def _precompile_hostcheck(config_cache, hostname):
    # type: (ConfigCache, HostName) -> None
    host_config = config_cache.get_host_config(hostname)

    console.verbose("%s%s%-16s%s:",
                    tty.bold,
                    tty.blue,
                    hostname,
                    tty.normal,
                    stream=sys.stderr)

    check_api_utils.set_hostname(hostname)

    compiled_filename = cmk.utils.paths.precompiled_hostchecks_dir + "/" + hostname
    source_filename = compiled_filename + ".py"
    for fname in [compiled_filename, source_filename]:
        try:
            os.remove(fname)
        except OSError as e:
            if e.errno != errno.ENOENT:
                raise

    needed_check_plugin_names = _get_needed_check_plugin_names(host_config)
    if not needed_check_plugin_names:
        console.verbose("(no Check_MK checks)\n")
        return

    output = open(source_filename + ".new", "w")
    output.write("#!/usr/bin/env python3\n")
    output.write("# encoding: utf-8\n\n")

    output.write("import logging\n")
    output.write("import sys\n\n")

    output.write("if not sys.executable.startswith('/omd'):\n")
    output.write(
        "    sys.stdout.write(\"ERROR: Only executable with sites python\\n\")\n"
    )
    output.write("    sys.exit(2)\n\n")

    # Remove precompiled directory from sys.path. Leaving it in the path
    # makes problems when host names (name of precompiled files) are equal
    # to python module names like "random"
    output.write("sys.path.pop(0)\n")

    output.write("import cmk.utils.log\n")
    output.write("import cmk.utils.debug\n")
    output.write("from cmk.utils.exceptions import MKTerminate\n")
    output.write("\n")
    output.write("import cmk.base.utils\n")
    output.write("import cmk.base.config as config\n")
    output.write("import cmk.base.console as console\n")
    output.write("import cmk.base.checking as checking\n")
    output.write("import cmk.base.check_api as check_api\n")
    output.write("import cmk.base.ip_lookup as ip_lookup\n")

    # Self-compile: replace symlink with precompiled python-code, if
    # we are run for the first time
    if config.delay_precompile:
        output.write("""
import os
if os.path.islink(%(dst)r):
    import py_compile
    os.remove(%(dst)r)
    py_compile.compile(%(src)r, %(dst)r, %(dst)r, True)
    os.chmod(%(dst)r, 0755)

""" % {
            "src": source_filename,
            "dst": compiled_filename
        })

    # Register default Check_MK signal handler
    output.write("cmk.base.utils.register_sigint_handler()\n")

    # initialize global variables
    output.write("""
# very simple commandline parsing: only -v (once or twice) and -d are supported

cmk.utils.log.setup_console_logging()
logger = logging.getLogger("cmk.base")

# TODO: This is not really good parsing, because it not cares about syntax like e.g. "-nv".
#       The later regular argument parsing is handling this correctly. Try to clean this up.
cmk.utils.log.logger.setLevel(cmk.utils.log.verbosity_to_log_level(len([ a for a in sys.argv if a in [ "-v", "--verbose"] ])))

if '-d' in sys.argv:
    cmk.utils.debug.enable()

""")

    output.write("config.load_checks(check_api.get_check_api_context, %r)\n" %
                 _get_needed_check_file_names(needed_check_plugin_names))

    for check_plugin_name in sorted(needed_check_plugin_names):
        console.verbose(" %s%s%s",
                        tty.green,
                        check_plugin_name,
                        tty.normal,
                        stream=sys.stderr)

    output.write("config.load_packed_config()\n")

    # IP addresses
    needed_ipaddresses, needed_ipv6addresses, = {}, {}
    if host_config.is_cluster:
        if host_config.nodes is None:
            raise TypeError()

        for node in host_config.nodes:
            node_config = config_cache.get_host_config(node)
            if node_config.is_ipv4_host:
                needed_ipaddresses[node] = ip_lookup.lookup_ipv4_address(node)

            if node_config.is_ipv6_host:
                needed_ipv6addresses[node] = ip_lookup.lookup_ipv6_address(
                    node)

        try:
            if host_config.is_ipv4_host:
                needed_ipaddresses[hostname] = ip_lookup.lookup_ipv4_address(
                    hostname)
        except Exception:
            pass

        try:
            if host_config.is_ipv6_host:
                needed_ipv6addresses[hostname] = ip_lookup.lookup_ipv6_address(
                    hostname)
        except Exception:
            pass
    else:
        if host_config.is_ipv4_host:
            needed_ipaddresses[hostname] = ip_lookup.lookup_ipv4_address(
                hostname)

        if host_config.is_ipv6_host:
            needed_ipv6addresses[hostname] = ip_lookup.lookup_ipv6_address(
                hostname)

    output.write("config.ipaddresses = %r\n\n" % needed_ipaddresses)
    output.write("config.ipv6addresses = %r\n\n" % needed_ipv6addresses)

    # perform actual check with a general exception handler
    output.write("try:\n")
    output.write("    sys.exit(checking.do_check(%r, None))\n" % hostname)
    output.write("except MKTerminate:\n")
    output.write("    console.output('<Interrupted>\\n', stream=sys.stderr)\n")
    output.write("    sys.exit(1)\n")
    output.write("except SystemExit as e:\n")
    output.write("    sys.exit(e.code)\n")
    output.write("except Exception as e:\n")
    output.write("    import traceback, pprint\n")

    # status output message
    output.write(
        "    sys.stdout.write(\"UNKNOWN - Exception in precompiled check: %s (details in long output)\\n\" % e)\n"
    )

    # generate traceback for long output
    output.write(
        "    sys.stdout.write(\"Traceback: %s\\n\" % traceback.format_exc())\n"
    )

    output.write("\n")
    output.write("    sys.exit(3)\n")
    output.close()

    # compile python (either now or delayed), but only if the source
    # code has not changed. The Python compilation is the most costly
    # operation here.
    if os.path.exists(source_filename):
        if open(source_filename).read() == open(source_filename +
                                                ".new").read():
            console.verbose(" (%s is unchanged)\n",
                            source_filename,
                            stream=sys.stderr)
            os.remove(source_filename + ".new")
            return
        console.verbose(" (new content)", stream=sys.stderr)

    os.rename(source_filename + ".new", source_filename)
    if not config.delay_precompile:
        py_compile.compile(source_filename, compiled_filename,
                           compiled_filename, True)
        os.chmod(compiled_filename, 0o755)
    else:
        if os.path.exists(compiled_filename) or os.path.islink(
                compiled_filename):
            os.remove(compiled_filename)
        os.symlink(hostname + ".py", compiled_filename)

    console.verbose(" ==> %s.\n", compiled_filename, stream=sys.stderr)
예제 #11
0
def _snmp_scan(host_config,
               on_error="ignore",
               for_inv=False,
               do_snmp_scan=True,
               for_mgmt_board=False):
    import cmk.base.inventory_plugins as inventory_plugins

    # Make hostname globally available for scan functions.
    # This is rarely used, but e.g. the scan for if/if64 needs
    # this to evaluate if_disabled_if64_checks.
    check_api_utils.set_hostname(host_config.hostname)

    snmp.initialize_single_oid_cache(host_config)
    console.vverbose("  SNMP scan:\n")
    if not config.get_config_cache().in_binary_hostlist(
            host_config.hostname, config.snmp_without_sys_descr):
        for oid, name in [(".1.3.6.1.2.1.1.1.0", "system description"),
                          (".1.3.6.1.2.1.1.2.0", "system object")]:
            value = snmp.get_single_oid(host_config,
                                        oid,
                                        do_snmp_scan=do_snmp_scan)
            if value is None:
                raise MKSNMPError(
                    "Cannot fetch %s OID %s. This might be OK for some bogus devices. "
                    "In that case please configure the ruleset \"Hosts without system "
                    "description OID\" to tell Check_MK not to fetch the system "
                    "description and system object OIDs." % (name, oid))
    else:
        # Fake OID values to prevent issues with a lot of scan functions
        console.vverbose(
            "       Skipping system description OID "
            "(Set .1.3.6.1.2.1.1.1.0 and .1.3.6.1.2.1.1.2.0 to \"\")\n")
        snmp.set_single_oid_cache(host_config, ".1.3.6.1.2.1.1.1.0", "")
        snmp.set_single_oid_cache(host_config, ".1.3.6.1.2.1.1.2.0", "")

    found_check_plugin_names = []
    if for_inv:
        items = inventory_plugins.inv_info.items()
    else:
        items = config.check_info.items()

    positive_found = []
    default_found = []

    for check_plugin_name, _unused_check in items:
        if config.service_ignored(host_config.hostname, check_plugin_name,
                                  None):
            continue
        else:
            if for_inv and not inventory_plugins.is_snmp_plugin(
                    check_plugin_name):
                continue
            elif not for_inv and not cmk.base.check_utils.is_snmp_check(
                    check_plugin_name):
                continue

        section_name = cmk.base.check_utils.section_name_of(check_plugin_name)
        # The scan function should be assigned to the section_name, because
        # subchecks sharing the same SNMP info of course should have
        # an identical scan function. But some checks do not do this
        # correctly
        if check_plugin_name in config.snmp_scan_functions:
            scan_function = config.snmp_scan_functions[check_plugin_name]
        elif section_name in config.snmp_scan_functions:
            scan_function = config.snmp_scan_functions[section_name]
        elif section_name in inventory_plugins.inv_info:
            scan_function = inventory_plugins.inv_info[section_name].get(
                "snmp_scan_function")
        else:
            scan_function = None

        if scan_function:
            try:

                def oid_function(oid,
                                 default_value=None,
                                 cp_name=check_plugin_name):
                    value = snmp.get_single_oid(host_config,
                                                oid,
                                                cp_name,
                                                do_snmp_scan=do_snmp_scan)
                    return default_value if value is None else value

                result = scan_function(oid_function)
                if result is not None and not isinstance(result, (str, bool)):
                    if on_error == "warn":
                        console.warning(
                            "   SNMP scan function of %s returns invalid type %s."
                            % (check_plugin_name, type(result)))
                    elif on_error == "raise":
                        raise MKGeneralException("SNMP Scan aborted.")
                elif result:
                    found_check_plugin_names.append(check_plugin_name)
                    positive_found.append(check_plugin_name)
            except MKGeneralException:
                # some error messages which we explicitly want to show to the user
                # should be raised through this
                raise
            except Exception:
                if on_error == "warn":
                    console.warning(
                        "   Exception in SNMP scan function of %s" %
                        check_plugin_name)
                elif on_error == "raise":
                    raise
        else:
            found_check_plugin_names.append(check_plugin_name)
            default_found.append(check_plugin_name)

    _output_snmp_check_plugins("SNMP scan found", positive_found)
    if default_found:
        _output_snmp_check_plugins("SNMP without scan function", default_found)

    filtered = config.filter_by_management_board(host_config.hostname,
                                                 found_check_plugin_names,
                                                 for_mgmt_board,
                                                 for_discovery=True,
                                                 for_inventory=for_inv)

    _output_snmp_check_plugins("SNMP filtered check plugin names", filtered)
    snmp.write_single_oid_cache(host_config)
    return sorted(filtered)
예제 #12
0
def _snmp_scan(host_config,
               on_error="ignore",
               for_inv=False,
               do_snmp_scan=True,
               for_mgmt_board=False):
    # type: (SNMPHostConfig, str, bool, bool, bool) -> Set[CheckPluginName]
    import cmk.base.inventory_plugins as inventory_plugins  # pylint: disable=import-outside-toplevel

    # Make hostname globally available for scan functions.
    # This is rarely used, but e.g. the scan for if/if64 needs
    # this to evaluate if_disabled_if64_checks.
    check_api_utils.set_hostname(host_config.hostname)

    snmp_cache.initialize_single_oid_cache(host_config)
    console.vverbose("  SNMP scan:\n")
    if not config.get_config_cache().in_binary_hostlist(host_config.hostname,
                                                        config.snmp_without_sys_descr):
        for oid, name in [(".1.3.6.1.2.1.1.1.0", "system description"),
                          (".1.3.6.1.2.1.1.2.0", "system object")]:
            value = snmp.get_single_oid(host_config, oid, do_snmp_scan=do_snmp_scan)
            if value is None:
                raise MKSNMPError(
                    "Cannot fetch %s OID %s. This might be OK for some bogus devices. "
                    "In that case please configure the ruleset \"Hosts without system "
                    "description OID\" to tell Check_MK not to fetch the system "
                    "description and system object OIDs." % (name, oid))
    else:
        # Fake OID values to prevent issues with a lot of scan functions
        console.vverbose("       Skipping system description OID "
                         "(Set .1.3.6.1.2.1.1.1.0 and .1.3.6.1.2.1.1.2.0 to \"\")\n")
        snmp_cache.set_single_oid_cache(".1.3.6.1.2.1.1.1.0", "")
        snmp_cache.set_single_oid_cache(".1.3.6.1.2.1.1.2.0", "")

    if for_inv:
        these_plugin_names = [
            name for name in inventory_plugins.inv_info if inventory_plugins.is_snmp_plugin(name)
        ]
    else:
        # TODO (mo): stop converting to string!
        these_plugin_names = [str(n) for n in config.registered_snmp_sections]

    found_plugins = set()  # type: Set[CheckPluginName]

    for check_plugin_name in these_plugin_names:
        if config.service_ignored(host_config.hostname, check_plugin_name, None):
            continue

        detection_spec = _get_detection_spec_from_plugin_name(check_plugin_name,
                                                              inventory_plugins.inv_info)

        if detection_spec is None:
            console.warning("   SNMP check %s: Could not detect specifications for plugin" %
                            check_plugin_name)

            continue

        try:

            def oid_function(oid, default_value=None, cp_name=check_plugin_name):
                # type: (OID, Optional[DecodedString], Optional[CheckPluginName]) -> Optional[DecodedString]
                value = snmp.get_single_oid(host_config, oid, cp_name, do_snmp_scan=do_snmp_scan)
                return default_value if value is None else value

            if callable(detection_spec):
                result = detection_spec(oid_function)
            else:
                result = _evaluate_snmp_detection(oid_function, detection_spec)

            if result is not None and not isinstance(result, (str, bool)):
                if on_error == "warn":
                    console.warning("   SNMP scan function of %s returns invalid type %s." %
                                    (check_plugin_name, type(result)))
                elif on_error == "raise":
                    raise MKGeneralException("SNMP Scan aborted.")
            elif result:
                found_plugins.add(check_plugin_name)
        except MKGeneralException:
            # some error messages which we explicitly want to show to the user
            # should be raised through this
            raise
        except Exception:
            if on_error == "warn":
                console.warning("   Exception in SNMP scan function of %s" % check_plugin_name)
            elif on_error == "raise":
                raise

    _output_snmp_check_plugins("SNMP scan found", found_plugins)

    filtered = config.filter_by_management_board(
        host_config.hostname,
        found_plugins,
        for_mgmt_board,
        for_discovery=True,
        for_inventory=for_inv,
    )

    _output_snmp_check_plugins("SNMP filtered check plugin names", filtered)
    snmp_cache.write_single_oid_cache(host_config)
    return filtered
예제 #13
0
def _snmp_scan(host_config,
               on_error="ignore",
               for_inv=False,
               do_snmp_scan=True,
               for_mgmt_board=False):
    # type: (SNMPHostConfig, str, bool, bool, bool) -> Set[CheckPluginName]
    import cmk.base.inventory_plugins as inventory_plugins  # pylint: disable=import-outside-toplevel

    # Make hostname globally available for scan functions.
    # This is rarely used, but e.g. the scan for if/if64 needs
    # this to evaluate if_disabled_if64_checks.
    check_api_utils.set_hostname(host_config.hostname)

    snmp_cache.initialize_single_oid_cache(host_config)
    console.vverbose("  SNMP scan:\n")
    if not config.get_config_cache().in_binary_hostlist(
            host_config.hostname, config.snmp_without_sys_descr):
        for oid, name in [(".1.3.6.1.2.1.1.1.0", "system description"),
                          (".1.3.6.1.2.1.1.2.0", "system object")]:
            value = snmp.get_single_oid(host_config,
                                        oid,
                                        do_snmp_scan=do_snmp_scan)
            if value is None:
                raise MKSNMPError(
                    "Cannot fetch %s OID %s. This might be OK for some bogus devices. "
                    "In that case please configure the ruleset \"Hosts without system "
                    "description OID\" to tell Check_MK not to fetch the system "
                    "description and system object OIDs." % (name, oid))
    else:
        # Fake OID values to prevent issues with a lot of scan functions
        console.vverbose(
            "       Skipping system description OID "
            "(Set .1.3.6.1.2.1.1.1.0 and .1.3.6.1.2.1.1.2.0 to \"\")\n")
        snmp_cache.set_single_oid_cache(".1.3.6.1.2.1.1.1.0", "")
        snmp_cache.set_single_oid_cache(".1.3.6.1.2.1.1.2.0", "")

    # TODO (mo): Assumption here is that inventory plugins are significantly fewer
    #            than check plugins. We should pass an explicit list along, instead
    #            of this flag. That way we would also get rid of the import above.
    if for_inv:
        section_names = [PluginName(n) for n in inventory_plugins.inv_info]
        these_sections = [
            config.registered_snmp_sections[section_name]
            for section_name in section_names
            if section_name in config.registered_snmp_sections
        ]
    else:
        these_sections = list(config.registered_snmp_sections.values())

    found_plugins = set()  # type: Set[CheckPluginName]

    for section_plugin in these_sections:

        try:

            if _evaluate_snmp_detection(
                    section_plugin.detect_spec,
                    host_config,
                    str(section_plugin.name),
                    do_snmp_scan,
            ):
                found_plugins.add(str(section_plugin.name))

        except MKGeneralException:
            # some error messages which we explicitly want to show to the user
            # should be raised through this
            raise
        except Exception:
            if on_error == "warn":
                console.warning("   Exception in SNMP scan function of %s" %
                                section_plugin.name)
            elif on_error == "raise":
                raise

    _output_snmp_check_plugins("SNMP scan found", found_plugins)

    filtered = config.filter_by_management_board(
        host_config.hostname,
        found_plugins,
        for_mgmt_board,
        for_discovery=True,
        for_inventory=for_inv,
    )

    _output_snmp_check_plugins("SNMP filtered check plugin names", filtered)
    snmp_cache.write_single_oid_cache(host_config)
    return filtered