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

#<<<netapp_api_if:sep(9)>>>
# interface clu1-01_clus1 use-failover-group unused       address 222.254.110.11  dns-domain-name none    is-auto-revert true     lif-uuid 3d682f64-4bd1-11e5-a02c-0050569628b6   vserver Cluster role cluster    netmask-length 24       data-protocols.data-protocol none       operational-status up   netmask 255.255.255.0   failover-policy local_only      home-node clu1-01       address-family ipv4     current-port e0a        current-node clu1-01    routing-group-name c222.254.110.0/24    listen-for-dns-query false      administrative-status up        failover-group Cluster  home-port e0a   is-home true    send_data 4265424  send_errors 0   recv_errors 0   instance_name clu1-01_clus1     recv_data 5988948
# interface clu1-01_clus2 use-failover-group unused       address 222.254.110.12  dns-domain-name none    is-auto-revert true     lif-uuid 3d6817c9-4bd1-11e5-a02c-0050569628b6   vserver Cluster role cluster    netmask-length 24       data-protocols.data-protocol none       operational-status up   netmask 255.255.255.0   failover-policy local_only      home-node clu1-01       address-family ipv4     current-port e0b        current-node clu1-01    routing-group-name c222.254.110.0/24    listen-for-dns-query false      administrative-status up        failover-group Cluster  home-port e0b   is-home true    send_data 4389886  send_errors 0   recv_errors 0   instance_name clu1-01_clus2     recv_data 6113182


def netapp_convert_to_if64(info):
    interfaces = netapp_api_parse_lines(info)

    # Calculate speed, state and create mac-address list
    if_mac_list = {} # Dictionary with lists of common mac addresses
    vif_list    = [] # List of virtual interfaces
    for name, values in interfaces.items():
        # Reported by 7Mode
        mediatype = values.get("mediatype")
        if mediatype:
            tokens = mediatype.split("-")
            # Possible values according to 7-Mode docu: 100tx | 100tx-fd | 1000fx | 10g-sr
            if "1000" in mediatype:
                speed = 1000000000
            elif "100" in mediatype:
                speed = 100000000
            elif "10g" in mediatype:
                speed = 10000000000
            elif "10" in mediatype:
                speed = 10000000
            else:
                speed = 0
            values["speed"] = speed

            values["state"] = tokens[-1].lower() == "up" and "1" or "2"
        elif values.get("port-role") != "storage-acp":
            # If an interface has no media type and is not a storage-acp it is considered as virtual interface
            vif_list.append(name)

        # Reported by Clustermode
        for status_key in [ "link-status", "operational-status" ]:
            if status_key in values:
                if values[status_key] == "up":
                    values["state"] = "1"
                else:
                    values["state"] = "2"
                break

        # Reported by Clustermode
        if "operational-speed" in values:
            values["speed"] = int(values["operational-speed"]) * 1000 * 1000

        if "mac-address" in values:
            if_mac_list.setdefault(values["mac-address"], [])
            if_mac_list[values["mac-address"]].append(name)


    nics       = []
    extra_info = {}
    for idx, entry in enumerate(sorted(interfaces)):
        nic_name, values = entry, interfaces[entry]

        speed = values.get("speed", 0)
        state = values.get("state", "2")

        # Try to determine the speed and state for virtual interfaces
        # We know all physical interfaces for this virtual device and use the highest available
        # speed as the virtual speed. Note: Depending on the configuration this behaviour might
        # differ, e.g. the speed of all interfaces might get accumulated..
        # Additionally, we check if not all interfaces of the virtual group share the same connection speed
        if not speed:
            if "mac-address" in values:
                mac_list = if_mac_list[values["mac-address"]]
                if len(mac_list) > 1: # check if this interface is grouped
                    extra_info.setdefault(nic_name, {})
                    extra_info[nic_name]["grouped_if"] = [ x for x in mac_list if x not in vif_list ]

                    max_speed = 0
                    min_speed = 1024**5
                    for tmp_if in mac_list:
                        if tmp_if == nic_name or "speed" not in interfaces[tmp_if]:
                            continue
                        check_speed = interfaces[tmp_if]["speed"]
                        max_speed = max(max_speed, check_speed)
                        min_speed = min(min_speed, check_speed)
                    if max_speed != min_speed:
                        extra_info[nic_name]["speed_differs"] = (max_speed, min_speed)
                    speed = max_speed

        # Virtual interfaces is "Up" if at least one physical interface is up
        if "state" not in values:
            if "mac-address" in values:
                for tmp_if in if_mac_list[values["mac-address"]]:
                    if interfaces[tmp_if].get("state") == "1":
                        state = "1"
                        break

        # Only add interfaces with counters
        if "recv_data" in values:
            if values.get("mac-address"):
                mac = "".join(map(lambda x: chr(int(x, 16)), values["mac-address"].split(':')))
            else:
                mac = ''

            nic = ['0'] * 20
            nic[0]  = str(idx + 1)                          # Index
            nic[1]  = nic_name                              # Description
            nic[2]  = "6" # Fake ethernet                   # Type
            nic[3]  = speed                                 # Speed
            nic[4]  = state                                 # Status
            # IN
            nic[5]  = values.get("recv_data", 0)            # inoctets
            nic[6]  = 0                                     # inucast
            nic[7]  = values.get("recv_mcasts", 0)          # inmcast
            nic[8]  = 0                                     # ibcast
            nic[9]  = 0                                     # indiscards
            nic[10] = values.get("recv_errors", 0)          # inerrors
            # OUT
            nic[11] = values.get("send_data", 0)            # outoctets
            nic[12] = 0                                     # outucast
            nic[13] = values.get("send_mcasts", 0)          # outmcast
            nic[14] = 0                                     # outbcast
            nic[15] = 0                                     # outdiscards
            nic[16] = values.get("send_errors", 0)          # outspeed
            nic[17] = 0                                     # outqlen
            nic[18] = values.get("interface-name", "")      # Alias
            nic[19] = mac                                   # MAC

            nics.append(nic)

    return nics, extra_info

def inventory_netapp_api_if(parsed):
    nics, extra_info = parsed
    return inventory_if_common(nics)

def check_netapp_api_if(item, params, parsed):
    nics, extra_info = parsed
    yield check_if_common(item, params, nics)

    for line in nics:
        ifIndex = line[0]
        ifDescr = line[1]
        ifAlias = line[18]
        if type(ifIndex) == tuple:
            ifGroup, ifIndex = ifIndex

        ifDescr_cln = cleanup_if_strings(ifDescr)
        ifAlias_cln = cleanup_if_strings(ifAlias)
        if if_item_matches(item, ifIndex, ifAlias_cln, ifDescr_cln):
            if ifDescr in extra_info:
                vif_group = extra_info[ifDescr]
                yield 0, "Physical interfaces: %s" %\
                    ", ".join([group for group in vif_group["grouped_if"] if group != ifDescr])
                if "speed_differs" in vif_group:
                    yield 1, "Interfaces do not have the same speed"

check_info["netapp_api_if"] = {
    'check_function'          : check_netapp_api_if,
    'inventory_function'      : inventory_netapp_api_if,
    'parse_function'          : netapp_convert_to_if64,
    'service_description'     : 'Interface %s',
    'has_perfdata'            : True,
    'group'                   : 'if',
    'includes'                : [ 'if.include', 'netapp_api.include' ],
    'default_levels_variable' : 'if_default_levels',
}
