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

# exemplary output of special agent agent_ucs_bladecenter (separator is <TAB> and means tabulator):
#
# <<<ucs_c_rack_server_util:sep(9)>>>
# serverUtilization<TAB>dn sys/rack-unit-1/utilization<TAB>overallUtilization 0<TAB>cpuUtilization 0<TAB>memoryUtilization 0<TAB>ioUtilization 0
# serverUtilization<TAB>dn sys/rack-unit-2/utilization<TAB>overallUtilization 90<TAB>cpuUtilization 90<TAB>memoryUtilization 90<TAB>ioUtilization 90
#
# The format of the XML API v2.0 raw output provided via the agent is not documented.
# The description about the meaning of the XML attributes is described in the corresponding
# section of the GUI Configuration Guide. The units of overallUtilization, cpuUtilization,
# memoryUtilization and ioUtilization are percentages.
# https://www.cisco.com/c/en/us/td/docs/unified_computing/ucs/c/sw/gui/config/guide/3_1/b_Cisco_UCS_C-series_GUI_Configuration_Guide_31/b_Cisco_UCS_C-series_GUI_Configuration_Guide_31_chapter_0101.pdf


def parse_ucs_c_rack_server_util(info):
    """
    Returns dict with indexed racks mapped to keys and utilization values mapped to dicts.
    """
    parsed = {}
    # The element count of info lines is under our control (agent output) and
    # ensured to have expected length. It is ensured that elements contain a
    # string. Handles invalid values provided by the XML API which cannot be
    # casted by setting corresponding values to None.
    for _, dn, overall_util, cpu_util, memory_util, pci_io_util in info:
        rack = (
            dn.replace("dn ", "")
            .replace("sys/", "")
            .replace("rack-unit-", "Rack unit ")
            .replace("/utilization", "")
        )

        for ds_key, ds in (
            ("overallUtilization", overall_util),
            ("cpuUtilization", cpu_util),
            ("memoryUtilization", memory_util),
            ("ioUtilization", pci_io_util),
        ):
            try:
                value = float(ds.replace(ds_key + " ", ""))
            except ValueError:
                continue
            parsed.setdefault(rack, {})[ds_key] = value

    return parsed


def inventory_ucs_c_rack_server_util(parsed):
    """
    Yields indexed racks as items (e.g. Rack Unit 1).
    """
    for key in parsed:
        yield key, {}


##########################
# ucs_c_rack_server_util #
##########################

factory_settings["ucs_c_rack_server_util_overall_default_levels"] = {
    "upper_levels": (90.0, 95.0),
}


@get_parsed_item_data
def check_ucs_c_rack_server_util(item, params, data):
    # None values passed to check_levels(value, ...) are handled by Checkmk internals appropriatelly.
    yield check_levels(
        data["overallUtilization"],
        "overall_util",
        params["upper_levels"],
        human_readable_func=get_percent_human_readable,
    )


check_info["ucs_c_rack_server_util"] = {
    "parse_function": parse_ucs_c_rack_server_util,
    "inventory_function": inventory_ucs_c_rack_server_util,
    "check_function": check_ucs_c_rack_server_util,
    "group": "overall_utilization_multiitem",
    "service_description": "Overall Utilization %s",
    "default_levels_variable": "ucs_c_rack_server_util_overall_default_levels",
    "has_perfdata": True,
}

##############################
# ucs_c_rack_server_util.cpu #
##############################

factory_settings["ucs_c_rack_server_util_cpu_default_levels"] = {
    "upper_levels": (90.0, 95.0),
}


@get_parsed_item_data
def check_ucs_c_rack_server_util_cpu(item, params, data):
    # None values passed to check_levels(value, ...) are handled by Checkmk internals appropriatelly.
    return check_cpu_util(data["cpuUtilization"], params["upper_levels"])


check_info["ucs_c_rack_server_util.cpu"] = {
    "inventory_function": inventory_ucs_c_rack_server_util,
    "check_function": check_ucs_c_rack_server_util_cpu,
    "group": "cpu_utilization_multiitem",
    "service_description": "CPU Utilization %s",
    "default_levels_variable": "ucs_c_rack_server_util_cpu_default_levels",
    "has_perfdata": True,
}

#################################
# ucs_c_rack_server_util.pci_io #
#################################

factory_settings["ucs_c_rack_server_util_pci_io_default_levels"] = {
    "upper_levels": (90.0, 95.0),
}


@get_parsed_item_data
def check_ucs_c_rack_server_util_pci_io(item, params, data):
    yield check_levels(
        data["ioUtilization"],
        "pci_io_util",
        params["upper_levels"],
        human_readable_func=get_percent_human_readable,
    )


check_info["ucs_c_rack_server_util.pci_io"] = {
    "inventory_function": inventory_ucs_c_rack_server_util,
    "check_function": check_ucs_c_rack_server_util_pci_io,
    "group": "pci_io_utilization_multiitem",
    "service_description": "PCI IO Utilization %s",
    "default_levels_variable": "ucs_c_rack_server_util_pci_io_default_levels",
    "has_perfdata": True,
}

##############################
# ucs_c_rack_server_util.mem #
##############################

factory_settings["ucs_c_rack_server_util_mem_default_levels"] = {
    "upper_levels": (90.0, 95.0),
}


@get_parsed_item_data
def check_ucs_c_rack_server_util_mem(item, params, data):
    yield check_levels(
        data["memoryUtilization"],
        "memory_util",
        params["upper_levels"],
        human_readable_func=get_percent_human_readable,
    )


check_info["ucs_c_rack_server_util.mem"] = {
    "inventory_function": inventory_ucs_c_rack_server_util,
    "check_function": check_ucs_c_rack_server_util_mem,
    "group": "memory_utilization_multiitem",
    "service_description": "Memory Utilization %s",
    "default_levels_variable": "ucs_c_rack_server_util_mem_default_levels",
    "has_perfdata": True,
}
