#!/usr/bin/python
# -*- encoding: utf-8; py-indent-offset: 4 -*-
# +------------------------------------------------------------------+
# |             ____ _               _        __  __ _  __           |
# |            / ___| |__   ___  ___| | __   |  \/  | |/ /           |
# |           | |   | '_ \ / _ \/ __| |/ /   | |\/| | ' /            |
# |           | |___| | | |  __/ (__|   <    | |  | | . \            |
# |            \____|_| |_|\___|\___|_|\_\___|_|  |_|_|\_\           |
# |                                                                  |
# | Copyright Mathias Kettner 2015             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-
# ails.  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.

def parse_cisco_temperature(info):
    description_info, state_info, levels_info, perfstuff = info

    # Parse OIDs described by CISCO-ENTITY-SENSOR-MIB
    entity_parsed = {}

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

    # Create dict with thresholds
    thresholds = {}
    for sensor_id, sensortype, scalecode, magnitude, value, sensorstate in state_info:
        thresholds.setdefault(sensor_id, [])

    for endoid, level in levels_info:
        # endoid is e.g. 21549.9 or 21459.10
        sensor_id, subid = endoid.split('.')
        thresholds.setdefault(sensor_id, []).append(level)

    for sensor_id, sensortype, scalecode, magnitude, value, sensorstate in state_info:
        if sensor_id in descriptions:
            descr = descriptions[sensor_id]
        else:
            descr = sensor_id

        if descr and sensortype == '8':

            if sensorstate == '2':
                entity_parsed[descr] = (3, "Data from sensor currently not available")
            elif sensorstate == '3':
                entity_parsed[descr] = (3, "Sensor is broken")
            else:
                entity_parsed[descr] = {}
                scale = 10**int(magnitude)
                if scalecode == '8':
                    scale *= 1000
                entity_parsed[descr]['temp'] = float(value) / scale

                if len(thresholds[sensor_id]) in [ 2, 4 ]:
                    warnraw, critraw = thresholds[sensor_id][0:2]
                    dev_levels = (float(warnraw)/scale, float(critraw)/scale)
                else:
                    dev_levels = None
                entity_parsed[descr]['dev_levels'] = dev_levels

                entity_parsed[descr]['dev_status'] = None

    # Now parse OIDs described by CISCO-ENVMON-MIB
    envmon_states = {
     '1': "normal",
     '2': "warning",
     '3': "critical",
     '4': "shutdown",
     '5': "not present",
     '6': "not functioning"
    }

    parsed = {}
    for statustext, temp, max_temp, state, oid_end in perfstuff:
        item = cisco_sensor_item(statustext, oid_end)
        if state in ['5', '6']:
            parsed[item] = (3, "Sensor %s" % envmon_states[state])
        elif int(temp) == 0:
            if state in ('123'):
                parsed[item] = ( int(state) - 1, "Sensor reports %s state" % envmon_states[state] )
            else:
                parsed[item] = (3, "Sensor defect")
        else:
            parsed[item] = {}
            parsed[item]['temp'] = int(temp)
            if max_temp and int(max_temp):
                parsed[item]['dev_status'] = None
                parsed[item]['dev_levels'] = (int(max_temp), int(max_temp))
            else:
                parsed[item]['dev_levels'] = None
                if state == '1':
                    parsed[item]['dev_status'] = 0
                elif state == '2':
                    parsed[item]['dev_status'] = 1
                elif state in '34':
                    parsed[item]['dev_status'] = 2
                else:
                    parsed[item] = (3, "Sensor reports unknown status code")

    # Merge the two dicts, preferring keys generated from ENTITY data
    parsed.update(entity_parsed)

    return parsed


def inventory_cisco_temperature(parsed):
    for item in parsed.keys():
        yield item, None


def check_cisco_temperature(item, params, parsed):
    if item in parsed:
        if type(parsed[item]) == tuple:
            return parsed[item]
        else:
            return check_temperature(parsed[item]['temp'], params,
                        dev_levels = parsed[item]['dev_levels'],
                        dev_status = parsed[item]['dev_status'])


check_info['cisco_temperature'] = {
    "parse_function"     : parse_cisco_temperature,
    "inventory_function" : inventory_cisco_temperature,
    "check_function"     : check_cisco_temperature,
    "service_description": "Temperature %s",
    "group"              : "temperature",
    "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 or
                                      oid(".1.3.6.1.4.1.9.9.13.1.3.1.3.*") != None ),
    "snmp_info"          : [
                               # cisco_temp_sensor data
                               ( ".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, # scalecode, 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
                               ]),

                               # cisco_temp_perf data
                               ( ".1.3.6.1.4.1.9.9.13.1.3.1", [ # CISCO-SMI
                                                               2, # ciscoEnvMonTemperatureStatusDescr
                                                               3, # ciscoEnvMonTemperatureStatusValue
                                                               4, # ciscoEnvMonTemperatureThreshold
                                                               6, # ciscoEnvMonTemperatureState
                                                               OID_END
                               ]),
                            ],
    "includes"          : [ "temperature.include", 'cisco_sensor_item.include' ],
}
