#!/usr/bin/python
# -*- encoding: utf-8; py-indent-offset: 4 -*-
# +------------------------------------------------------------------+
# |             ____ _               _        __  __ _  __           |
# |            / ___| |__   ___  ___| | __   |  \/  | |/ /           |
# |           | |   | '_ \ / _ \/ __| |/ /   | |\/| | ' /            |
# |           | |___| | | |  __/ (__|   <    | |  | | . \            |
# |            \____|_| |_|\___|\___|_|\_\___|_|  |_|_|\_\           |
# |                                                                  |
# | Copyright Mathias Kettner 2014             mk@mathias-kettner.de |
# +------------------------------------------------------------------+
#
# This file is part of Check_MK.
# The official homepage is at http://mathias-kettner.de/check_mk.
#
# check_mk is free software;  you can redistribute it and/or modify it
# under the  terms of the  GNU General Public License  as published by
# the Free Software Foundation in version 2.  check_mk is  distributed
# in the hope that it will be useful, but WITHOUT ANY WARRANTY;  with-
# out even the implied warranty of  MERCHANTABILITY  or  FITNESS FOR A
# PARTICULAR PURPOSE. See the  GNU General Public License for more de-
# tails. You should have  received  a copy of the  GNU  General Public
# License along with GNU Make; see the file  COPYING.  If  not,  write
# to the Free Software Foundation, Inc., 51 Franklin St,  Fifth Floor,
# Boston, MA 02110-1301 USA.


# OIDs for name and type of the sensors (type 8 = temperature sensor)
# SNMPv2-SMI::mib-2.47.1.1.1.1.2.21594 = STRING: "module-1 Crossbar(s5)"
# SNMPv2-SMI::mib-2.47.1.1.1.1.2.21601 = STRING: "module-1 QEng1Sn1(s12)"
# SNMPv2-SMI::mib-2.47.1.1.1.1.2.21602 = STRING: "module-1 QEng1Sn2(s13)"
# SNMPv2-SMI::mib-2.47.1.1.1.1.2.21603 = STRING: "module-1 QEng1Sn3(s14)"
# SNMPv2-SMI::mib-2.47.1.1.1.1.2.21604 = STRING: "module-1 QEng1Sn4(s15)"
# SNMPv2-SMI::mib-2.47.1.1.1.1.2.21605 = STRING: "module-1 QEng2Sn1(s16)"
# SNMPv2-SMI::mib-2.47.1.1.1.1.2.21606 = STRING: "module-1 QEng2Sn2(s17)"
# [...]
# Types of sensors:
#        other(1):        a measure other than those listed below
#        unknown(2):      unknown measurement, or arbitrary, relative numbers
#        voltsAC(3):      electric potential
#        voltsDC(4):      electric potential
#        amperes(5):      electric current
#        watts(6):        power
#        hertz(7):        frequency
#        celsius(8):      temperature
#        percentRH(9):    percent relative humidity
#        rpm(10):         shaft revolutions per minute
#        cmm(11),:        cubic meters per minute (airflow)
#        truthvalue(12):  value takes { true(1), false(2) }
#        specialEnum(13): value takes user defined enumerated values
#        dBm(14):         dB relative to 1mW of power
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.1.21594 = INTEGER: 8
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.1.21601 = INTEGER: 8
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.1.21602 = INTEGER: 8
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.1.21603 = INTEGER: 8
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.1.21604 = INTEGER: 8
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.1.21605 = INTEGER: 8
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.1.21606 = INTEGER: 8
# [...]

# Current value of the sensor
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.4.21594 = INTEGER: 62
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.4.21601 = INTEGER: 102
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.4.21602 = INTEGER: 99
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.4.21603 = INTEGER: 98
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.4.21604 = INTEGER: 99
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.4.21605 = INTEGER: 101
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.4.21606 = INTEGER: 99
# [...]

# State of the sensor itself
#        ok(1) means the agent can read the sensor
#        value.
#
#        unavailable(2) means that the agent presently
#        can not report the sensor value.
#
#        nonoperational(3) means that the agent believes
#        the sensor is broken.  The sensor could have a
#        hard failure (disconnected wire), or a soft failure
#        such as out-of-range, jittery, or wildly fluctuating
#        readings.
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.5.21594 = INTEGER: 1
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.5.21601 = INTEGER: 1
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.5.21602 = INTEGER: 1
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.5.21603 = INTEGER: 1
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.5.21604 = INTEGER: 1
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.5.21605 = INTEGER: 1
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.5.21606 = INTEGER: 1

# Thresholds
# SNMPv2-SMI::enterprises.9.9.91.1.2.1.1.4.21594.9 = INTEGER: 95
# SNMPv2-SMI::enterprises.9.9.91.1.2.1.1.4.21594.10 = INTEGER: 105
# SNMPv2-SMI::enterprises.9.9.91.1.2.1.1.4.21601.23 = INTEGER: 110
# SNMPv2-SMI::enterprises.9.9.91.1.2.1.1.4.21601.24 = INTEGER: 115
# SNMPv2-SMI::enterprises.9.9.91.1.2.1.1.4.21602.25 = INTEGER: 110
# SNMPv2-SMI::enterprises.9.9.91.1.2.1.1.4.21602.26 = INTEGER: 115
# SNMPv2-SMI::enterprises.9.9.91.1.2.1.1.4.21603.27 = INTEGER: 110
# SNMPv2-SMI::enterprises.9.9.91.1.2.1.1.4.21603.28 = INTEGER: 115
# SNMPv2-SMI::enterprises.9.9.91.1.2.1.1.4.21604.29 = INTEGER: 110
# SNMPv2-SMI::enterprises.9.9.91.1.2.1.1.4.21604.30 = INTEGER: 115
# SNMPv2-SMI::enterprises.9.9.91.1.2.1.1.4.21605.31 = INTEGER: 110
# SNMPv2-SMI::enterprises.9.9.91.1.2.1.1.4.21605.32 = INTEGER: 115
# SNMPv2-SMI::enterprises.9.9.91.1.2.1.1.4.21606.33 = INTEGER: 110
# SNMPv2-SMI::enterprises.9.9.91.1.2.1.1.4.21606.34 = INTEGER: 115


# Create a dictionary with the information about each
# sensor. The key into the dict is the end OID of the
# sensor.
def parse_cisco_temp_sensor(info):
    description_info, state_info, levels_info = info

    # Create dict of sensor descriptions
    descriptions = dict(description_info)

    # Create dict with thresholds
    thresholds = {}
    for id, sensortype, scale, precision, value, sensorstate in state_info:
        thresholds.setdefault(id, [])

    for endoid, level in levels_info:
        level = float(level)/(10**int(precision))
        # endoid is e.g. 21549.9 or 21459.10
        id, subid = endoid.split('.')
        thresholds.setdefault(id, []).append(level)

    # Create main dictionary (only of temperature sensors)
    sensors = []
    for id, sensortype, scale, precision, value, sensorstate in state_info:
        value = float(value)/(10**int(precision))
        sensors.append( ( id, descriptions.get(id), sensortype, scale,
                        value, sensorstate, thresholds[id] ) )
    return sensors

def inventory_cisco_temp_sensor(info):
#    sensors = parse_cisco_temp_sensor(info)
    inventory = []
#    for id, descr, sensortype, scale, value, sensorstate, levels in sensors:
#        # Use all temperature sensors with a non-empty description and valid threshold
#        if descr != None and sensortype == '8' and len(levels) in [ 2, 4 ]:
#            warn, crit = saveint(levels[0]), saveint(levels[1])
#            inventory.append(( descr, (warn, crit) ))
    return inventory

def check_cisco_temp_sensor(item, params, info):
    sensors = parse_cisco_temp_sensor(info)
    for id, descr, sensortype, scale, temp, sensorstate, levels in sensors:
        if item == descr:
#            # Use built in levels if no levels are configured
#            if params:
#                warn, crit = params
#            else:
#                warn, crit = levels[0:2]
#                # convert threshold milli values to native unit
#                if scale == "8":
#                    temp = temp/1000
#                    warn = warn/1000
#
#            # convert milli temperature to native unit
#            if scale == "8":
#                crit = crit/1000
#
#            if sensorstate == "2":
#                return (3, "Data from sensor currently not available")
#            elif sensorstate == "3":
#                return (3, "Sensor is broken")
#
#            return check_temperature(temp, (warn, crit))
            return 3, "This check is obsolete, please re-inventorize this host"


check_info['cisco_temp_sensor'] = {
    "check_function"     : check_cisco_temp_sensor,
    "inventory_function" : inventory_cisco_temp_sensor,
    "service_description": "Temperature %s",
    "has_perfdata"       : True,
    "snmp_scan_function" : lambda oid: "cisco" in oid(".1.3.6.1.2.1.1.1.0").lower() and \
                                    oid(".1.3.6.1.4.1.9.9.91.1.1.1.1.*") != None,
    "snmp_info"          : [
                               ( ".1.3.6.1.2.1.47.1.1.1.1", [
                                 OID_END,
                                 2, # Description of the sensor
                               ]),

                               # Type and current state
                               ( ".1.3.6.1.4.1.9.9.91.1.1.1.1", [
                                 OID_END,
                                 1, # Type (see above), 8 = Celsius, 12 = truth value
                                 2, # Scale, 8 == milli
                                 3, # Precision
                                 4, # Most recent measurement
                                 5, # Status of the sensor 1 == ok, 2 == cannot report, 3 == broken
                               ]),

                               # Threshold
                               ( ".1.3.6.1.4.1.9.9.91.1.2.1.1", [
                                 OID_END,
                                 4, # Thresholds
                               ]),
                            ],
    "includes"          : [ "temperature.include" ]
}

