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

# Frus (Field replaceable units) can be
# - power supply
# - fan tray
# - uplink module
# - transceivers
#
# .1.3.6.1.4.1.2636.3.1.15.1.5.2.1.1.0 Power Supply: Power Supply 0 @ 0/0/* --> JUNIPER-MIB::jnxFruName.2.1.1.0
# .1.3.6.1.4.1.2636.3.1.15.1.5.2.2.1.0 Power Supply: Power Supply 0 @ 1/0/* --> JUNIPER-MIB::jnxFruName.2.2.1.0
# .1.3.6.1.4.1.2636.3.1.15.1.5.4.1.1.1 FAN: Fan 1 @ 0/0/0 --> JUNIPER-MIB::jnxFruName.4.1.1.1
# .1.3.6.1.4.1.2636.3.1.15.1.5.4.1.1.2 FAN: Fan 2 @ 0/0/1 --> JUNIPER-MIB::jnxFruName.4.1.1.2
# .1.3.6.1.4.1.2636.3.1.15.1.5.4.2.1.1 FAN: Fan 1 @ 1/0/0 --> JUNIPER-MIB::jnxFruName.4.2.1.1
# .1.3.6.1.4.1.2636.3.1.15.1.5.4.2.1.2 FAN: Fan 2 @ 1/0/1 --> JUNIPER-MIB::jnxFruName.4.2.1.2
# .1.3.6.1.4.1.2636.3.1.15.1.5.7.1.0.0 FPC: EX3300 48-Port @ 0/*/* --> JUNIPER-MIB::jnxFruName.7.1.0.0
# .1.3.6.1.4.1.2636.3.1.15.1.5.7.2.0.0 FPC: EX3300 48-Port @ 1/*/* --> JUNIPER-MIB::jnxFruName.7.2.0.0
# .1.3.6.1.4.1.2636.3.1.15.1.5.8.1.1.0 PIC: 48x 10/100/1000 Base-T @ 0/0/* --> JUNIPER-MIB::jnxFruName.8.1.1.0
# .1.3.6.1.4.1.2636.3.1.15.1.5.8.1.2.0 PIC: 4x GE/XE SFP+ @ 0/1/* --> JUNIPER-MIB::jnxFruName.8.1.2.0
# .1.3.6.1.4.1.2636.3.1.15.1.5.8.2.1.0 PIC: 48x 10/100/1000 Base-T @ 1/0/* --> JUNIPER-MIB::jnxFruName.8.2.1.0
# .1.3.6.1.4.1.2636.3.1.15.1.5.8.2.2.0 PIC: 4x GE/XE SFP+ @ 1/1/* --> JUNIPER-MIB::jnxFruName.8.2.2.0
# .1.3.6.1.4.1.2636.3.1.15.1.5.9.1.0.0 Routing Engine 0 --> JUNIPER-MIB::jnxFruName.9.1.0.0
# .1.3.6.1.4.1.2636.3.1.15.1.5.9.2.0.0 Routing Engine 1 --> JUNIPER-MIB::jnxFruName.9.2.0.0
# .1.3.6.1.4.1.2636.3.1.15.1.6.2.1.1.0 7 --> JUNIPER-MIB::jnxFruType.2.1.1.0
# .1.3.6.1.4.1.2636.3.1.15.1.6.2.2.1.0 7 --> JUNIPER-MIB::jnxFruType.2.2.1.0
# .1.3.6.1.4.1.2636.3.1.15.1.6.4.1.1.1 13 --> JUNIPER-MIB::jnxFruType.4.1.1.1
# .1.3.6.1.4.1.2636.3.1.15.1.6.4.1.1.2 13 --> JUNIPER-MIB::jnxFruType.4.1.1.2
# .1.3.6.1.4.1.2636.3.1.15.1.6.4.2.1.1 13 --> JUNIPER-MIB::jnxFruType.4.2.1.1
# .1.3.6.1.4.1.2636.3.1.15.1.6.4.2.1.2 13 --> JUNIPER-MIB::jnxFruType.4.2.1.2
# .1.3.6.1.4.1.2636.3.1.15.1.6.7.1.0.0 3 --> JUNIPER-MIB::jnxFruType.7.1.0.0
# .1.3.6.1.4.1.2636.3.1.15.1.6.7.2.0.0 3 --> JUNIPER-MIB::jnxFruType.7.2.0.0
# .1.3.6.1.4.1.2636.3.1.15.1.6.8.1.1.0 11 --> JUNIPER-MIB::jnxFruType.8.1.1.0
# .1.3.6.1.4.1.2636.3.1.15.1.6.8.1.2.0 11 --> JUNIPER-MIB::jnxFruType.8.1.2.0
# .1.3.6.1.4.1.2636.3.1.15.1.6.8.2.1.0 11 --> JUNIPER-MIB::jnxFruType.8.2.1.0
# .1.3.6.1.4.1.2636.3.1.15.1.6.8.2.2.0 11 --> JUNIPER-MIB::jnxFruType.8.2.2.0
# .1.3.6.1.4.1.2636.3.1.15.1.6.9.1.0.0 6 --> JUNIPER-MIB::jnxFruType.9.1.0.0
# .1.3.6.1.4.1.2636.3.1.15.1.6.9.2.0.0 6 --> JUNIPER-MIB::jnxFruType.9.2.0.0
# .1.3.6.1.4.1.2636.3.1.15.1.8.2.1.1.0 6 --> JUNIPER-MIB::jnxFruState.2.1.1.0
# .1.3.6.1.4.1.2636.3.1.15.1.8.2.2.1.0 6 --> JUNIPER-MIB::jnxFruState.2.2.1.0
# .1.3.6.1.4.1.2636.3.1.15.1.8.4.1.1.1 6 --> JUNIPER-MIB::jnxFruState.4.1.1.1
# .1.3.6.1.4.1.2636.3.1.15.1.8.4.1.1.2 6 --> JUNIPER-MIB::jnxFruState.4.1.1.2
# .1.3.6.1.4.1.2636.3.1.15.1.8.4.2.1.1 6 --> JUNIPER-MIB::jnxFruState.4.2.1.1
# .1.3.6.1.4.1.2636.3.1.15.1.8.4.2.1.2 6 --> JUNIPER-MIB::jnxFruState.4.2.1.2
# .1.3.6.1.4.1.2636.3.1.15.1.8.7.1.0.0 6 --> JUNIPER-MIB::jnxFruState.7.1.0.0
# .1.3.6.1.4.1.2636.3.1.15.1.8.7.2.0.0 6 --> JUNIPER-MIB::jnxFruState.7.2.0.0
# .1.3.6.1.4.1.2636.3.1.15.1.8.8.1.1.0 6 --> JUNIPER-MIB::jnxFruState.8.1.1.0
# .1.3.6.1.4.1.2636.3.1.15.1.8.8.1.2.0 6 --> JUNIPER-MIB::jnxFruState.8.1.2.0
# .1.3.6.1.4.1.2636.3.1.15.1.8.8.2.1.0 6 --> JUNIPER-MIB::jnxFruState.8.2.1.0
# .1.3.6.1.4.1.2636.3.1.15.1.8.8.2.2.0 6 --> JUNIPER-MIB::jnxFruState.8.2.2.0
# .1.3.6.1.4.1.2636.3.1.15.1.8.9.1.0.0 6 --> JUNIPER-MIB::jnxFruState.9.1.0.0
# .1.3.6.1.4.1.2636.3.1.15.1.8.9.2.0.0 6 --> JUNIPER-MIB::jnxFruState.9.2.0.0

#   .--psu-----------------------------------------------------------------.
#   |                                                                      |
#   |                           _ __  ___ _   _                            |
#   |                          | '_ \/ __| | | |                           |
#   |                          | |_) \__ \ |_| |                           |
#   |                          | .__/|___/\__,_|                           |
#   |                          |_|                                         |
#   +----------------------------------------------------------------------+
#   |                              main check                              |
#   '----------------------------------------------------------------------'

def parse_juniper_fru(info):
    parsed = {}
    for fru_name, fru_type, fru_state in info:
        # jnxFruName is read-only, thus we can replace here
        # some auto-generated declarations
        name = fru_name.replace("Power Supply: Power Supply ", "") \
                       .replace("FAN: Fan ", "") \
                       .replace("@ ", "") \
                       .replace("/*", "") \
                       .strip()
        parsed[name] = {
            "fru_type"  : fru_type,
            "fru_state" : fru_state,
        }
    return parsed


def inventory_juniper_fru(parsed, fru_type):
    return [ (fru_name, None) for fru_name, fru_data in parsed.items() \
             if fru_data["fru_type"] == fru_type
                and fru_data["fru_state"] != "2" ] # ignore "empty" states


def check_juniper_fru(item, _no_params, parsed):
    map_fru_state = {
        "1"  : (3, "unknown"),
        "2"  : (2, "empty"),
        "3"  : (1, "present"),
        "4"  : (0, "ready"),
        "5"  : (0, "announce online"),
        "6"  : (0, "online"),
        "7"  : (2, "anounce offline"),
        "8"  : (2, "offline"),
        "9"  : (1, "diagnostic"),
        "10" : (1, "standby")
    }
    if item in parsed:
        state, state_readable = map_fru_state[parsed[item]["fru_state"]]
        return state, "Operational status: %s" % state_readable


check_info['juniper_fru'] = {
    'parse_function'            : parse_juniper_fru,
    'inventory_function'        : lambda info: inventory_juniper_fru(info, "7"),
    'check_function'            : check_juniper_fru,
    'service_description'       : 'Power Supply FRU %s',
    'snmp_scan_function'        : lambda oid: oid(".1.3.6.1.2.1.1.2.0").startswith(".1.3.6.1.4.1.2636.1.1.1.2"),
    'snmp_info'                 : (".1.3.6.1.4.1.2636.3.1.15.1", [
                                        "5",    # jnxFruName
                                        "6",    # jnxFruType
                                        "8",    # jnxFruState
                                  ]),
}

#.
#   .--fan-----------------------------------------------------------------.
#   |                            __                                        |
#   |                           / _| __ _ _ __                             |
#   |                          | |_ / _` | '_ \                            |
#   |                          |  _| (_| | | | |                           |
#   |                          |_|  \__,_|_| |_|                           |
#   |                                                                      |
#   '----------------------------------------------------------------------'

check_info['juniper_fru.fan'] = {
    'inventory_function'        : lambda info: inventory_juniper_fru(info, "13"),
    'check_function'            : check_juniper_fru,
    'service_description'       : 'Fan FRU %s',
}

