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

# Example output from agent:
# <<<livestatus_status:sep(59)>>>
# [downsite]
# [mysite]
# accept_passive_host_checks;accept_passive_service_checks;cached_log_messages;check_external_commands;check_host_freshness;check_service_freshness;connections;connections_rate;enable_event_handlers;enable_flap_detection;enable_notifications;execute_host_checks;execute_service_checks;external_command_buffer_max;external_command_buffer_slots;external_command_buffer_usage;external_commands;external_commands_rate;forks;forks_rate;host_checks;host_checks_rate;interval_length;last_command_check;last_log_rotation;livecheck_overflows;livecheck_overflows_rate;livechecks;livechecks_rate;livestatus_active_connections;livestatus_queued_connections;livestatus_threads;livestatus_version;log_messages;log_messages_rate;nagios_pid;neb_callbacks;neb_callbacks_rate;num_hosts;num_services;obsess_over_hosts;obsess_over_services;process_performance_data;program_start;program_version;requests;requests_rate;service_checks;service_checks_rate
# 1;1;0;1;0;1;231;1.0327125668e-01;1;1;1;1;1;0;32768;0;0;0.0000000000e+00;0;0.0000000000e+00;0;0.0000000000e+00;60;1359471450;0;0;0.0000000000e+00;0;0.0000000000e+00;1;0;20;2013.01.23;0;0.0000000000e+00;15126;15263;6.5307324420e+00;0;0;0;0;1;1359469039;3.2.3;230;1.0327125668e-01;0;0.0000000000e+00

factory_settings["livestatus_status_default_levels"] = {
    "site_stopped"                  : 2,
    "execute_host_checks"           : 2,
    "execute_service_checks"        : 2,
    "accept_passive_host_checks"    : 2,
    "accept_passive_service_checks" : 2,
    "check_host_freshness"          : 0, # Was in OMD the default up to now, better not warn
    "check_service_freshness"       : 1,
    "enable_event_handlers"         : 1,
    "enable_flap_detection"         : 1,
    "enable_notifications"          : 2,
    "process_performance_data"      : 1,
    "check_external_commands"       : 2,
}


def parse_livestatus_status(info):
    parsed = {}
    n = 0
    while n < len(info):
        site = info[n][0][1:-1]
        if n == len(info) - 1 or info[n+1][0].startswith('['):
            # Handle the case if the check running in cluster
            if site not in parsed.keys():
                parsed[site] = None # Site is down
            n += 1
        else:
            headers = info[n+1]
            values = info[n+2]
            parsed[site] = dict(zip(headers, values))
            n += 3
    return parsed


def inventory_livestatus_status(parsed):
    return [ (site, {}) for (site, status) in parsed.items() if status != None ]



def check_livestatus_status(item, params, parsed):
    if item not in parsed:
        return
    status = parsed[item]

    # Ignore down sites. This happens on a regular basis due to restarts
    # of the core. The availability of a site is monitored with 'omd_status'.
    if status == None:
        yield params["site_stopped"], "Site is currently not running"
        return

    # Check Performance counters
    this_time = time.time()
    status_counters = [
        # conv_func, factor, calc_rate, column, format, title
        (int, 1, True, "%.1f/s", "host_checks",    "Host Checks",         ),
        (int, 1, True, "%.1f/s", "service_checks", "Service Checks",      ),
        (int, 1, True, "%.1f/s", "forks",          "Process Creations",   ),
        (int, 1, True, "%.1f/s", "connections",    "Livestatus Connects", ),
        (int, 1, True, "%.1f/s", "requests",       "Livestatus Requests", ),
        (int, 1, True, "%.1f/s", "log_messages",   "Log Messages",        ),
    ]

    if status["program_version"].startswith("Check_MK"):
        # We have a CMC here.

        status_counters += [
            # conv_func, factor, calc_rate, format, column, title
            (float, 1,   False, "%.3fs",  "average_latency_generic",   "Average check latency"),
            (float, 1,   False, "%.3fs",  "average_latency_cmk",       "Average Check_MK latency"),
            (float, 100, False, "%.1f%%", "helper_usage_generic",      "Check helper usage"),
            (float, 100, False, "%.1f%%", "helper_usage_cmk",          "Check_MK helper usage"),
            (float, 100, False, "%.1f%%", "livestatus_usage",          "Livestatus usage"),
            (float, 1,   False, "%.1f/s", "livestatus_overflows_rate", "Livestatus overflow rate"),
        ]

    for conv_func, factor, calc_rate, fmt, counter, title in status_counters:
        value = factor * conv_func(status[counter])

        if calc_rate:
            value = get_rate("livestatus_status.%s.%s" % (item, counter), this_time, value)

        yield 0, ("%s: %s" % (title, fmt % value)), [(counter, value)]

    yield 0, "%d Hosts" % int(status["num_hosts"]), [("monitored_hosts", int(status["num_hosts"]))]
    yield 0, "%d Services" % int(status["num_services"]), [("monitored_services", int(status["num_services"]))]

    # Output some general information
    yield 0, "Core version: %s"       % status["program_version"]
    yield 0, "Livestatus version: %s" % status["livestatus_version"]

    if status["program_version"].startswith("Check_MK 1.2.6"):
        # In CMC <= 1.2.6 event handlers cannot be enabled. So never warn.
        params["enable_event_handlers"] = 0
    elif status.get("has_event_handlers", '1') == '0':
        # After update from < 1.2.7 the check would warn about disabled alert
        # handlers since they are disabled in this case. But the user has no alert
        # handlers defined, so this is nothing to warn about. Start warn when the
        # user defines his first alert handlers.
        params["enable_event_handlers"] = 0

    settings = [
        ("execute_host_checks",           "Active host checks are disabled"),
        ("execute_service_checks",        "Active service checks are disabled"),
        ("accept_passive_host_checks",    "Passive host check are disabled"),
        ("accept_passive_service_checks", "Passive service checks are disabled"),
        ("check_host_freshness",          "Host freshness checking is disabled"),
        ("check_service_freshness",       "Service freshness checking is disabled"),
        ("enable_event_handlers",         "Event handlers are disabled"),
        ("enable_flap_detection",         "Flap detection is disabled"),
        ("enable_notifications",          "Notifications are disabled"),
        ("process_performance_data",      "Performance data is disabled"),
        ("check_external_commands",       "External commands are disabled"),
    ]
    # Check settings of enablings. Here we are quiet unless a non-OK state is found
    for settingname, title in settings:
        if status[settingname] != '1' and params[settingname] != 0:
            yield params[settingname], title


check_info['livestatus_status'] = {
    "parse_function"          : parse_livestatus_status,
    "inventory_function"      : inventory_livestatus_status,
    "check_function"          : check_livestatus_status,
    "service_description"     : "OMD %s performance",
    "has_perfdata"            : True,
    "group"                   : "livestatus_status",
    "default_levels_variable" : "livestatus_status_default_levels",
}
