Exemplo n.º 1
0
    def _update_with_parse_function(self, section_content, section_name):
        # type: (AbstractSectionContent, SectionName) -> ParsedSectionContent
        """Transform the section_content using the defined parse functions.

        Some checks define a parse function that is used to transform the section_content
        somehow. It is applied by this function.

        Please note that this is not a check/subcheck individual setting. This option is related
        to the agent section.

        All exceptions raised by the parse function will be catched and re-raised as
        MKParseFunctionError() exceptions."""

        if section_name not in config.check_info:
            return section_content

        parse_function = cast(Callable[[AbstractSectionContent], ParsedSectionContent],
                              config.check_info[section_name]["parse_function"])
        if not parse_function:
            return section_content

        # TODO: Item state needs to be handled in local objects instead of the
        # item_state._cached_item_states object
        orig_item_state_prefix = item_state.get_item_state_prefix()
        try:
            item_state.set_item_state_prefix(section_name, None)
            return parse_function(section_content)
        except Exception:
            if cmk.utils.debug.enabled():
                raise
            raise MKParseFunctionError(*sys.exc_info())
        finally:
            item_state.set_item_state_prefix(*orig_item_state_prefix)

        return section_content
Exemplo n.º 2
0
def initialised_item_state():
    previous = item_state.get_item_state_prefix()
    item_state._cached_item_states.reset()
    item_state.set_item_state_prefix(("unitialised-test-env", None))
    try:
        yield
    finally:
        item_state.set_item_state_prefix(previous)
Exemplo n.º 3
0
def context(plugin_name: CheckPluginName,
            item: Optional[str]) -> Iterator[None]:
    """Set item state prefix"""
    saved_prefix = get_item_state_prefix()
    set_item_state_prefix((str(plugin_name), item))

    try:
        yield
    finally:
        set_item_state_prefix(saved_prefix)
Exemplo n.º 4
0
def context(plugin, item):
    # type: (ItemStateKeyElement, ItemStateKeyElement) -> Iterator[None]
    """Set item state prefix"""
    saved_prefix = get_item_state_prefix()
    set_item_state_prefix(plugin, item)

    try:
        yield
    finally:
        set_item_state_prefix(*saved_prefix)
Exemplo n.º 5
0
def context(plugin_name, item):
    # type: (PluginName, Optional[str]) -> Iterator[None]
    """Set item state prefix"""
    saved_prefix = get_item_state_prefix()
    set_item_state_prefix(str(plugin_name), item)

    try:
        yield
    finally:
        set_item_state_prefix(*saved_prefix)
def _test_context(mock_state: Mapping[str, object]):
    previous_prefix = item_state.get_item_state_prefix()
    item_state._cached_item_states.reset()
    item_state.set_item_state_prefix(("item_state_unit_tests", None))
    for k, v in mock_state.items():
        item_state.set_item_state(k, v)
    try:
        yield
    finally:
        item_state._cached_item_states.reset()
        item_state.set_item_state_prefix(previous_prefix)
Exemplo n.º 7
0
    def _update_with_parse_function(
        section_content: AbstractSectionContent,
        section_name: SectionName,
    ) -> ParsedSectionContent:
        """Transform the section_content using the defined parse functions.

        Some checks define a parse function that is used to transform the section_content
        somehow. It is applied by this function.

        Please note that this is not a check/subcheck individual setting. This option is related
        to the agent section.

        All exceptions raised by the parse function will be catched and re-raised as
        MKParseFunctionError() exceptions."""
        section_plugin = config.get_registered_section_plugin(section_name)
        if section_plugin is None:
            # use legacy parse function for unmigrated sections
            parse_function = config.check_info.get(str(section_name),
                                                   {}).get("parse_function")
            if parse_function is None:
                return section_content
        else:
            # TODO (mo): deal with the parsed_section_name feature (CMK-4006)
            if str(section_plugin.name) != str(
                    section_plugin.parsed_section_name):
                raise NotImplementedError()
            parse_function = section_plugin.parse_function

        # TODO (mo): make this unnecessary
        parse_function = cast(
            Callable[[AbstractSectionContent], ParsedSectionContent],
            parse_function)

        # TODO: Item state needs to be handled in local objects instead of the
        # item_state._cached_item_states object
        # TODO (mo): ValueStores (formally Item state) need to be *only* available
        # from within the check function, nowhere else.
        orig_item_state_prefix = item_state.get_item_state_prefix()
        try:
            item_state.set_item_state_prefix(section_name, None)
            return parse_function(section_content)

        except item_state.MKCounterWrapped:
            raise

        except Exception:
            if cmk.utils.debug.enabled():
                raise
            raise MKParseFunctionError(*sys.exc_info())

        finally:
            item_state.set_item_state_prefix(*orig_item_state_prefix)
Exemplo n.º 8
0
def get_precompiled_check_table(hostname,
                                remove_duplicates=True,
                                filter_mode=None,
                                skip_ignored=True):
    # type: (str, bool, Optional[str], bool) -> List[Service]
    """The precompiled check table is somehow special compared to the regular check table.

    a) It is sorted by the service dependencies (which are only relevant for Nagios). The
       sorting is important here to send the state updates to Nagios in the correct order.
       Sending the updates in this order gives Nagios a consistent state in a shorter time.
    b) More important: Some special checks pre-compue a new set of parameters
       using a plugin specific precompile_params function. It's purpose is to
       perform time consuming ruleset evaluations once without the need to perform
       it during each check execution.

       The effective check parameters are calculated in these steps:

       1. Read from config
         a) autochecks + cmk.base.config.compute_check_parameters()
         b) static checks

       2. Execute the precompile params function
         The precompile_params function can base on the "params" from a static check or
         autocheck and computes a new "params".

         This is the last step that may be cached across the single executions.

       3. Execute the check
         During check execution will update the check parameters once more with
         checking.legacy_determine_check_params() right before execution the check.
    """
    host_checks = _get_sorted_check_table(hostname,
                                          remove_duplicates,
                                          filter_mode=filter_mode,
                                          skip_ignored=skip_ignored)
    services = []  # type: List[Service]
    for service in host_checks:
        # make these globals available to the precompile function
        check_api_utils.set_service(service.check_plugin_name,
                                    service.description)
        item_state.set_item_state_prefix(service.check_plugin_name,
                                         service.item)

        precompiled_parameters = get_precompiled_check_parameters(
            hostname, service.item, service.parameters,
            service.check_plugin_name)
        services.append(
            Service(service.check_plugin_name, service.item,
                    service.description, precompiled_parameters,
                    service.service_labels))
    return services
Exemplo n.º 9
0
    def _update_with_parse_function(
        section_content: ABCRawDataSection,
        section_name: SectionName,
        check_legacy_info: Dict[str, Dict[str, Any]],
    ) -> ParsedSectionContent:
        """Transform the section_content using the defined parse functions.

        Some checks define a parse function that is used to transform the section_content
        somehow. It is applied by this function.

        Please note that this is not a check/subcheck individual setting. This option is related
        to the agent section.

        All exceptions raised by the parse function will be catched and re-raised as
        MKParseFunctionError() exceptions."""
        # We can use the migrated section: we refuse to migrate sections with
        # "'node_info'=True", so the auto-migrated ones will keep working.
        # This function will never be called on checks programmed against the new
        # API (or migrated manually)
        if not agent_based_register.is_registered_section_plugin(section_name):
            # use legacy parse function for unmigrated sections
            parse_function = check_legacy_info.get(str(section_name),
                                                   {}).get("parse_function")
        else:
            section_plugin = agent_based_register.get_section_plugin(
                section_name)
            parse_function = cast(
                Callable[[ABCRawDataSection], ParsedSectionContent],
                section_plugin.parse_function)

        if parse_function is None:
            return section_content

        # (mo): ValueStores (formally Item state) need to be *only* available
        # from within the check function, nowhere else.
        orig_item_state_prefix = item_state.get_item_state_prefix()
        try:
            item_state.set_item_state_prefix(section_name, None)
            return parse_function(section_content)

        except item_state.MKCounterWrapped:
            raise

        except Exception:
            if cmk.utils.debug.enabled():
                raise
            raise MKParseFunctionError(*sys.exc_info())

        finally:
            item_state.set_item_state_prefix(*orig_item_state_prefix)
Exemplo n.º 10
0
def _execute_check_legacy_mode(multi_host_sections: MultiHostSections, hostname: HostName,
                               ipaddress: Optional[HostAddress], service: Service) -> bool:
    legacy_check_plugin_name = config.legacy_check_plugin_names.get(service.check_plugin_name)
    if legacy_check_plugin_name is None:
        _submit_check_result(hostname, service.description, CHECK_NOT_IMPLEMENTED, None)
        return True

    check_function = config.check_info[legacy_check_plugin_name].get("check_function")
    if check_function is None:
        _submit_check_result(hostname, service.description, CHECK_NOT_IMPLEMENTED, None)
        return True

    # Make a bit of context information globally available, so that functions
    # called by checks know this context. check_api_utils.set_service has
    # already been called.
    item_state.set_item_state_prefix(str(service.check_plugin_name), service.item)

    section_name = legacy_check_plugin_name.split('.')[0]

    section_content = None
    mgmt_board_info = config.get_management_board_precedence(section_name, config.check_info)
    source_type = SourceType.MANAGEMENT if mgmt_board_info == LEGACY_MGMT_ONLY else SourceType.HOST
    try:
        section_content = multi_host_sections.get_section_content(
            HostKey(hostname, ipaddress, source_type),
            mgmt_board_info,
            section_name,
            for_discovery=False,
            cluster_node_keys=config.get_config_cache().get_clustered_service_node_keys(
                hostname,
                source_type,
                service.description,
                ip_lookup.lookup_ip_address,
            ),
            check_legacy_info=config.check_info,
        )

        # TODO: Move this to a helper function
        if section_content is None:  # No data for this check type
            return False

        # Call the actual check function
        item_state.reset_wrapped_counters()

        used_params = legacy_determine_check_params(service.parameters)
        raw_result = check_function(service.item, used_params, section_content)
        result = sanitize_check_result(raw_result)
        item_state.raise_counter_wrap()

    except item_state.MKCounterWrapped as e:
        # handle check implementations that do not yet support the
        # handling of wrapped counters via exception on their own.
        # Do not submit any check result in that case:
        console.verbose("%-20s PEND - Cannot compute check result: %s\n",
                        ensure_str(service.description), e)
        # Don't submit to core - we're done.
        return True

    except MKTimeout:
        raise

    except Exception:
        if cmk.utils.debug.enabled():
            raise
        result = 3, cmk.base.crash_reporting.create_check_crash_dump(
            hostname,
            service.check_plugin_name,
            {
                "item": service.item,
                "params": used_params,
                "section_content": section_content
            },
            is_manual_check(hostname, service.id()),
            service.description,
        ), []

    _submit_check_result(
        hostname,
        service.description,
        result,
        _legacy_determine_cache_info(multi_host_sections, SectionName(section_name)),
    )
    return True
Exemplo n.º 11
0
def execute_check(config_cache, multi_host_sections, hostname, ipaddress,
                  check_plugin_name, item, params, description):
    # type: (config.ConfigCache, data_sources.MultiHostSections, HostName, Optional[HostAddress], CheckPluginName, Item, CheckParameters, ServiceName) -> Optional[bool]
    # Make a bit of context information globally available, so that functions
    # called by checks now this context
    check_api_utils.set_service(check_plugin_name, description)
    item_state.set_item_state_prefix(check_plugin_name, item)

    # Skip checks that are not in their check period
    period = config_cache.check_period_of_service(hostname, description)
    if period is not None:
        if not cmk.base.core.check_timeperiod(period):
            console.verbose(
                "Skipping service %s: currently not in timeperiod %s.\n",
                six.ensure_str(description), period)
            return None
        console.vverbose("Service %s: timeperiod %s is currently active.\n",
                         six.ensure_str(description), period)

    section_name = cmk.base.check_utils.section_name_of(check_plugin_name)

    dont_submit = False
    section_content = None
    try:
        # TODO: There is duplicate code with discovery._execute_discovery(). Find a common place!
        try:
            section_content = multi_host_sections.get_section_content(
                hostname,
                ipaddress,
                section_name,
                for_discovery=False,
                service_description=description)
        except MKParseFunctionError as e:
            x = e.exc_info()
            # re-raise the original exception to not destory the trace. This may raise a MKCounterWrapped
            # exception which need to lead to a skipped check instead of a crash
            # TODO CMK-3729, PEP-3109
            new_exception = x[0](x[1])
            new_exception.__traceback__ = x[2]  # type: ignore[attr-defined]
            raise new_exception

        # TODO: Move this to a helper function
        if section_content is None:  # No data for this check type
            return False

        # In case of SNMP checks but missing agent response, skip this check.
        # TODO: This feature predates the 'parse_function', and is not needed anymore.
        # # Special checks which still need to be called even with empty data
        # # may declare this.
        if not section_content and cmk.base.check_utils.is_snmp_check(check_plugin_name) \
           and not config.check_info[check_plugin_name]["handle_empty_info"]:
            return False

        check_function = config.check_info[check_plugin_name].get(
            "check_function")
        if check_function is None:
            check_function = lambda item, params, section_content: (
                3, 'UNKNOWN - Check not implemented')

        # Call the actual check function
        item_state.reset_wrapped_counters()

        raw_result = check_function(item, determine_check_params(params),
                                    section_content)
        result = sanitize_check_result(
            raw_result, cmk.base.check_utils.is_snmp_check(check_plugin_name))
        item_state.raise_counter_wrap()

    except item_state.MKCounterWrapped as e:
        # handle check implementations that do not yet support the
        # handling of wrapped counters via exception on their own.
        # Do not submit any check result in that case:
        console.verbose("%-20s PEND - Cannot compute check result: %s\n",
                        six.ensure_str(description), e)
        dont_submit = True

    except MKTimeout:
        raise

    except Exception as e:
        if cmk.utils.debug.enabled():
            raise
        result = 3, cmk.base.crash_reporting.create_check_crash_dump(
            hostname, check_plugin_name, item,
            is_manual_check(hostname, check_plugin_name, item), params,
            description, section_content), []

    if not dont_submit:
        # Now add information about the age of the data in the agent
        # sections. This is in data_sources.g_agent_cache_info. For clusters we
        # use the oldest of the timestamps, of course.
        oldest_cached_at = None
        largest_interval = None

        def minn(a, b):
            # type: (Optional[int], Optional[int]) -> Optional[int]
            if a is None:
                return b
            if b is None:
                return a
            return min(a, b)

        for host_sections in multi_host_sections.get_host_sections().values():
            section_entries = host_sections.cache_info
            if section_name in section_entries:
                cached_at, cache_interval = section_entries[section_name]
                oldest_cached_at = minn(oldest_cached_at, cached_at)
                largest_interval = max(largest_interval, cache_interval)

        _submit_check_result(hostname,
                             description,
                             result,
                             cached_at=oldest_cached_at,
                             cache_interval=largest_interval)
    return True
Exemplo n.º 12
0
def execute_check(multi_host_sections, hostname, ipaddress, service):
    # type: (data_sources.MultiHostSections, HostName, Optional[HostAddress], Service) -> bool
    check_function = config.check_info[service.check_plugin_name].get(
        "check_function")
    if check_function is None:
        _submit_check_result(hostname, service.description,
                             CHECK_NOT_IMPLEMENTED, (None, None))
        return True

    # Make a bit of context information globally available, so that functions
    # called by checks now this context
    check_api_utils.set_service(service.check_plugin_name, service.description)
    item_state.set_item_state_prefix(service.check_plugin_name, service.item)

    section_name = cmk.base.check_utils.section_name_of(
        service.check_plugin_name)

    section_content = None
    try:
        # TODO: There is duplicate code with discovery._execute_discovery(). Find a common place!
        try:
            section_content = multi_host_sections.get_section_content(
                hostname,
                ipaddress,
                section_name,
                for_discovery=False,
                service_description=service.description)
        except MKParseFunctionError as e:
            x = e.exc_info()
            # re-raise the original exception to not destory the trace. This may raise a MKCounterWrapped
            # exception which need to lead to a skipped check instead of a crash
            # TODO CMK-3729, PEP-3109
            new_exception = x[0](x[1])
            new_exception.__traceback__ = x[2]  # type: ignore[attr-defined]
            raise new_exception

        # TODO: Move this to a helper function
        if section_content is None:  # No data for this check type
            return False

        # Call the actual check function
        item_state.reset_wrapped_counters()

        raw_result = check_function(service.item,
                                    determine_check_params(service.parameters),
                                    section_content)
        result = sanitize_check_result(raw_result)
        item_state.raise_counter_wrap()

    except item_state.MKCounterWrapped as e:
        # handle check implementations that do not yet support the
        # handling of wrapped counters via exception on their own.
        # Do not submit any check result in that case:
        console.verbose("%-20s PEND - Cannot compute check result: %s\n",
                        six.ensure_str(service.description), e)
        # Don't submit to core - we're done.
        return True

    except MKTimeout:
        raise

    except Exception:
        if cmk.utils.debug.enabled():
            raise
        result = 3, cmk.base.crash_reporting.create_check_crash_dump(
            hostname, service.check_plugin_name, service.item,
            is_manual_check(hostname, service.check_plugin_name, service.item),
            service.parameters, service.description, section_content), []

    _submit_check_result(
        hostname,
        service.description,
        result,
        determine_cache_info(multi_host_sections, section_name),
    )
    return True