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

# info = [
# [['12.109.103.48.50.49.52.49.56.49.54.52.57', '10', 'AP-RTSG01-R29'],
#  ['12.109.103.48.50.49.52.49.56.48.55.57.50', '7',  'AP-D16-Schwille'],
#  ...
# ],
# [['12.109.103.48.50.49.52.49.56.49.54.52.57.1',
#   '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'],
#  ['12.109.103.48.50.49.52.49.56.48.55.57.50.2',
#   '878622', '722521169', '259010759', '80213977575', '53258427', '3911398497', '84355', '78', '160792', '0', '-116'],
#  ...
# ]]

# parsed = {
# 'Y21': {
#   'end_oid': '12.109.103.48.50.49.51.52.51.50.48.55.50',
#   'radios': {
#       '1': {'counters': [1443734995, 1796570108261, 3424375497, 558931548065, 7034540503, 3954342568339, 88605696, 21530, 548422790],
#             'noise_floor': -104,
#             'sessions': 1,
#       },
#       '2': {'counters': [51392622, 58779322688, 1354946125, 359126216495, 453487399, 211359829109, 1937805, 454, 14888291],
#             'noise_floor': -115,
#             'sessions': 0,
#       },
#   },
#   'status': '7',
# },
# ...
# }

def parse_juniper_trpz_aps_sessions(info):
    parsed = {}
    count = 0
    for node in range(len(info)/2):
        # This is needed cause of node_info
        access_points = info[node+count][1:]
        radios        = info[node+count+1][1:]
        count += 1
        for end_oid, status, name in access_points:
            # 10 means that that accesspoint is located on the
            # other cluster part. Use custered_services to see all APs
            if int(status) != 10:
                name = name.replace('AP-','')
                parsed[name] = {
                    'end_oid'    : end_oid,
                    'status'     : int(status),
                    'radios'     : {},
                }

        for data in radios:
            radio_oid, radio_number = data[0].rsplit('.', 1)
            for ap_name, ap_data in parsed.items():
                if radio_oid == parsed[ap_name]['end_oid']:
                    ap_data['radios'][radio_number] = {
                        'counters'    : map(int, data[1:-2]),
                        'sessions'    : int(data[-2]),
                        'noise_floor' : int(data[-1]),
                    }

    return parsed


def inventory_juniper_trpz_aps_sessions(info):
    parsed = parse_juniper_trpz_aps_sessions(info)
    # A failover condition occurs when a primary controller goes down or fails for any reason.
    # Then, a second controller takes over the operation.
    # Failover is also called controller redundancy.
    return [ (key, None) for key in parsed ]


def check_juniper_trpz_aps_sessions(item, _no_params, info):
    parsed = parse_juniper_trpz_aps_sessions(info)
    if item in parsed:
        ap_states = {
            1  : (2, "cleared"),
            2  : (1, "init"),
            3  : (2, "boot started"),
            4  : (2, "image downloaded"),
            5  : (2, "connect failed"),
            6  : (1, "configuring"),
            7  : (0, "operational"),
            10 : (0, "redundant"),
            20 : (2, "conn outage"),
        }
        state, ap_status = ap_states[parsed[item]['status']]

        yield state, "Status: %s" % ap_status

        now = time.time()
        ap_rates    = [0, 0, 0, 0, 0, 0, 0, 0, 0]
        ap_sessions = 0
        noise_floor_radios = []

        for radio_number, radio_data in parsed[item]['radios'].items():
            noise_floor_radios.append( radio_data['noise_floor'] )
            ap_sessions += radio_data['sessions']

            radio_rates = []
            for nr, counter in enumerate(radio_data['counters']):
                radio_rate = get_rate("juniper_trpz_aps_sessions.%s.%s.%d" \
                             % (item, radio_number, nr), now, counter)
                radio_rates.append(radio_rate)
                ap_rates[nr] += radio_rate

            infotext = "Radio %s: input: %s/s, output: %s/s, \
                        %d errors, %d resets, %d retries, %d sessions, noise: %d dBm" % \
                       ( radio_number,
                         get_bytes_human_readable(radio_rates[5]),
                         get_bytes_human_readable(radio_rates[1] + radio_rates[3]),
                         radio_rates[6], radio_rates[7], radio_rates[8],
                         radio_data['sessions'], radio_data['noise_floor'] )

            yield 0, infotext

        perfdata = [
            ("if_out_unicast",            ap_rates[0]),
            ("if_out_unicast_octets",     ap_rates[1]),
            ("if_out_non_unicast",        ap_rates[2]),
            ("if_out_non_unicast_octets", ap_rates[3]),
            ("if_in_pkts",                ap_rates[4]),
            ("if_in_octets",              ap_rates[5]),
            ("wlan_physical_errors",      ap_rates[6]),
            ("wlan_resets",               ap_rates[7]),
            ("wlan_retries",              ap_rates[8]),
            ("total_sessions",            ap_sessions),
            ("noise_floor",               max(noise_floor_radios)),
        ]

        yield 0, "", perfdata


check_info["juniper_trpz_aps_sessions"] = {
    #"parse_function"            : parse_juniper_trpz_aps_sessions, #seams to conflicts with node_info
    "inventory_function"        : inventory_juniper_trpz_aps_sessions,
    "check_function"            : check_juniper_trpz_aps_sessions,
    "service_description"       : "Access Point %s",
    "has_perfdata"              : True,
    "node_info"                 : True,
    "snmp_scan_function"        : lambda oid: oid(".1.3.6.1.2.1.1.2.0").startswith(".1.3.6.1.4.1.14525.3.1"),
    "snmp_info"                 : [
            ( ".1.3.6.1.4.1.14525.4.5.1.1.2.1", [
                OID_END,
                "5",    # trpzApStatApStatusMacApState         -> status of access point
                "8",    # trpzApStatApStatusMacApName          -> name of access point
            ]),
            ( ".1.3.6.1.4.1.14525.4.5.1.1.10.1", [
                OID_END,
                "3",    # trpzApStatRadioOpStatsTxUniPkt       -> unicast packets transmitted
                "4",    # trpzApStatRadioOpStatsTxUniOct       -> octets transmitted in unicast packets
                "5",    # trpzApStatRadioOpStatsTxMultiPkt     -> multicast packets transmitted
                "6",    # trpzApStatRadioOpStatsTxMultiOct     -> octets transmitted in multicast packets
                "7",    # trpzApStatRadioOpStatsRxPkt          -> packets received
                "8",    # trpzApStatRadioOpStatsRxOctet        -> octets received
                "11",   # trpzApStatRadioOpStatsPhyErr         -> nr. physical errors occurred
                "12",   # trpzApStatRadioOpStatsResetCount     -> nr. reset operations
                "14",   # trpzApStatRadioOpStatsRxRetriesCount -> nr. transmission retries
                "15",   # trpzApStatRadioOpStatsUserSessions   -> current client sessions
                "16",   # trpzApStatRadioOpStatsNoiseFloor     -> noise floor (dBm)
            ]),
        ],
}
