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


# settings for inventory: which ports should be inventorized
qlogic_fcport_inventory_opstates  = [ "1", "3" ]
qlogic_fcport_inventory_admstates = [ "1", "3" ]

# this function is needed to have the same port IDs in Check_MK
# as within the Management interface of the device
def qlogic_fcport_generate_port_id(port_id):
    major, minor = port_id.split(".", 1)
    minor = int(minor) - 1
    port_id = "%s.%s" % (major, minor)
    return port_id

def inventory_qlogic_fcport(info):
    inventory = []

    for port_id, oper_mode, admin_status, oper_status, link_failures, \
        sync_losses, prim_seq_proto_errors, invalid_tx_words, invalid_crcs, \
        address_id_errors, link_reset_ins, link_reset_outs, ols_ins, \
        ols_outs, c2_in_frames, c2_out_frames, c2_in_octets, c2_out_octets, \
        c2_discards, c2_fbsy_frames, c2_frjt_frames, c3_in_frames, \
        c3_out_frames, c3_in_octets, c3_out_octets, c3_discards in info:

        if admin_status in qlogic_fcport_inventory_admstates and \
           oper_status in qlogic_fcport_inventory_opstates:
               inventory.append( (qlogic_fcport_generate_port_id(port_id), None) )

    return inventory


def check_qlogic_fcport(item, params, info):
    for port_id, oper_mode, admin_status, oper_status, link_failures, \
        sync_losses, prim_seq_proto_errors, invalid_tx_words, invalid_crcs, \
        address_id_errors, link_reset_ins, link_reset_outs, ols_ins, \
        ols_outs, c2_in_frames, c2_out_frames, c2_in_octets, c2_out_octets, \
        c2_discards, c2_fbsy_frames, c2_frjt_frames, c3_in_frames, \
        c3_out_frames, c3_in_octets, c3_out_octets, c3_discards in info:

        port_id = qlogic_fcport_generate_port_id(port_id)
        if port_id == item:
            status = 0
            perfdata = []
            message = "Port %s" % port_id

            # fcFxPortPhysAdminStatus
            if admin_status == "1":
                message  += " AdminStatus: online"
                status = 0
            elif admin_status == "2":
                message += "AdminStatus: offline (!!)"
                status = 2
            elif admin_status == "3":
                message += "AdminStatus: testing (!)"
                status = 1
            else:
                message += "unknown AdminStatus %s (!)" % admin_status
                status = 1

            # fcFxPortPhysOperStatus
            if oper_status == "1":
                message += ", OperStatus: online"
                status = max(status, 0)
            elif oper_status == "2":
                message += ", OperStatus: offline (!!)"
                status = max(status, 2)
            elif oper_status == "3":
                message += ", OperStatus: testing (!)"
                status = max(status, 1)
            elif oper_status == "4":
                message += ", OperStatus: linkFailure (!!)"
                status = max(status, 2)
            else:
                message += ", unknown OperStatus %s (!)" % oper_status
                status = max(status, 1)

            # fcFxPortOperMode (for display only)
            if oper_mode == "2":
                message += ", OperMode: fPort"
            elif oper_mode == "3":
                message += ", OperMode: flPort"

            # Counters
            this_time = time.time()

            # Bytes/sec in and out
            in_octets  = int(c2_in_octets)  + int(c3_in_octets)
            out_octets = int(c2_out_octets) + int(c3_out_octets)

            in_octet_rate  = get_rate("qlogic_fcport.in_octets.%s"  % port_id, this_time, in_octets)
            out_octet_rate = get_rate("qlogic_fcport.out_octets.%s" % port_id, this_time, out_octets)

            message += ", In: %s/s"  % get_bytes_human_readable(in_octet_rate)
            message += ", Out: %s/s" % get_bytes_human_readable(out_octet_rate)

            perfdata.append(("in",  in_octet_rate))
            perfdata.append(("out", out_octet_rate))

            # Frames in and out
            in_frames  = int(c2_in_frames)  + int(c3_in_frames)
            out_frames = int(c2_out_frames) + int(c3_out_frames)

            in_frame_rate  = get_rate("qlogic_fcport.in_frames.%s"  % port_id, this_time, in_frames)
            out_frame_rate = get_rate("qlogic_fcport.out_frames.%s" % port_id, this_time, out_frames)

            message += ", in frames: %s/s"  % in_frame_rate
            message += ", out frames: %s/s" % out_frame_rate

            perfdata.append(("rxframes", in_frame_rate))
            perfdata.append(("txframes", out_frame_rate))

            # error rates
            discards = int(c2_discards) + int(c3_discards)
            error_sum = 0
            for descr, counter, value in [
                ("Link Failures",         "link_failures",         link_failures),
                ("Sync Losses",           "sync_losses",           sync_losses),
                ("PrimitSeqErrors",       "prim_seq_proto_errors", prim_seq_proto_errors),
                ("Invalid TX Words",      "invalid_tx_words",      invalid_tx_words),
                ("Invalid CRCs",          "invalid_crcs",          invalid_crcs),
                ("Address ID Errors",     "address_id_errors",     address_id_errors),
                ("Link Resets In",        "link_reset_ins",        link_reset_ins),
                ("Link Resets Out",       "link_reset_outs",       link_reset_outs),
                ("Offline Sequences In",  "ols_ins",               ols_ins),
                ("Offline Sequences Out", "ols_outs",              ols_outs),
                ("Discards",              "discards",              discards),
                ("F_BSY frames",          "c2_fbsy_frames",        c2_fbsy_frames),
                ("F_RJT frames",          "c2_frjt_frames",        c2_frjt_frames),
            ]:
                value = int(value)
                per_sec = get_rate("qlogic_fcport.%s.%s" % (counter, port_id), this_time, value)
                perfdata.append((counter, per_sec))
                error_sum += per_sec

                if per_sec > 0:
                    message += ", %s: %s/s" % (descr, per_sec)
            if error_sum == 0:
                message += ", no protocol errors"

            return status, message, perfdata

    return 3, "Port %s not found" % item


check_info["qlogic_fcport"] = {
    'check_function':          check_qlogic_fcport,
    'inventory_function':      inventory_qlogic_fcport,
    'service_description':     'FC Port %s',
    'has_perfdata':            True,
    'snmp_info':               ( ".1.3.6.1.2.1.75.1",[
                                      OID_END,    # Index of the Port
                                      "2.1.1.3",  # fcFxPortOperMode
                                      "2.2.1.1",  # fcFxPortPhysAdminStatus
                                      "2.2.1.2",  # fcFxPortPhysOperStatus
                                      "3.1.1.1",  # fcFxPortLinkFailures
                                      "3.1.1.2",  # fcFxPortSyncLosses
                                      "3.1.1.4",  # fcFxPortPrimSeqProtoErrors
                                      "3.1.1.5",  # fcFxPortInvalidTxWords
                                      "3.1.1.6",  # fcFxPortInvalidCrcs
                                      "3.1.1.8",  # fcFxPortAddressIdErrors
                                      "3.1.1.9",  # fcFxPortLinkResetIns
                                      "3.1.1.10", # fcFxPortLinkResetOuts
                                      "3.1.1.11", # fcFxPortOlsIns
                                      "3.1.1.12", # fcFxPortOlsOuts
                                      "4.2.1.1",  # fcFxPortC2InFrames
                                      "4.2.1.2",  # fcFxPortC2OutFrames
                                      "4.2.1.3",  # fcFxPortC2InOctets
                                      "4.2.1.4",  # fcFxPortC2OutOctets
                                      "4.2.1.5",  # fcFxPortC2Discards
                                      "4.2.1.6",  # fcFxPortC2FbsyFrames
                                      "4.2.1.7",  # fcFxPortC2FrjtFrames
                                      "4.3.1.1",  # fcFxPortC3InFrames
                                      "4.3.1.2",  # fcFxPortC3OutFrames
                                      "4.3.1.3",  # fcFxPortC3InOctets
                                      "4.3.1.4",  # fcFxPortC3OutOctets
                                      "4.3.1.5",  # fcFxPortC3Discards
                               ]),
    'snmp_scan_function'    : lambda oid: oid(".1.3.6.1.2.1.1.2.0").startswith(".1.3.6.1.4.1.3873.1.14"),
    'group':                   'qlogic_fcport',
    'default_levels_variable': 'qlogic_fcport_default_levels',
}
