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

def parse_f5_bigip_vserver(info):
    def ip_from_string(ip):
        if len(ip) == 4:
            ip = "".join(map(lambda x: chr(ord(x)), ip))
            return socket.inet_ntop(socket.AF_INET, ip)
        elif len(ip) == 16:
            ip = "".join(map(lambda x: chr(ord(x)), ip))
            return socket.inet_ntop(socket.AF_INET6, ip)
        else:
            return "-"

    vservers = {}
    for line in info:
        name = line[0]
        vservers.setdefault(name, {})
        vservers[name].setdefault("status"                  , []).append(int(line[1])),
        vservers[name].setdefault("enabled"                 , []).append(int(line[2])),
        vservers[name].setdefault("detail"                  , []).append(line[3]),
        vservers[name].setdefault("ip"                      , []).append(ip_from_string(line[4])),
        vservers[name].setdefault("connections_duration_min" , []).append(int(line[5])),
        vservers[name].setdefault("connections_duration_max" , []).append(int(line[6])),
        vservers[name].setdefault("connections_duration_mean", []).append(int(line[7])),
        vservers[name].setdefault("if_in_pkts"              , []).append(int(line[8])),
        vservers[name].setdefault("if_out_pkts"             , []).append(int(line[9])),
        vservers[name].setdefault("if_in_octets"            , []).append(int(line[10])),
        vservers[name].setdefault("if_out_octets"           , []).append(int(line[11])),
        vservers[name].setdefault("connections_rate"        , []).append(int(line[12])),
        vservers[name].setdefault("connections"             , []).append(int(line[13])),
        vservers[name].setdefault("packet_velocity_asic"    , []).append(int(line[14]))

    return vservers


def inventory_f5_bigip_vserver(parsed):
    for name, vserver in parsed.items():
        if vserver["status"][0] in [1, 4]: # Green and Blue
            yield name, {}


def check_f5_bigip_vserver(item, params, parsed):
    # Need compatibility to version with _no_params
    if params == None:
        params = {}

    if item in parsed:
        vserver = parsed[item]

        summed_values = {}
        now = time.time()

        # Calculate counters
        for what in [
                        "if_in_pkts",
                        "if_out_pkts",
                        "if_in_octets",
                        "if_out_octets",
                        "connections_rate",
                        "packet_velocity_asic"
                    ]:
            summed_values.setdefault(what, 0)
            for idx, entry in enumerate(vserver[what]):
                rate = get_rate("%s.%s" % (what, idx), now, entry)
                summed_values[what] += rate

        # Calucate min/max/sum/mean values
        for what, function in [ ("connections_duration_min",  min),
                                ("connections_duration_max",  max),
                                ("connections",  sum),
                                ("connections_duration_mean", lambda x: float(sum(x)/len(x))) ]:
            value_list = [x for x in vserver[what] if x != 0]
            if not value_list:
                summed_values[what] = 0
            else:
                summed_values[what] = function(value_list)


        # Current number of connections
        yield 0, "Client connections: %d" % summed_values["connections"], summed_values.items()

        # New connections per time
        yield 0, "Rate: %.2f/sec" % summed_values["connections_rate"]

        # Current server status
        # vserver["status"]
        # 0 - NONE:   disabled
        # 1 - GREEN:  available in some capacity
        # 2 - YELLOW: not currently available
        # 3 - RED:    not available
        # 4 - BLUE:   availability is unknown
        # 5 - GREY:   unlicensed
        map_server_status = {
            0: (1, "is disabled"),
            1: (0, "is up and available"),
            2: (2, "is currently not available"),
            3: (2, "is not available"),
            4: (1, "availability is unknown"),
            5: (3, "is unlicensed")
        }
        state, status = map_server_status.get(vserver["status"][0],\
                                             (3, "Unhandled status (%d)" % vserver["status"][0]))

        # vserver["enabled"]
        # 0 - none
        # 1 - enabled
        # 2 - disabled
        # 3 - disabledbyparent
        enabled = ["NONE", "enabled", "disabled", "disabled by parent"][vserver["enabled"][0]]

        output = "Virtual Server with IP %s is %s, State %s, Detail: %s" % (vserver["ip"][0],\
                 enabled, status, vserver["detail"][0])

        # Special handling
        if vserver["status"][0] == 3: # not available
            # Statement from the network team, it's uncritical when the childrens are down
            if vserver["detail"][0].lower() == "The children pool member(s) are down".lower():
                state = 0

        yield state, output


        # Check configured limits
        map_paramvar_to_text = {
            "if_in_octets":    "Incoming Bytes",
            "if_out_octets":   "Outgoing Bytes",
            "if_total_octets": "Total Bytes",
            "if_in_pkts":      "Incoming Packets",
            "if_out_pkts":     "Outgoing Packets",
            "if_total_pkts":   "Total Packets",
        }
        summed_values["if_total_octets"] = summed_values["if_in_octets"]  + summed_values["if_out_octets"]
        summed_values["if_total_pkts"]   = summed_values["if_in_pkts"]    + summed_values["if_out_pkts"]
        for param_var, levels in params.items():
            if param_var.endswith("_lower") and type(levels) == tuple:
                levels = (None, None) + levels
            value = summed_values[param_var.rstrip("_lower")]
            state, extra_text, extra_perfdata = check_levels(value, param_var, levels)
            if state:
                if "octets" in param_var:
                    value = get_bytes_human_readable(value, base = 1000.0)
                yield state, "%s: %s%s" % (map_paramvar_to_text[param_var.rstrip("_lower")], value, extra_text)


check_info["f5_bigip_vserver"] = {
    "parse_function"          : parse_f5_bigip_vserver,
    "check_function"          : check_f5_bigip_vserver,
    "inventory_function"      : inventory_f5_bigip_vserver,
    "group"                   : "f5_bigip_vserver",
    "service_description"     : "Virtual Server %s",
    "has_perfdata"            : True,
    "snmp_info"               : (".1.3.6.1.4.1.3375.2.2.10", [
                                    "13.2.1.1", # ltmVsStatusName
                                    "13.2.1.2", # ltmVsStatusAvailState
                                    "13.2.1.3", # ltmVsStatusEnabledState
                                    "13.2.1.5", # ltmVsStatusDetailReason
                                    "1.2.1.3",  # IP Address
                                    "2.3.1.2",  # min conn duration
                                    "2.3.1.3",  # max conn duration
                                    "2.3.1.4",  # mean connection duration
                                    "2.3.1.6",  # Client Packets In
                                    "2.3.1.8",  # Client Packets Out
                                    "2.3.1.7",  # Client Bytes In
                                    "2.3.1.9",  # Client Bytes Out
                                    "2.3.1.11", # Client Total Connections
                                    "2.3.1.12", # Client Current Connections
                                    "2.3.1.25", # packet_velocity_asic Total Connections
                               ]),
    "snmp_scan_function"      : lambda oid: ".1.3.6.1.4.1.3375.2" in oid(".1.3.6.1.2.1.1.2.0") \
                                      and "big-ip" in oid(".1.3.6.1.4.1.3375.2.1.4.1.0").lower(),
}
