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


# snmp_scan_function
# .1.3.6.1.2.1.1.1.0 = "AirLaser IP1000"  < matches airlaser
# .1.3.6.1.4.1.2800.2.1.1.0 3             < Version of management agent ( exists )
# snmp_info
# .1.3.6.1.4.1.2800.2.1.3                 < AirLaser Status


# Migrate to factory settings?
airlaser_default_levels = {
     "opttxTempValue"   : (60, 80),
     "chassisTempValue" : (60, 70),
     "chassisFrontScreenTempValue" : (40, 55),
     "optrxTempValue"   : (50, 60),
     "apmodTempValue"   : (60, 70),  }


def parse_cbl_airlaser(info):

    airlaser_status_names = { 0: 'undefined', 1: 'active', 2: 'standby',
                    3 : 'warning', 4: 'failure', 5: 'not_installed' }


# I have my own little MIB right here, their MIB is
# just a long list, not structured.
    airlaser_sensors = {
       "chassis" : {
      # Name of OID,    Value,    specific OID (not used), Position in SNMP data
          "chassisFrontScreenTempStatus"   : ( None, "2.1.1.0",  0 ),
          "chassisFrontScreenTempValue"    : ( None, "2.1.2.0",  1 ),
          "chassisHeatingStatus"           : ( None, "2.1.7.0",  6 ),
          "chassisTempStatus"              : ( None, "2.1.8.0",  7 ),
          "chassisTempValue"               : ( None, "2.1.9.0",  8 ),
          "chassisFan1Status"              : ( None, "2.1.10.0", 9 ),
          "chassisFan2Status"              : ( None, "2.1.12.0", 11),
             },
       "power"    : {
          "psStatus48V"                    : ( None, "2.2.2.0",  1),
          "psStatus230V"                   : ( None, "2.2.3.0",  2),
          "psStatus5V"                     : ( None, "2.2.4.0",  3),
          "psStatus3V3"                    : ( None, "2.2.8.0",  7),
          "psStatus2V5"                    : ( None, "2.2.12.0", 11),
             },

       "module"   : {
           "apmodTempStatus"               : (None, "2.3.6.0",   5),
           "apmodTempValue"                : (None, "2.3.7.0",   6),
             },

       "opttx"    : {
           "opttxTempValue"                : (None, "2.4.3.0",   2),
           "opttxStatusTemp"               : (None, "2.4.4.0",   3),
             },

       "optrx"    : {
           "optrxStatusTemp"               : (None, "2.5.3.0",   2),
           # this is mislabeled "optrxValueTemp"
           "optrxTempValue"                : (None, "2.5.4.0",   3),
           #"optrxOptValue"
           # .1.3.6.1.4.1.2800.2.2.5.8.0  -10
           #"optrxOptMargin"
           # .1.3.6.1.4.1.2800.2.2.5.9.0  22
             },
    }


    # load the info into a dict separated by the different MIB regions
    # Selfest (info[0] is not handled here.
    data = {
        "chassis" :  info[1],
        "power"   :  info[2],
        "module"  :  info[3],
        "opttx"   :  info[4],
        "optrx"   :  info[5],
    }


    # update values from one dict into the other by picking the "offsetted" values
    # (optimize at will, if we can make it one-dict-for-all then we 100% sanitized their MIB)
    for hwclass in airlaser_sensors.keys():
        for sensor in airlaser_sensors[hwclass].keys():
            # we could remove the offset hack by parsing our OID
            sub_oid   = airlaser_sensors[hwclass][sensor][1]
            offset    = airlaser_sensors[hwclass][sensor][2]


            if "Status" in sensor:
                value = airlaser_status_names[int(data[hwclass][offset][0])]
            else:
                value = saveint(data[hwclass][offset][0])
            airlaser_sensors[hwclass][sensor] = ( value, sub_oid, offset)

    return airlaser_sensors



def check_cbl_airlaser_hw(item, params, info):


    airlaser_info = parse_cbl_airlaser(info)

    state  = 0
    msgtxt = ""
    perfdata = []

    for hwclass in airlaser_info.keys():
        for sensor in airlaser_info[hwclass].keys():
            val = airlaser_info[hwclass][sensor][0]
            if sensor.lower().endswith("value"):
                val = saveint(val)
                if sensor in params.keys():
                    warn, crit = params[sensor]
                    perfdata.append(("%s" % sensor, "%d" % val, warn, crit, 0, 90)),
                    if   val > crit:
                        state = max(state, 2)
                    elif val > warn:
                        state = max(state, 1)
                else:
                    # if this sensor wasn't in the params, then we don't alert on it.
                    perfdata.append(("%s" % sensor, "%d" % val, '', '', 0, 90)),

            # HACK: for the main PSUs the status 3 is not "warning" but
            # not_detected  (3)
            if sensor in [ "psStatus48V", "psStatus230V" ] \
              and val == "warning":
                state = max(state, 0)

            else:
                if val == "failure":
                    state = 2
                elif val == "warning":
                    state = max(state, 1)
                # go here if no explicit error occured,
                # no handling undefined and not_installed
                else:
                    continue
            if state > 0:
                msgtxt = msgtxt + "Sensor %s %s" % (sensor, val) + state * "!" + " "

    if state == 0:
        msgtxt = "All sensors OK"

    return (state, nagios_state_names[state] + " - " + msgtxt, perfdata)


def inventory_cbl_airlaser(info):
    # start passing parameters, but since we might also need some for optics
    # this may change to using factory settings.
    # Or we just hardcode the margins we got from the vendor.
    return [ (None, "airlaser_default_levels") ]


def check_cbl_airlaser_status(item, _no_params, info):
    if len(info) == 0:
        return (3, "UNKNOWN - no information sent by agent")

    selftest, chassis, power, module, optrx, opttx = info
    status = selftest[0][0]

    if status == "1":
        return (0, "OK - Airlaser: normal operation")
    elif status == "2":
        return (1, "WARN - Airlaser: testing mode")
    elif status == "3":
        return (1, "WARN - Airlaser: warning condition")
    elif status == "4":
        return (2, "CRIT - Airlaser: a component has failed self-tests")

    return (3, "UNKNOWN - Unknown data from agent")


check_info["cbl_airlaser.status"]  = {
    "check_function"       : check_cbl_airlaser_status,
    "inventory_function"   : inventory_cbl_airlaser,
    "service_description"  : "CBL Airlaser Status",
    "has_perfdata"         : False,
    "snmp_scan_function"   : lambda oid: "airlaser" in oid(".1.3.6.1.2.1.1.1.0").lower() \
                             and oid(".1.3.6.1.4.1.2800.2.1.1.0"),
     "snmp_info"            : [ (".1.3.6.1.4.1.2800.2", [ "1.3" ]),
                                (".1.3.6.1.4.1.2800.2.2", [ "1" ]),
                                (".1.3.6.1.4.1.2800.2.2", [ "2" ]),
                                (".1.3.6.1.4.1.2800.2.2", [ "3" ]),
                                (".1.3.6.1.4.1.2800.2.2", [ "4" ]),
                                (".1.3.6.1.4.1.2800.2.2", [ "5" ]), ],

}


check_info["cbl_airlaser.hardware"]  = {
    "check_function"       : check_cbl_airlaser_hw,
    "inventory_function"   : inventory_cbl_airlaser,
    "service_description"  : "CBL Airlaser Hardware",
    "has_perfdata"         : True,
}
