#!/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.aws 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.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.diskstat import *  # pylint: disable=wildcard-import,unused-wildcard-import
from cmk.base.plugins.agent_based.aws_ec2 import EC2DefaultItemName

#   .--status check--------------------------------------------------------.
#   |           _        _                    _               _            |
#   |       ___| |_ __ _| |_ _   _ ___    ___| |__   ___  ___| | __        |
#   |      / __| __/ _` | __| | | / __|  / __| '_ \ / _ \/ __| |/ /        |
#   |      \__ \ || (_| | |_| |_| \__ \ | (__| | | |  __/ (__|   <         |
#   |      |___/\__\__,_|\__|\__,_|___/  \___|_| |_|\___|\___|_|\_\        |
#   |                                                                      |
#   +----------------------------------------------------------------------+
#   |                            main check                                |
#   '----------------------------------------------------------------------'


def check_aws_ec2_status_check(item, params, parsed):
    go_stale = True

    for title, key in [
        ("System", "StatusCheckFailed_System"),
        ("Instance", "StatusCheckFailed_Instance"),
    ]:
        try:
            state, state_readable = _get_status_check_readable(parsed[key])
        except KeyError:
            continue
        yield state, "%s: %s" % (title, state_readable)
        go_stale = False

    if go_stale:
        raise MKCounterWrapped("Currently no data from AWS")


def _get_status_check_readable(value):
    if int(value) == 0:
        return 0, "passed"
    return 2, "failed"


check_info["aws_ec2"] = {
    "inventory_function": lambda p: inventory_aws_generic_single(
        p,
        ["StatusCheckFailed_System", "StatusCheckFailed_Instance"],
    ),
    "check_function": check_aws_ec2_status_check,
    "service_description": "AWS/EC2 Status Check",
}

# .
#   .--CPU credits---------------------------------------------------------.
#   |           ____ ____  _   _                     _ _ _                 |
#   |          / ___|  _ \| | | |   ___ _ __ ___  __| (_) |_ ___           |
#   |         | |   | |_) | | | |  / __| '__/ _ \/ _` | | __/ __|          |
#   |         | |___|  __/| |_| | | (__| | |  __/ (_| | | |_\__ \          |
#   |          \____|_|    \___/   \___|_|  \___|\__,_|_|\__|___/          |
#   |                                                                      |
#   '----------------------------------------------------------------------'

factory_settings["aws_cpu_credits"] = {
    "balance_levels_lower": (10, 5),
}


def check_aws_ec2_cpu_credits(item, params, parsed):
    return check_aws_metrics(
        [
            {
                "metric_val": parsed.get(cw_metric_name),
                "metric_name": metric_name,
                "levels": levels,
                "human_readable_func": human_readable_func,
                "info_name": info_name,
            }
            for cw_metric_name, metric_name, levels, human_readable_func, info_name in zip(
                ["CPUCreditUsage", "CPUCreditBalance"],
                [None, "aws_cpu_credit_balance"],
                [None, (None, None) + params["balance_levels_lower"]],
                [lambda x: "%.2f" % x] * 2,
                ["Usage", "Balance"],
            )
        ]
    )


check_info["aws_ec2.cpu_credits"] = {
    "inventory_function": lambda p: inventory_aws_generic_single(
        p,
        ["CPUCreditUsage", "CPUCreditBalance"],
    ),
    "check_function": check_aws_ec2_cpu_credits,
    "service_description": "AWS/EC2 CPU Credits",
    "group": "aws_ec2_cpu_credits",
    "default_levels_variable": "aws_cpu_credits",
    "has_perfdata": True,
}

# .
#   .--CPU utilization-----------------------------------------------------.
#   |    ____ ____  _   _         _   _ _ _          _   _                 |
#   |   / ___|  _ \| | | |  _   _| |_(_) (_)______ _| |_(_) ___  _ __      |
#   |  | |   | |_) | | | | | | | | __| | | |_  / _` | __| |/ _ \| '_ \     |
#   |  | |___|  __/| |_| | | |_| | |_| | | |/ / (_| | |_| | (_) | | | |    |
#   |   \____|_|    \___/   \__,_|\__|_|_|_/___\__,_|\__|_|\___/|_| |_|    |
#   |                                                                      |
#   '----------------------------------------------------------------------'

factory_settings["aws_ec2_cpu_util_default_levels"] = {
    "util": (90.0, 95.0),
}


def check_aws_ec2_cpu_util(item, params, parsed):
    if "CPUUtilization" not in parsed:
        raise MKCounterWrapped("Currently no data from AWS")
    return check_cpu_util(parsed["CPUUtilization"], params, time.time())


check_info["aws_ec2.cpu_util"] = {
    "inventory_function": lambda p: inventory_aws_generic_single(
        p,
        ["CPUUtilization"],
    ),
    "check_function": check_aws_ec2_cpu_util,
    "service_description": "AWS/EC2 CPU utilization",
    "group": "cpu_utilization",
    "default_levels_variable": "aws_ec2_cpu_util_default_levels",
    "has_perfdata": True,
}

# .
#   .--disk IO-------------------------------------------------------------.
#   |                         _ _     _      ___ ___                       |
#   |                      __| (_)___| | __ |_ _/ _ \                      |
#   |                     / _` | / __| |/ /  | | | | |                     |
#   |                    | (_| | \__ \   <   | | |_| |                     |
#   |                     \__,_|_|___/_|\_\ |___\___/                      |
#   |                                                                      |
#   '----------------------------------------------------------------------'


# It would be better to use metrics with the statistics "Sum" instead of "Average" for this check
# (since we want to compute rates). However, this is does not seem to be possible here. AWS
# publishes the EC2 metrics at 5-minute intervals, whereby each published datapoint consists of 5
# 1-minute datapoints (one can check this using the statistics "SampleCount", which gives the number
# of data points in the specified interval). If we request one of the metrics used below for the
# last 600s (which is what the agent does), we should get a SampleCount of 10, however, we will
# only get a sample count of 5. Hence, if we used the "Sum" statistics, we would be dividing a sum
# corresponding to a 5-minute interval by 10 minutes. Note that this problem does not occur when
# collecting the metrics for a 10-minute interval further in the past (for example from -20 min to
# -10 min).
def check_aws_ec2_disk_io(item, params, metrics):
    disk_data = {}
    for key, metrics_key in [
        ("read_ios", "DiskReadOps"),
        ("write_ios", "DiskWriteOps"),
        ("read_throughput", "DiskReadBytes"),
        ("write_throughput", "DiskWriteBytes"),
    ]:
        value = metrics.get(metrics_key)
        if value is None:
            continue
        disk_data[key] = value / 60

    if not disk_data:
        raise MKCounterWrapped("Currently no data from AWS")

    return check_diskstat_dict(item, params, {item: disk_data})


check_info["aws_ec2.disk_io"] = {
    "inventory_function": lambda p: inventory_aws_generic(
        {EC2DefaultItemName: p},
        ["DiskReadOps", "DiskWriteOps", "DiskReadBytes", "DiskWriteBytes"],
    ),
    "check_function": check_aws_ec2_disk_io,
    "service_description": "AWS/EC2 Disk IO %s",
    "group": "diskstat",
    "has_perfdata": True,
}
