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

#   .--kernel--Counters----------------------------------------------------.
#   |                ____                  _                               |
#   |               / ___|___  _   _ _ __ | |_ ___ _ __ ___                |
#   |              | |   / _ \| | | | '_ \| __/ _ \ '__/ __|               |
#   |              | |__| (_) | |_| | | | | ||  __/ |  \__ \               |
#   |               \____\___/ \__,_|_| |_|\__\___|_|  |___/               |
#   |                                                                      |
#   +----------------------------------------------------------------------+
#   |  Check page faults, context switches and process creations           |
#   '----------------------------------------------------------------------'

# Inventory creates three checks per default:
inventory_kernel_counters = [ "pgmajfault", "ctxt", "processes" ]
kernel_default_levels = None

kernel_counter_names = {
  "ctxt"       : "Context Switches",
  "processes"  : "Process Creations",
  "pgmajfault" : "Major Page Faults",
}

def inventory_kernel(info):
    inventory = []
    for counter in inventory_kernel_counters:
        hits = [ line[0] for line in info[1:] if line[0] == counter ]
        if len(hits) == 1:
            countername = kernel_counter_names.get(counter, counter)
            inventory.append( (countername, "kernel_default_levels") )
    return inventory


# item is one of the keys in /proc/stat or /proc/vmstat
def check_kernel(item, params, info):
    this_time = int(info[0][0])

    hits = [ (line[0], line[1])
             for line in info[1:]
             if line[0] == item or kernel_counter_names.get(line[0], line[0]) == item ]
    if len(hits) == 0:
        return (3, "item '%s' not found in agent output" % item)
    elif len(hits) > 1:
        return (3, "item '%s' not unique (found %d times)" % (item, len(hits)))

    counter = hits[0][0]
    this_val = int(hits[0][1])
    per_sec = get_rate(None, this_time, this_val)

    if type(params) == tuple:
        warn, crit = params
    else:
        warn, crit = None, None
    perfdata = [ (counter, per_sec, warn, crit) ]
    state, text, extraperf = check_levels(per_sec, counter, params)
    perfdata += extraperf
    infotext = "%.0f/s" % per_sec
    if text:
        infotext += ", " + text
    return state, infotext, perfdata


check_info["kernel"] = {
    'check_function':          check_kernel,
    'inventory_function':      inventory_kernel,
    'service_description':     'Kernel %s',
    'has_perfdata':            True,
    'group':                   'vm_counter',
}

#.
#   .--kernel.util--CPU Utilization----------------------------------------.
#   |             _   _ _   _ _ _          _   _                           |
#   |            | | | | |_(_) (_)______ _| |_(_) ___  _ __                |
#   |            | | | | __| | | |_  / _` | __| |/ _ \| '_ \               |
#   |            | |_| | |_| | | |/ / (_| | |_| | (_) | | | |              |
#   |             \___/ \__|_|_|_/___\__,_|\__|_|\___/|_| |_|              |
#   |                                                                      |
#   +----------------------------------------------------------------------+
#   |  Check system/user/io-wait                                           |
#   '----------------------------------------------------------------------'

kernel_util_default_levels = None

def inventory_cpu_utilization(info):
    for x in info:
        if len(x) > 0 and x[0] == 'cpu':
            return [(None, {})]


def transform_cpu_info(element):
    if len(element) < 8:
        element += ['0', '0', '0', '0'] # needed for Linux 2.4

    return [element[0]] + [int(x) for x in element[1:]]

# Columns of cpu usage /proc/stat:
# - cpuX: number of CPU or only 'cpu' for aggregation
# - user: normal processes executing in user mode
# - nice: niced processes executing in user mode
# - system: processes executing in kernel mode
# - idle: twiddling thumbs
# - iowait: waiting for I/O to complete
# - irq: servicing interrupts
# - softirq: servicing softirqs
# - steal: Stolen time, which is the time spent in other operating systems
#          when running in a virtualized environment (since Linux 2.6.11)
# - guest: Time spent running a virtual CPU for guest operating systems (since Linux 2.6.24)
# - guest_nice: Time spent running a niced guest (since Linux 2.6.33)

def kernel_check_cpu_utilization(item, params, info):
    # Convert old style tuple-parameter to new dict
    if type(params) != dict:
        params = { "iowait": params }

    # Look for entry matching "cpu" (this is the combined load of all cores)
    total = [transform_cpu_info(line)
         for line in info
         if line[0] == "cpu"]

    if len(total) != 1:
        return 3, "More than one line with CPU info found. This check is not cluster-enabled."

    cores = [transform_cpu_info(line)
             for line in info
             if line[0].startswith("cpu") and len(line[0]) > 3]
    # total contains now the following columns:
    # 'cpu' user nice system idle wait hw-int sw-int (steal ...)
    # convert number to int
    return check_cpu_util_unix(total[0][1:], params, cores)

check_info["kernel.util"] = {
    'check_function':           kernel_check_cpu_utilization,
    'inventory_function':       inventory_cpu_utilization,
    'service_description':      'CPU utilization',
    'has_perfdata':             True,
    'default_levels_variable':  'kernel_util_default_levels',
    'group':                    'cpu_iowait',
    'includes':                 ['cpu_util.include'],
}

