#!/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.

# Check has been developed using a Emerson Network Power Rack PDU Card
# Agent App Firmware Version  4.840.0
# Agent Boot Firmware Version 4.540.3
# FDM Version 1209
# GDD Version 45585

# Example info:
# [['10.1.1.1', '2'], ['10.1.2.1', '1'], ['10.1.3.1', '3'], ['10.1.3.2', '3'], ['15.1.1.1', 'SNSR: 1-1'], ['15.1.2.1', 'SNSR: 1-2'], ['15.1.3.1', 'SNSR: 1-3'], ['15.1.3.2', 'SNSR: 1-3'], ['20.1.1.1', 'RAD-LUNEPL-SEN7(80000000B080CF26)'], ['20.1.2.1', 'RAD-LUNEPL-SEN5(Rueckseite-oben)'], ['20.1.3.1', 'RAD-LUNEPL-SEN3(TuerRueckseite)'], ['20.1.3.2', 'RAD-LUNEPL-SEN1(TuerFront)'], ['25.1.1.1', ''], ['25.1.2.1', ''], ['25.1.3.1', ''], ['25.1.3.2', ''], ['30.1.1.1', ''], ['30.1.2.1', ''], ['30.1.3.1', ''], ['30.1.3.2', ''], ['35.1.1.1', '80000000B080CF26'], ['35.1.2.1', 'DD0000000DFAEA42'], ['35.1.3.1', 'EC00000013FBD820'], ['35.1.3.2', 'EC00000013FBD820'], ['40.1.2.1', '873'], ['50.1.2.1', '500'], ['55.1.2.1', '878'], ['60.1.2.1', '590'], ['65.1.2.1', '806'], ['70.1.2.1', '307'], ['75.1.2.1', '100'], ['80.1.2.1', '310'], ['85.1.2.1', '150'], ['90.1.2.1', '270'], ['95.1.1.1', '156'], ['100.1.1.1', '150'], ['105.1.1.1', '600'], ['110.1.1.1', '200'], ['115.1.1.1', '560'], ['120.1.3.1', '2'], ['120.1.3.2', '2'], ['125.1.3.1', '1'], ['125.1.3.2', '1']]

# Indexes in lgpPduAuxMeasTable are:
# 1. lgpPduEntryIndex
# 2. lgpPduAuxMeasSensorIndex
# 3. lgpPduAuxMeasSensorMeasurementIndex

#     10, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasType
#     15, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasSensorSysAssignLabel
#     20, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasUsrLabel
#     35, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasSensorSerialNum
#     70, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasTempDeg
#     75, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasTempThrshldUndrAlmDegC
#     80, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasTempThrshldOvrAlmDegC
#     85, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasTempThrshldUndrWarnDegC
#     90, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasTempThrshldOvrWarnDegC
#     95, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasHum
#    100, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasHumThrshldUndrAlm
#    105, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasHumThrshldOvrAlm
#    110, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasHumThrshldUndrWarn
#    115, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasHumThrshldOvrWarn
#    120, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasDrClosureState
#    125, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasDrClosureConfig

lgp_pdu_aux_types = {
    '0': 'UNSPEC',
    '1': 'TEMP',
    '2': 'HUM',
    '3': 'DOOR',
    '4': 'CONTACT',
}

lgp_pdu_aux_states = [
  'not-specified',
  'open',
  'closed',
]

_lgp_pdu_aux_fields = {
    # Index, Type, Factor, ID
    '10': (str,       None, 'Type'),
    '15': (str,       None, 'SystemLabel'),
    '20': (str,       None, 'UserLabel'),
    '35': (str,       None, 'SerialNumber'),
    '70': (savefloat, 0.1,  'Temp'),
    '75': (savefloat, 0.1,  'TempLowCrit'),
    '80': (savefloat, 0.1,  'TempHighCrit'),
    '85': (savefloat, 0.1,  'TempLowWarn'),
    '90': (savefloat, 0.1,  'TempHighWarn'),
    '95': (savefloat, 0.1,  'Hum'),
   '100': (savefloat, 0.1,  'HumLowCrit'),
   '105': (savefloat, 0.1,  'HumHighCrit'),
   '110': (savefloat, 0.1,  'HumLowWarn'),
   '115': (savefloat, 0.1,  'HumHighWarn'),
   '120': (saveint,   None, 'DoorState'),
   '125': (saveint,   None, 'DoorConfig'),
}

def lgp_pdu_aux_fmt(info):
    new_info = {}
    for oid, value in info:
        type, id = oid.split('.', 1)
        if not id in new_info:
            new_info[id] = {'TypeIndex': id.split('.')[-1]}
        # Skip not handled rows
        if type in _lgp_pdu_aux_fields:
            ty, factor, key = _lgp_pdu_aux_fields[type]

            if key == 'Type':
                value = lgp_pdu_aux_types.get(value, 'UNHANDLED')
            else:
                if factor:
                    value = ty(value) * factor
                else:
                    value = ty(value)

            new_info[id][key] = value
    return new_info

def inventory_lgp_pdu_aux(info):
    info = lgp_pdu_aux_fmt(info)
    inv = []
    for id, pdu in info.iteritems():
        # Using SystemLabel as index. But it is not uniq in all cases.
        # Adding the Type-Index to prevent problems
        inv.append((pdu['Type'] + '-' + pdu['SystemLabel'] + '-' + pdu['TypeIndex'], None))
    return inv

def check_lgp_pdu_aux(item, params, info):
    info = lgp_pdu_aux_fmt(info)
    for id, pdu in info.iteritems():
        if item == pdu['Type'] + '-' + pdu['SystemLabel'] + '-' + pdu['TypeIndex']:
            state    = 0
            output   = []
            perfdata = []

            if pdu['UserLabel'] != '':
                output.append('Label: %s (%s)' % (pdu['UserLabel'], pdu['SystemLabel']))
            else:
                output.append('Label: ' + pdu['SystemLabel'])

            def handle_type(ty, label, uom):
                state = 0
                perfdata = (ty.lower(), pdu[ty],
                            '%0.2f:%0.2f' % (pdu[ty+'LowWarn'], pdu[ty+'HighWarn']),
                            '%0.2f:%0.2f' % (pdu[ty+'LowCrit'], pdu[ty+'HighCrit']))
                s_out = ''
                if pdu[ty] >= pdu[ty+'HighCrit']:
                    state = 2
                    s_out = ' >= %0.2f (!!)' % pdu[ty+'HighCrit']
                elif pdu[ty] <= pdu[ty+'LowCrit']:
                    state = 2
                    s_out = ' <= %0.2f (!!)' % pdu[ty+'LowCrit']
                elif pdu[ty] >= pdu[ty+'HighWarn']:
                    state = 1
                    s_out = ' >= %0.2f (!)' % pdu[ty+'HighWarn']
                elif pdu[ty] <= pdu[ty+'LowWarn']:
                    state = 1
                    s_out = ' <= %0.2f (!)' % pdu[ty+'LowWarn']

                return state, '%s: %0.2f%s%s' % (label, pdu[ty], uom, s_out), perfdata

            if pdu['Type'] == 'TEMP':
                state, out, perf = handle_type('Temp', 'Temperature', 'C')
                output.append(out)
                perfdata.append(perf)

            elif pdu['Type'] == 'HUM':
                state, out, perf = handle_type('Hum', 'Humidity', '%')
                output.append(out)
                perfdata.append(perf)

            elif pdu['Type'] == 'DOOR':
                # DoorConfig: 1 -> open, 0 -> disabled
                if pdu['DoorConfig'] == 1 and lgp_pdu_aux_states[pdu['DoorState']] == 'open':
                    state = 2
                    output.append('Door is %s (!!)' % lgp_pdu_aux_states[pdu['DoorState']])
                else:
                    output.append('Door is %s' % lgp_pdu_aux_states[pdu['DoorState']])

            return (state, ', '.join(output), perfdata)

    return (3, 'Could not find given PDU.')

check_info['lgp_pdu_aux'] = (check_lgp_pdu_aux, 'Liebert PDU AUX %s', 1, inventory_lgp_pdu_aux)

snmp_info['lgp_pdu_aux'] = ('.1.3.6.1.4.1.476.1.42.3.8.60.15', [
    OID_END, '1', # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasTable
])

snmp_scan_functions['lgp_pdu_aux'] = lambda oid: oid('.1.3.6.1.2.1.1.2.0') == \
                                                         '.1.3.6.1.4.1.476.1.42'

#check_info["lgp_pdu_aux"] = {
#    "check_function"        : check_lgp_pdu_aux,
#    "inventory_function"    : inventory_lgp_pdu_aux,
#    "service_description"   : "Liebert PDU AUX %s",
#    "has_perfdata"          : True,
#    "snmp_scan_function"    : lambda oid: oid(".1.3.6.1.2.1.1.2.0") == \
#                                          ".1.3.6.1.4.1.476.1.42"
#}
