#!/usr/bin/python
# -*- encoding: utf-8; py-indent-offset: 4 -*-
# +------------------------------------------------------------------+
# |             ____ _               _        __  __ _  __           |
# |            / ___| |__   ___  ___| | __   |  \/  | |/ /           |
# |           | |   | '_ \ / _ \/ __| |/ /   | |\/| | ' /            |
# |           | |___| | | |  __/ (__|   <    | |  | | . \            |
# |            \____|_| |_|\___|\___|_|\_\___|_|  |_|_|\_\           |
# |                                                                  |
# | Copyright Mathias Kettner 2018             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.


def discover_k8s_stats_network(parsed):
    # don't use the k8s check if the check_mk_agent delivers interface data
    parsed, lnx_info = parsed
    if lnx_info:
        return

    for key, value in parsed.iteritems():
        if key != 'network':
            continue

        interfaces = {i.get('name') for i in value['interfaces']}
        for interface in interfaces:
            yield interface, {}


def discover_k8s_stats_fs(parsed):
    parsed, _ = parsed
    ignore_fs = ['tmpfs', 'rootfs']

    for key, value in parsed.iteritems():
        if key != 'filesystem':
            continue

        devices = {disk.get('device') for disk in value}
        for device in devices:
            if device not in ignore_fs:
                yield device, {}


def k8s_network_err_pac(device, params, now):
    for name, mway, pway in [('Input', 'rx', 'in'), ('Output', 'tx', 'out')]:
        pac_rate = get_rate('if.%s.if_%s_pkts' % (device['name'], pway), now,
                            device['%s_packets' % mway])
        err_rate = get_rate('if.%s.if_%s_errors' % (device['name'], pway), now,
                            device['%s_errors' % mway])
        warn, crit = params.get('errors', (None, None))
        perf_data = [('if_%s_pkts' % pway, pac_rate), ('if_%s_errors' % pway, err_rate)]
        if isinstance(warn, float):
            try:
                err_perc = 100.0 * err_rate / (err_rate + pac_rate)
            except ZeroDivisionError:
                err_perc = 0

            status, infotext, _perf = check_levels_backport(
                err_perc, 'err_perc', (warn, crit), unit='%', infoname=name + " errors percentage")
        else:  # absolute levels or no levels
            status, infotext, _perf = check_levels_backport(
                err_rate, 'if_errors', (warn, crit), unit='/s', infoname=name + " error rate")

        yield status, infotext, perf_data


def check_k8s_stats_network(item, params, parsed):
    metrics, _ = parsed

    device = sum([
        collections.Counter(device)
        for device in metrics['network']['interfaces']
        if device.get('name') == item
    ], collections.Counter())

    now = metrics['timestamp']

    # Bandwidth
    for name, met, dsname in [('In', 'rx_bytes', 'in'), ('Out', 'tx_bytes', 'out')]:
        rate = get_rate('if.%s.%s' % (item, dsname), now, device[met])
        yield check_levels_backport(
            rate,
            dsname,
            None,
            unit='/s',
            human_readable_func=lambda x: "%s/s" % get_bytes_human_readable(x),
            infoname=name)

    # Errors / Packets
    for check_result in k8s_network_err_pac(device, params, now):
        yield check_result

    # Discards
    for name, met, dsname in [
        ('Input Discards', 'rx_dropped', 'if_in_discards'),
        ('Output Discards', 'tx_dropped', 'if_out_discards'),
    ]:
        rate = get_rate('if.%s.%s' % (item, dsname), now, device[met])
        yield check_levels_backport(rate, dsname, params.get('discards'), unit='/s', infoname=name)


def check_k8s_stats_fs(item, params, parsed):
    metrics, _ = parsed

    disk = sum([
        collections.Counter(device)
        for device in metrics['filesystem']
        if device.get('device') == item
    ], collections.Counter())

    yield df_check_filesystem_single(
        item,
        disk['capacity'] / 1024.0 / 1024.0,
        disk['available'] / 1024.0 / 1024.0,
        0,
        disk['inodes'],
        disk['inodes_free'],
        params,
    )


check_info['k8s_stats'] = {
    'parse_function': parse_k8s,
    'extra_sections': ['lnx_if'],
}

check_info['k8s_stats.network'] = {
    'inventory_function': discover_k8s_stats_network,
    'check_function': check_k8s_stats_network,
    'service_description': 'Interface %s',
    "has_perfdata": True,
    "group": "k8s_if",
    'includes': ['backport.include', 'k8s.include'],
}

check_info['k8s_stats.fs'] = {
    'inventory_function': discover_k8s_stats_fs,
    'check_function': check_k8s_stats_fs,
    'service_description': 'Filesystem %s',
    "has_perfdata": True,
    "group": "filesystem",
    "default_levels_variable": "filesystem_default_levels",
    'includes': ['backport.include', 'k8s.include', 'size_trend.include', 'df.include'],
}
