예제 #1
0
def check_cmciii_lcp_fanunit(item, params, info):
    if params is None:
        params = {}
    _unit_desc, unit_status, _desc, status = info[0][1:4]
    temps = extract_cmciii_lcp_temps(info[0][4:])

    status, message, perfdata = check_temperature(
        temps[4],
        params,
        "cmciii_lcp_fanunit_%s" % item,
        dev_status=translate_cmciii_lcp_status(unit_status),
        dev_status_name="Unit: %s" % unit_status,
        dev_levels=(temps[2], temps[3]),
        dev_levels_lower=(temps[1], temps[0]),
    )

    output_unit = params.get("output_unit", "c")

    message += " ; Top/Mid/Bottom: %s/%s/%s" % (
        render_temp(temps[5], output_unit),
        render_temp(temps[6], output_unit),
        render_temp(temps[7], output_unit),
    )

    return status, message, perfdata
예제 #2
0
def check_temperature_list(sensorlist, params, unique_name):
    params = _migrate_params(params)

    output_unit = params.get("output_unit", "c")

    def worststate(a, b):
        if a != 3 and b != 3:
            return max(a, b)
        if a != 2 and b != 2:
            return 3
        return 2

    if sensorlist == []:
        return None

    sensor_count = len(sensorlist)
    tempsum = 0
    tempmax = sensorlist[0][1]
    tempmin = sensorlist[0][1]
    status = 0
    detailtext = ""
    for entry in sensorlist:

        if len(entry) == 2:
            sub_item, temp = entry
            kwargs = {}
        else:
            sub_item, temp, kwargs = entry
        if not isinstance(temp, (float, int)):
            temp = float(temp)

        tempsum += temp
        tempmax = max(tempmax, temp)
        tempmin = min(tempmin, temp)
        sub_status, sub_infotext, _sub_perfdata = check_temperature(
            temp, params, None, **kwargs)
        status = worststate(status, sub_status)
        if status != 0:
            detailtext += sub_item + ": " + sub_infotext + state_markers[
                sub_status] + ", "
    if detailtext:
        detailtext = " " + detailtext[:
                                      -2]  # Drop trailing ", ", add space to join with summary

    unitsym = temp_unitsym[output_unit]
    tempavg = tempsum / float(sensor_count)
    summarytext = "%d Sensors; Highest: %s %s, Average: %s %s, Lowest: %s %s" % (
        sensor_count,
        render_temp(tempmax, output_unit),
        unitsym,
        render_temp(tempavg, output_unit),
        unitsym,
        render_temp(tempmin, output_unit),
        unitsym,
    )
    infotext = summarytext + detailtext
    perfdata = [("temp", tempmax)]

    if "trend_compute" in params and "period" in params["trend_compute"]:
        usr_warn, usr_crit = params.get("levels") or (None, None)
        usr_warn_lower, usr_crit_lower = params.get("levels_lower") or (None,
                                                                        None)

        # no support for dev_unit or dev_levels in check_temperature_list so
        # this ignores the device level handling set in params
        _warn, crit, _warn_lower, crit_lower = check_temperature_determine_levels(
            "usr", usr_warn, usr_crit, usr_warn_lower, usr_crit_lower, None,
            None, None, None)

        trend_status, trend_infotext = check_temperature_trend(
            tempavg, params["trend_compute"], output_unit, crit, crit_lower,
            unique_name)
        status = max(status, trend_status)
        if trend_infotext:
            infotext += ", " + trend_infotext

    return status, infotext, perfdata
예제 #3
0
def check_temperature(
    reading: Number,
    params: TempParamType,
    unique_name: Optional[AnyStr],
    dev_unit: AnyStr = "c",
    dev_levels: Optional[TwoLevelsType] = None,
    dev_levels_lower: Optional[TwoLevelsType] = None,
    dev_status: Optional[StatusType] = None,
    dev_status_name: AnyStr = None,
) -> CheckType:
    """Check temperature levels and trends.

    The function will check the supplied data and supplied user configuration against the
    temperature reading and warn/crit on failed levels or trends.

    Args:
        reading (Number): The numeric temperature value itself.
        params (dict): A dictionary giving the user's configuration. See below.
        unique_name (str): The name under which to track perf-data.
        dev_unit (str): The unit. May be one of 'c', 'f' or 'k'. Default is 'c'.
        dev_levels (Optional[LevelsType]): The upper levels (warn, crit)
        dev_levels_lower (Optional[LevelsType]): The lower levels (warn, crit)
        dev_status (Optional[Number]): The status according to the device itself.
        dev_status_name (Optional[AnyStr]): What the device thinks the status should be called.

    Configuration:
        The parameter `params` may contain user configurable settings with the following keys:
            - ``input_unit`` -- The device's unit, user defined.
            - ``output_unit`` -- The unit by which to report.
            - ``levels`` -- Upper levels, user defined.
            - ``levels_lower`` -- Lower levels, user defined.
            - ``device_levels_handling`` -- One of the following modes:
                - ``usrdefault`` (default) -- Use user's levels, if not there use device's levels.
                - ``usr`` -- Always use user's levels. Ignore device's levels.
                - ``devdefault`` -- Use device's levels, if not there use user's levels.
                - ``dev`` -- Always use device's levels. Ignore users's levels.
                - ``best`` -- Report on the best case of user's and device's levels.
                - ``worst`` -- Report on the worst case of user's and device's levels.
            - ``trend_compute`` -- A dictionary of the following values:
                - ``period`` -- The observation period for trend computation in minutes.
                - ``trend_levels`` -- Levels on temp increase per period. (warn, crit)
                - ``trend_levels_lower`` -- Levels on temp decrease per period. (warn, crit)
                - ``trend_timeleft`` -- Levels on the time left until crit (upper or lower).

        The parameter `params` may also be one of the following legacy formats (do not use!):
            - None -- discarded
            - (None, None) -- discarded
            - (int|float, int|float) -- reused as params['levels']

    GUI:
         - cmk/gui/plugins/wato/check_parameters/temperature.py

    """
    # Convert legacy tuple params into new dict
    params = _migrate_params(params)

    # Convert reading into Celsius
    input_unit = params.get("input_unit", dev_unit)
    output_unit = params.get("output_unit", "c")
    temp = to_celsius(reading, input_unit)

    # Prepare levels, dealing with user defined and device's own levels
    usr_levels = _normalize_level(params.get("levels"))
    usr_levels_lower = _normalize_level(params.get("levels_lower"))
    dev_levels = _normalize_level(dev_levels)
    dev_levels_lower = _normalize_level(dev_levels_lower)

    # Set all user levels to None. None means do not impose a level
    usr_warn, usr_crit = usr_levels or (None, None)
    usr_warn_lower, usr_crit_lower = usr_levels_lower or (None, None)

    # Same for device levels
    dev_warn, dev_crit = to_celsius(dev_levels or (None, None), dev_unit)
    dev_warn_lower, dev_crit_lower = to_celsius(
        dev_levels_lower or (None, None), dev_unit)

    # Decide which of user's and device's levels should be used according to the setting
    # "device_levels_handling". Result is four variables: {warn,crit}{,_lower}
    dlh = params.get("device_levels_handling", "usrdefault")

    effective_levels = check_temperature_determine_levels(
        dlh,
        usr_warn,
        usr_crit,
        usr_warn_lower,
        usr_crit_lower,
        dev_warn,
        dev_crit,
        dev_warn_lower,
        dev_crit_lower,
    )

    if dlh == "usr" or (dlh == "usrdefault" and usr_levels):
        # ignore device status if user-levels are used
        dev_status = None

    # infotext does some device/user specifics
    status, _, perfdata = check_levels(  # type: ignore[name-defined]
        temp,
        "temp",
        effective_levels,
    )

    if dev_status is not None:
        if dlh == "best":
            status = min(status, dev_status)
        else:
            status = max(status, dev_status)

    # Render actual temperature, e.g. "17.8 °F"
    infotext = "%s %s" % (render_temp(temp,
                                      output_unit), temp_unitsym[output_unit])

    if dev_status is not None and dev_status != 0 and dev_status_name:  # omit status in OK case
        infotext += ", %s" % dev_status_name

    # In case of a non-OK status output the information about the levels
    if status != 0:
        usr_levelstext = ""
        usr_levelstext_lower = ""
        dev_levelstext = ""
        dev_levelstext_lower = ""

        if usr_warn is not None and usr_crit is not None:
            usr_levelstext = " (warn/crit at %s/%s %s)" % (
                render_temp(usr_warn, output_unit),
                render_temp(usr_crit, output_unit),
                temp_unitsym[output_unit],
            )

        if usr_warn_lower is not None and usr_crit_lower is not None:
            usr_levelstext_lower = " (warn/crit below %s/%s %s)" % (
                render_temp(usr_warn_lower, output_unit),
                render_temp(usr_crit_lower, output_unit),
                temp_unitsym[output_unit],
            )

        if dev_levels:
            dev_levelstext = " (device warn/crit at %s/%s %s)" % (
                render_temp(dev_warn, output_unit),
                render_temp(dev_crit, output_unit),
                temp_unitsym[output_unit],
            )

        if dev_levels_lower:
            dev_levelstext_lower = " (device warn/crit below %s/%s %s)" % (
                render_temp(dev_warn_lower, output_unit),
                render_temp(dev_crit_lower, output_unit),
                temp_unitsym[output_unit],
            )

        # Output only levels that are relevant when computing the state
        if dlh == "usr":
            infotext += usr_levelstext + usr_levelstext_lower

        elif dlh == "dev":
            infotext += dev_levelstext + dev_levelstext_lower

        elif dlh in ("best", "worst"):
            infotext += (usr_levelstext + usr_levelstext_lower +
                         dev_levelstext + dev_levelstext_lower)

        elif dlh == "devdefault":
            infotext += dev_levelstext + dev_levelstext_lower
            if not dev_levels:
                infotext += usr_levelstext
            if not dev_levels_lower:
                infotext += usr_levelstext_lower

        elif dlh == "usrdefault":
            infotext += usr_levelstext + usr_levelstext_lower
            if not usr_levels:
                infotext += dev_levelstext
            if not usr_levels_lower:
                infotext += dev_levelstext_lower

    # all checks specify a unique_name but when multiple sensors are handled through
    #   check_temperature_list, trend is only calculated for the average and then the individual
    #   calls to check_temperate receive no unique_name
    # "trend_compute" in params tells us if there if there is configuration for trend computation
    #   when activating trend computation through the website, "period" is always set together with
    #   the trend_compute dictionary. But a check may want to specify default levels for trends
    #   without activating them. In this case they can leave period unset to deactivate the
    #   feature.
    if unique_name and params.get("trend_compute",
                                  {}).get("period") is not None:
        crit = effective_levels[1]
        crit_lower = effective_levels[3]
        trend_status, trend_infotext = check_temperature_trend(
            temp, params["trend_compute"], output_unit, crit, crit_lower,
            unique_name)
        status = max(status, trend_status)
        if trend_infotext:
            infotext += ", " + trend_infotext

    return status, infotext, perfdata
예제 #4
0
def check_temperature_trend(temp, params, output_unit, crit, crit_lower,
                            unique_name):
    def combiner(status, infotext):
        if "status" in dir(combiner):
            combiner.status = max(combiner.status, status)
        else:
            combiner.status = status

        if "infotext" in dir(combiner):
            combiner.infotext += ", " + infotext
        else:
            combiner.infotext = infotext

    try:
        trend_range_min = params["period"]
        this_time = time.time()

        # first compute current rate in C/s by computing delta since last check
        rate = get_rate("temp.%s.delta" % unique_name,
                        this_time,
                        temp,
                        allow_negative=True)

        # average trend, initialize with zero (by default), rate_avg is in C/s
        rate_avg = get_average("temp.%s.trend" % unique_name, this_time, rate,
                               trend_range_min)

        # rate_avg is growth in C/s, trend is in C per trend range minutes
        trend = float(rate_avg * trend_range_min * 60.0)
        sign = "+" if trend > 0 else ""
        combiner(
            0, "rate: %s%s/%g min" %
            (sign, render_temp(trend, output_unit, True), trend_range_min))

        if "trend_levels" in params:
            warn_upper_trend, crit_upper_trend = params["trend_levels"]
        else:
            warn_upper_trend = crit_upper_trend = None
        # it may be unclear to the user if he should specify temperature decrease as a negative
        # number or positive. This works either way. Having a positive lower bound makes no
        # sense anyway.
        if "trend_levels_lower" in params:
            warn_lower_trend, crit_lower_trend = [
                abs(x) * -1 for x in params["trend_levels_lower"]
            ]
        else:
            warn_lower_trend = crit_lower_trend = None

        if crit_upper_trend is not None and trend > crit_upper_trend:
            combiner(
                2,
                "rising faster than %s/%g min(!!)" % (render_temp(
                    crit_upper_trend, output_unit, True), trend_range_min),
            )
        elif warn_upper_trend is not None and trend > warn_upper_trend:
            combiner(
                1,
                "rising faster than %s/%g min(!)" % (render_temp(
                    warn_upper_trend, output_unit, True), trend_range_min),
            )
        elif crit_lower_trend is not None and trend < crit_lower_trend:
            combiner(
                2,
                "falling faster than %s/%g min(!!)" % (render_temp(
                    crit_lower_trend, output_unit, True), trend_range_min),
            )
        elif warn_lower_trend is not None and trend < warn_lower_trend:
            combiner(
                1,
                "falling faster than %s/%g min(!)" % (render_temp(
                    warn_lower_trend, output_unit, True), trend_range_min),
            )

        if "trend_timeleft" in params:
            # compute time until temperature limit is reached
            # The start value of minutes_left is negative. The pnp graph and the perfometer
            # will interpret this as infinite -> not growing
            limit = crit if trend > 0 else crit_lower

            if limit:  # crit levels may not be set, especially lower level
                diff_to_limit = limit - temp
                if rate_avg != 0.0:
                    minutes_left = (diff_to_limit /
                                    rate_avg) / 60.0  # fixed: true-division
                else:
                    minutes_left = float("inf")

                def format_minutes(minutes):
                    if minutes > 60:  # hours
                        hours = int(minutes / 60.0)
                        minutes += -int(hours) * 60
                        return "%dh %02dm" % (hours, minutes)
                    return "%d minutes" % minutes

                warn, crit = params["trend_timeleft"]
                if minutes_left <= crit:
                    combiner(
                        2, "%s until temp limit reached(!!)" %
                        format_minutes(minutes_left))
                elif minutes_left <= warn:
                    combiner(
                        1, "%s until temp limit reached(!)" %
                        format_minutes(minutes_left))
    except MKCounterWrapped:
        pass
    return combiner.status, combiner.infotext