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

# .
#   .--State---------------------------------------------------------------.
#   |                       ____  _        _                               |
#   |                      / ___|| |_ __ _| |_ ___                         |
#   |                      \___ \| __/ _` | __/ _ \                        |
#   |                       ___) | || (_| | ||  __/                        |
#   |                      |____/ \__\__,_|\__\___|                        |
#   |                                                                      |
#   +----------------------------------------------------------------------+


def inventory_esx_vsphere_hostsystem_state(parsed):
    if "runtime.inMaintenanceMode" in parsed:
        return [(None, None)]


def check_esx_vsphere_hostsystem_state(_no_item, _no_params, parsed):
    state = 0
    if "overallStatus" not in parsed:
        return

    overallStatus = str(parsed["overallStatus"][0])
    if overallStatus == "yellow":
        state = 1
    elif overallStatus in ["red", "gray"]:
        state = 2
    yield state, "Entity state: " + overallStatus

    state = 0
    powerState = str(parsed["runtime.powerState"][0])
    if powerState in ["poweredOff", "unknown"]:
        state = 2
    elif powerState == "standBy":
        state = 1
    yield state, "Power state: " + powerState


check_info["esx_vsphere_hostsystem.state"] = {
    "inventory_function": inventory_esx_vsphere_hostsystem_state,
    "check_function": check_esx_vsphere_hostsystem_state,
    "service_description": "Overall state",
}

# .
#   .--Maintenance---------------------------------------------------------.
#   |       __  __       _       _                                         |
#   |      |  \/  | __ _(_)_ __ | |_ ___ _ __   __ _ _ __   ___ ___        |
#   |      | |\/| |/ _` | | '_ \| __/ _ \ '_ \ / _` | '_ \ / __/ _ \       |
#   |      | |  | | (_| | | | | | ||  __/ | | | (_| | | | | (_|  __/       |
#   |      |_|  |_|\__,_|_|_| |_|\__\___|_| |_|\__,_|_| |_|\___\___|       |
#   |                                                                      |
#   +----------------------------------------------------------------------+
#   |                                                                      |
#   '----------------------------------------------------------------------'


def inventory_esx_vsphere_hostsystem_maintenance(parsed):
    if "runtime.inMaintenanceMode" in parsed:
        current_state = str(parsed["runtime.inMaintenanceMode"][0]).lower()
        return [(None, {"target_state": current_state})]


def check_esx_vsphere_hostsystem_maintenance(_no_item, params, parsed):
    target_state = params["target_state"]

    if "runtime.inMaintenanceMode" not in parsed:
        return

    current_state = str(parsed["runtime.inMaintenanceMode"][0]).lower()
    state = 0
    if target_state != current_state:
        state = 2
    if current_state == "true":
        return state, "System running is in Maintenance mode"
    return state, "System not in Maintenance mode"


check_info["esx_vsphere_hostsystem.maintenance"] = {
    "inventory_function": inventory_esx_vsphere_hostsystem_maintenance,
    "check_function": check_esx_vsphere_hostsystem_maintenance,
    "service_description": "Maintenance Mode",
    "group": "esx_hostystem_maintenance",
}

# .
#   .--Multipath-----------------------------------------------------------.
#   |             __  __       _ _   _             _   _                   |
#   |            |  \/  |_   _| | |_(_)_ __   __ _| |_| |__                |
#   |            | |\/| | | | | | __| | '_ \ / _` | __| '_ \               |
#   |            | |  | | |_| | | |_| | |_) | (_| | |_| | | |              |
#   |            |_|  |_|\__,_|_|\__|_| .__/ \__,_|\__|_| |_|              |
#   |                                 |_|                                  |
#   +----------------------------------------------------------------------+

# 5.1
# fc.20000024ff2e1b4c:21000024ff2e1b4c-fc.500a098088866d7e:500a098188866d7e-naa.60a9800044314f68553f436779684544 active
# unknown.vmhba0-unknown.2:0-naa.6b8ca3a0facdc9001a2a27f8197dd718 active
# 5.5
# fc.20000024ff3708ec:21000024ff3708ec-fc.500a098088866d7e:500a098188866d7e-naa.60a9800044314f68553f436779684544 active
# fc.500143802425a24d:500143802425a24c-fc.5001438024483280:5001438024483288-naa.5001438024483280 active
# >= version 6.0
# vmhba32:C0:T0:L0 active


def esx_vsphere_multipath_convert(data):

    raw_path_info = data.get("config.storageDevice.multipathInfo")
    if not raw_path_info:
        return {}

    paths = {}
    for lun_id, path, state in zip(raw_path_info[::3], raw_path_info[1::3], raw_path_info[2::3]):
        paths.setdefault(lun_id, []).append((state, path))
    return paths


def inventory_esx_vsphere_hostsystem_multipath(parsed):
    return [(x, None) for x in esx_vsphere_multipath_convert(parsed)]


def check_esx_vsphere_hostsystem_multipath(item, params, parsed):
    state_infos = {
        # alert_state, count, info
        "active": [0, 0, ""],
        "dead": [2, 0, ""],
        "disabled": [1, 0, ""],
        "standby": [0, 0, ""],
        "unknown": [2, 0, ""],
    }

    state = 0
    message = ""
    path_names = []

    states = esx_vsphere_multipath_convert(parsed).get(item)
    if states is None:
        return states

    # Collect states
    for path_state, path_name in states:
        state_item = state_infos.get(path_state)
        path_info = path_name
        if state_item:
            state_item[1] += 1
            state = max(state_item[0], state)
            path_info += state_markers[state_item[0]]
        path_names.append(path_info)

    # Check warn, critical
    if not params or isinstance(params, list):
        if state_infos["standby"][1] > 0 and state_infos["standby"][1] != state_infos["active"][1]:
            state = max(state_infos["standby"][0], state)
    else:
        state = 0
        for state_name, state_values in state_infos.items():
            if params.get(state_name):
                limits = params.get(state_name)
                if len(limits) == 2:
                    warn_max, crit_max = limits
                    crit_min, warn_min = 0, 0
                else:
                    crit_min, warn_min, warn_max, crit_max = limits

                count = state_values[1]
                if count < crit_min:
                    state = max(state, 2)
                    state_values[2] = "(!!)(less than %d)" % crit_min
                elif count > crit_max:
                    state = max(state, 2)
                    state_values[2] = "(!!)(more than %d)" % crit_max
                elif count < warn_min:
                    state = max(state, 1)
                    state_values[2] = "(!)(less than %d)" % warn_min
                elif count > warn_max:
                    state = max(state, 1)
                    state_values[2] = "(!)(more than %d)" % warn_max

    # Output message
    message = ""

    element_text = []
    for element in "active", "dead", "disabled", "standby", "unknown":
        element_text.append("%d %s%s" % (state_infos[element][1], element, state_infos[element][2]))
    message += ", ".join(element_text)
    message += "\nIncluded Paths:\n" + "\n".join(path_names)

    return state, message


check_info["esx_vsphere_hostsystem.multipath"] = {
    "inventory_function": inventory_esx_vsphere_hostsystem_multipath,
    "check_function": check_esx_vsphere_hostsystem_multipath,
    "service_description": "Multipath %s",
    "group": "multipath_count",
}
