Example #1
0
def event_match_contactgroups(rule: EventRule,
                              context: EventContext) -> Optional[str]:
    required_groups = rule.get("match_contactgroups")
    if required_groups is None:
        return None

    if context["WHAT"] == "SERVICE":
        cgn = context.get("SERVICECONTACTGROUPNAMES")
    else:
        cgn = context.get("HOSTCONTACTGROUPNAMES")

    if cgn is None:
        return None

    if not cgn:
        return "The object is in no group, but %s is required" % (
            " or ".join(required_groups))

    contactgroups = cgn.split(",")
    for group in required_groups:
        if group in contactgroups:
            return None

    return "The object is only in the groups %s, but %s is required" % (
        cgn,
        " or ".join(required_groups),
    )
Example #2
0
def event_match_servicelevel(rule: EventRule,
                             context: EventContext) -> Optional[str]:
    if "match_sl" in rule:
        from_sl, to_sl = rule["match_sl"]
        if context["WHAT"] == "SERVICE" and context.get("SVC_SL",
                                                        "").isdigit():
            sl = saveint(context.get("SVC_SL"))
        else:
            sl = saveint(context.get("HOST_SL"))

        if sl < from_sl or sl > to_sl:
            return "The service level %d is not between %d and %d." % (
                sl, from_sl, to_sl)
    return None
Example #3
0
def pipe_decode_raw_context(raw_context: EventContext) -> None:
    """
    cmk_base replaces all occurences of the pipe symbol in the infotext with
    the character "Light vertical bar" before a check result is submitted to
    the core. We remove this special encoding here since it may result in
    gibberish output when deliered via a notification plugin.
    """
    def _remove_pipe_encoding(value):
        return value.replace("\u2758", "|")

    output = raw_context.get("SERVICEOUTPUT")
    if output:
        raw_context["SERVICEOUTPUT"] = _remove_pipe_encoding(output)
    long_output = raw_context.get("LONGSERVICEOUTPUT")
    if long_output:
        raw_context["LONGSERVICEOUTPUT"] = _remove_pipe_encoding(long_output)
Example #4
0
def _event_match_servicegroups(rule: EventRule, context: EventContext,
                               is_regex: bool) -> Optional[str]:
    if is_regex:
        match_type, required_groups = rule.get("match_servicegroups_regex",
                                               (None, None))
    else:
        required_groups = rule.get("match_servicegroups")

    if context["WHAT"] != "SERVICE":
        if required_groups:
            return (
                "This rule requires membership in a service group, but this is a host notification"
            )
        return None

    if required_groups is not None:
        sgn = context.get("SERVICEGROUPNAMES")
        if sgn is None:
            return (
                "No information about service groups is in the context, but service "
                "must be in group %s" % (" or ".join(required_groups)))
        if sgn:
            servicegroups = sgn.split(",")
        else:
            return "The service is in no service group, but %s%s is required" % (
                (is_regex and "regex " or ""),
                " or ".join(required_groups),
            )

        for group in required_groups:
            if is_regex:
                r = regex(group)
                for sg in servicegroups:
                    match_value = (config.define_servicegroups[sg]
                                   if match_type == "match_alias" else sg)
                    if r.search(match_value):
                        return None
            elif group in servicegroups:
                return None

        if is_regex:
            if match_type == "match_alias":
                return (
                    "The service is only in the groups %s. None of these patterns match: %s"
                    % (
                        '"' + '", "'.join(config.define_servicegroups[x]
                                          for x in servicegroups) + '"',
                        '"' + '" or "'.join(required_groups),
                    ) + '"')

            return (
                "The service is only in the groups %s. None of these patterns match: %s"
                % ('"' + '", "'.join(servicegroups) + '"',
                   '"' + '" or "'.join(required_groups)) + '"')

        return "The service is only in the groups %s, but %s is required" % (
            sgn,
            " or ".join(required_groups),
        )
    return None
Example #5
0
def event_match_folder(rule: EventRule,
                       context: EventContext) -> Optional[str]:
    if "match_folder" in rule:
        mustfolder = rule["match_folder"]
        mustpath = mustfolder.split("/")
        hasfolder = None
        for tag in context.get("HOSTTAGS", "").split():
            if tag.startswith("/wato/"):
                hasfolder = tag[6:].rstrip("/")
                haspath = hasfolder.split("/")
                if mustpath == [
                        "",
                ]:
                    return None  # Match is on main folder, always OK
                while mustpath:
                    if not haspath or mustpath[0] != haspath[0]:
                        return "The rule requires folder '%s', but the host is in '%s'" % (
                            mustfolder,
                            hasfolder,
                        )
                    mustpath = mustpath[1:]
                    haspath = haspath[1:]

        if hasfolder is None:
            return "The host is not managed in Setup, but the rule requires a folder"
    return None
Example #6
0
def event_match_hosttags(rule: EventRule,
                         context: EventContext) -> Optional[str]:
    required = rule.get("match_hosttags")
    if required:
        tags = context.get("HOSTTAGS", "").split()
        if not config.hosttags_match_taglist(tags, required):
            return "The host's tags %s do not match the required tags %s" % (
                "|".join(tags),
                "|".join(required),
            )
    return None
Example #7
0
def event_match_site(rule: EventRule, context: EventContext) -> Optional[str]:
    if "match_site" not in rule:
        return None

    required_site_ids = rule["match_site"]

    # Fallback to local site ID in case there is none in the context
    site_id = context.get("OMD_SITE", omd_site())

    if site_id not in required_site_ids:
        return "The site '%s' is not in the required sites list: %s" % (
            site_id,
            ",".join(required_site_ids),
        )
    return None
Example #8
0
def add_rulebased_macros(raw_context: EventContext) -> None:
    # For the rule based notifications we need the list of contacts
    # an object has. The CMC does send this in the macro "CONTACTS"
    if "CONTACTS" not in raw_context:
        contact_list = livestatus_fetch_contacts(
            raw_context["HOSTNAME"], raw_context.get("SERVICEDESC"))
        if contact_list is not None:
            raw_context["CONTACTS"] = ",".join(contact_list)
        else:
            raw_context[
                "CONTACTS"] = "?"  # means: contacts could not be determined!

    # Add a pseudo contact name. This is needed for the correct creation
    # of spool files. Spool files are created on a per-contact-base, as in classical
    # notifications the core sends out one individual notification per contact.
    # In the case of rule based notifications we do not make distinctions between
    # the various contacts.
    raw_context["CONTACTNAME"] = "check-mk-notify"
Example #9
0
def _event_match_exclude_servicegroups(rule: EventRule, context: EventContext,
                                       is_regex: bool) -> Optional[str]:
    if is_regex:
        match_type, excluded_groups = rule.get(
            "match_exclude_servicegroups_regex", (None, None))
    else:
        excluded_groups = rule.get("match_exclude_servicegroups")

    if context["WHAT"] != "SERVICE":
        # excluded_groups do not apply to a host notification
        return None

    if excluded_groups is not None:
        context_sgn = context.get("SERVICEGROUPNAMES")
        if not context_sgn:
            # No actual groups means no possible negative match
            return None

        servicegroups = context_sgn.split(",")

        for group in excluded_groups:
            if is_regex:
                r = regex(group)
                for sg in servicegroups:
                    match_value = (config.define_servicegroups[sg]
                                   if match_type == "match_alias" else sg)
                    match_value_inverse = (sg
                                           if match_type == "match_alias" else
                                           config.define_servicegroups[sg])

                    if r.search(match_value):
                        return 'The service group "%s" (%s) is excluded per regex pattern: %s' % (
                            match_value,
                            match_value_inverse,
                            group,
                        )
            elif group in servicegroups:
                return "The service group %s is excluded" % group
    return None
Example #10
0
def event_match_hostgroups(rule: EventRule,
                           context: EventContext) -> Optional[str]:
    required_groups = rule.get("match_hostgroups")
    if required_groups is not None:
        hgn = context.get("HOSTGROUPNAMES")
        if hgn is None:
            return (
                "No information about host groups is in the context, but host "
                "must be in group %s" % (" or ".join(required_groups)))
        if hgn:
            hostgroups = hgn.split(",")
        else:
            return "The host is in no group, but %s is required" % (
                " or ".join(required_groups))

        for group in required_groups:
            if group in hostgroups:
                return None

        return "The host is only in the groups %s, but %s is required" % (
            hgn,
            " or ".join(required_groups),
        )
    return None
Example #11
0
def complete_raw_context(raw_context: EventContext, with_dump: bool) -> None:
    """Extend the raw notification context

    This ensures that all raw contexts processed in the notification code has specific variables
    set. Add a few further helper variables that are useful in notification and alert plugins.

    Please not that this is not only executed on the source system. When notifications are
    forwarded to another site and the analysis is executed on that site, this function will be
    executed on the central site. So be sure not to overwrite site specific things.
    """

    raw_keys = list(raw_context)

    try:
        raw_context["WHAT"] = "SERVICE" if raw_context.get(
            "SERVICEDESC") else "HOST"

        raw_context.setdefault("MONITORING_HOST", socket.gethostname())
        raw_context.setdefault("OMD_ROOT", str(cmk.utils.paths.omd_root))
        raw_context.setdefault("OMD_SITE", omd_site())

        # The Checkmk Micro Core sends the MICROTIME and no other time stamps. We add
        # a few Nagios-like variants in order to be compatible
        if "MICROTIME" in raw_context:
            microtime = int(raw_context["MICROTIME"])
            timestamp = float(microtime) / 1000000.0
            broken = time.localtime(timestamp)
            raw_context["DATE"] = time.strftime("%Y-%m-%d", broken)
            raw_context["SHORTDATETIME"] = time.strftime(
                "%Y-%m-%d %H:%M:%S", broken)
            raw_context["LONGDATETIME"] = time.strftime(
                "%a %b %d %H:%M:%S %Z %Y", broken)
        elif "MICROTIME" not in raw_context:
            # In case the microtime is not provided, e.g. when using Nagios, then set it here
            # from the current time. We could look for "LONGDATETIME" and calculate the timestamp
            # from that one, but we try to keep this simple here.
            raw_context["MICROTIME"] = "%d" % (time.time() * 1000000)

        raw_context[
            "HOSTURL"] = "/check_mk/index.py?start_url=view.py?%s" % quote(
                urlencode([
                    ("view_name", "hoststatus"),
                    ("host", raw_context["HOSTNAME"]),
                    ("site", raw_context["OMD_SITE"]),
                ]))
        if raw_context["WHAT"] == "SERVICE":
            raw_context[
                "SERVICEURL"] = "/check_mk/index.py?start_url=view.py?%s" % quote(
                    urlencode([
                        ("view_name", "service"),
                        ("host", raw_context["HOSTNAME"]),
                        ("service", raw_context["SERVICEDESC"]),
                        ("site", raw_context["OMD_SITE"]),
                    ]))

        # Relative Timestamps for several macros
        if (value := raw_context.get("LASTHOSTSTATECHANGE")) is not None:
            raw_context["LASTHOSTSTATECHANGE_REL"] = get_readable_rel_date(
                value)
        if (value := raw_context.get("LASTSERVICESTATECHANGE")) is not None:
            raw_context["LASTSERVICESTATECHANGE_REL"] = get_readable_rel_date(
                value)
Example #12
0
def find_host_service_in_context(context: EventContext) -> str:
    host = context.get("HOSTNAME", "UNKNOWN")
    service = context.get("SERVICEDESC")
    if service:
        return host + ";" + service
    return host
Example #13
0
def render_context_dump(raw_context: EventContext) -> str:
    return "Raw context:\n" + "\n".join("                    %s=%s" % v
                                        for v in sorted(raw_context.items())  #
                                        )