#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2019 tribe29 GmbH - License: GNU General Public License v2
# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and
# conditions defined in the file COPYING, which is part of this source code package.

# NOTE: Careful when replacing the *-import below with a more specific import. This can cause
# problems because it might remove variables from the check-context which are necessary for
# resolving legacy discovery results such as [("SUMMARY", "diskstat_default_levels")]. Furthermore,
# it might also remove variables needed for accessing discovery rulesets.
from cmk.base.check_legacy_includes.cpu_util import *  # pylint: disable=wildcard-import,unused-wildcard-import

# NOTE: Careful when replacing the *-import below with a more specific import. This can cause
# problems because it might remove variables from the check-context which are necessary for
# resolving legacy discovery results such as [("SUMMARY", "diskstat_default_levels")]. Furthermore,
# it might also remove variables needed for accessing discovery rulesets.
from cmk.base.check_legacy_includes.fortigate_sessions import *  # pylint: disable=wildcard-import,unused-wildcard-import

#
# monitoring of cluster members (nodes) in fortigate high availability tree
#

# cluster info
# .1.3.6.1.4.1.12356.101.13.1.1.0 3
# .1.3.6.1.4.1.12356.101.13.1.7.0 DEPTHA-HA

# node info
# .1.3.6.1.4.1.12356.101.13.2.1.1.11.1 NODE-01
# .1.3.6.1.4.1.12356.101.13.2.1.1.11.2 NODE-02
# .1.3.6.1.4.1.12356.101.13.2.1.1.3.1 13
# .1.3.6.1.4.1.12356.101.13.2.1.1.3.2 1
# .1.3.6.1.4.1.12356.101.13.2.1.1.4.1 52
# .1.3.6.1.4.1.12356.101.13.2.1.1.4.2 21
# .1.3.6.1.4.1.12356.101.13.2.1.1.6.1 1884
# .1.3.6.1.4.1.12356.101.13.2.1.1.6.2 742

# only one node given => standalone cluster
# .1.3.6.1.4.1.12356.101.13.2.1.1.11.1  ""
# .1.3.6.1.4.1.12356.101.13.2.1.1.3.1  0
# .1.3.6.1.4.1.12356.101.13.2.1.1.4.1  19
# .1.3.6.1.4.1.12356.101.13.2.1.1.6.1  443

#   .--Info----------------------------------------------------------------.
#   |                         ___        __                                |
#   |                        |_ _|_ __  / _| ___                           |
#   |                         | || '_ \| |_ / _ \                          |
#   |                         | || | | |  _| (_) |                         |
#   |                        |___|_| |_|_|  \___/                          |
#   |                                                                      |
#   '----------------------------------------------------------------------'


def parse_fortigate_node(info):
    parsed = {}
    if info[0]:
        parsed["cluster_info"] = info[0][0]

    for hostname, cpu_str, memory_str, sessions_str, oid_end in info[1]:
        # This means we have a standalone cluster
        if len(info[1]) == 1:
            item_name = "Cluster"
        elif hostname:
            item_name = hostname
        else:
            item_name = "Node %s" % oid_end

        parsed.setdefault("nodes", {})
        parsed["nodes"].setdefault(
            item_name,
            {
                "cpu": float(cpu_str),
                "memory": int(memory_str),
                "sessions": int(sessions_str),
            },
        )

    return parsed


def inventory_fortigate_cluster(parsed):
    if "cluster_info" in parsed:
        return [(None, None)]


def check_fortigate_cluster(_no_item, _no_params, parsed):
    map_mode = {
        "1": "Standalone",
        "2": "Active/Active",
        "3": "Active/Passive",
    }

    if "cluster_info" in parsed:
        system_mode, group_name = parsed["cluster_info"]
        return 0, "System mode: %s, Group: %s" % (map_mode[system_mode], group_name)


check_info["fortigate_node"] = {
    "parse_function": parse_fortigate_node,
    "inventory_function": inventory_fortigate_cluster,
    "check_function": check_fortigate_cluster,
    "service_description": "Cluster Info",
    "snmp_scan_function": lambda oid: ".1.3.6.1.4.1.12356.101.1" in oid(".1.3.6.1.2.1.1.2.0")
    # exclude FortiGates in standalone mode
    and oid(".1.3.6.1.4.1.12356.101.13.1.1.0") != "1",
    "snmp_info": [
        (
            ".1.3.6.1.4.1.12356.101.13.1",
            [
                1,  # fgHaSystemMode
                7,  # fgHaGroupName
            ],
        ),
        (
            ".1.3.6.1.4.1.12356.101.13.2.1.1",
            [
                11,  # fgHaStatsHostname
                3,  # fgHaStatsCpuUsage
                4,  # fgHaStatsMemUsage
                6,  # fgHaStatsSesCount
                OID_END,
            ],
        ),
    ],
}

# .
#   .--CPU-----------------------------------------------------------------.
#   |                           ____ ____  _   _                           |
#   |                          / ___|  _ \| | | |                          |
#   |                         | |   | |_) | | | |                          |
#   |                         | |___|  __/| |_| |                          |
#   |                          \____|_|    \___/                           |
#   |                                                                      |
#   '----------------------------------------------------------------------'

fortigate_node_cpu_default_levels = (80.0, 90.0)


def inventory_fortigate_node_cpu(parsed):
    for hostname in parsed["nodes"]:
        yield hostname, "fortigate_node_cpu_default_levels"


def check_fortigate_node_cpu(item, params, parsed):
    if item in parsed["nodes"]:
        return check_cpu_util(parsed["nodes"][item]["cpu"], params)


check_info["fortigate_node.cpu"] = {
    "inventory_function": inventory_fortigate_node_cpu,
    "check_function": check_fortigate_node_cpu,
    "service_description": "CPU utilization %s",
    "has_perfdata": True,
}

# .
#   .--Sessions------------------------------------------------------------.
#   |                ____                _                                 |
#   |               / ___|  ___  ___ ___(_) ___  _ __  ___                 |
#   |               \___ \ / _ \/ __/ __| |/ _ \| '_ \/ __|                |
#   |                ___) |  __/\__ \__ \ | (_) | | | \__ \                |
#   |               |____/ \___||___/___/_|\___/|_| |_|___/                |
#   |                                                                      |
#   '----------------------------------------------------------------------'

fortigate_node_sessions_default_levels = (100000, 150000)


def inventory_fortigate_node_ses(parsed):
    for hostname in parsed["nodes"]:
        yield hostname, "fortigate_node_sessions_default_levels"


def check_fortigate_node_ses(item, params, parsed):
    if item in parsed["nodes"]:
        if isinstance(params, dict):
            params = params["levels"]
        return fortigate_sessions(parsed["nodes"][item]["sessions"], params)


check_info["fortigate_node.sessions"] = {
    "inventory_function": inventory_fortigate_node_ses,
    "check_function": check_fortigate_node_ses,
    "service_description": "Sessions %s",
    "has_perfdata": True,
    "group": "fortigate_node_sessions",
}
