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

# Note: This file is almost identical with ibm_svc_nodestats. We should
# create an include file for sharing common code!

# Example output from agent:
# <<<ibm_svc_nodestats:sep(58)>>>
# 1:BLUBBSVC01:compression_cpu_pc:0:0:140325134931
# 1:BLUBBSVC01:cpu_pc:1:3:140325134526
# 1:BLUBBSVC01:fc_mb:35:530:140325134526
# 1:BLUBBSVC01:fc_io:5985:11194:140325134751
# 1:BLUBBSVC01:sas_mb:0:0:140325134931
# 1:BLUBBSVC01:sas_io:0:0:140325134931
# 1:BLUBBSVC01:iscsi_mb:0:0:140325134931
# 1:BLUBBSVC01:iscsi_io:0:0:140325134931
# 1:BLUBBSVC01:write_cache_pc:0:0:140325134931
# 1:BLUBBSVC01:total_cache_pc:70:77:140325134716
# 1:BLUBBSVC01:vdisk_mb:1:246:140325134526
# 1:BLUBBSVC01:vdisk_io:130:1219:140325134501
# 1:BLUBBSVC01:vdisk_ms:0:4:140325134531
# 1:BLUBBSVC01:mdisk_mb:17:274:140325134526
# 1:BLUBBSVC01:mdisk_io:880:1969:140325134526
# 1:BLUBBSVC01:mdisk_ms:1:5:140325134811
# 1:BLUBBSVC01:drive_mb:0:0:140325134931
# 1:BLUBBSVC01:drive_io:0:0:140325134931
# 1:BLUBBSVC01:drive_ms:0:0:140325134931
# 1:BLUBBSVC01:vdisk_r_mb:0:244:140325134526
# 1:BLUBBSVC01:vdisk_r_io:19:1022:140325134501
# 1:BLUBBSVC01:vdisk_r_ms:2:8:140325134756
# 1:BLUBBSVC01:vdisk_w_mb:0:2:140325134701
# 1:BLUBBSVC01:vdisk_w_io:110:210:140325134901
# 1:BLUBBSVC01:vdisk_w_ms:0:0:140325134931
# 1:BLUBBSVC01:mdisk_r_mb:1:265:140325134526
# 1:BLUBBSVC01:mdisk_r_io:15:1081:140325134526
# 1:BLUBBSVC01:mdisk_r_ms:5:23:140325134616
# 1:BLUBBSVC01:mdisk_w_mb:16:132:140325134751
# 1:BLUBBSVC01:mdisk_w_io:865:1662:140325134736
# 1:BLUBBSVC01:mdisk_w_ms:1:5:140325134811
# 1:BLUBBSVC01:drive_r_mb:0:0:140325134931
# 1:BLUBBSVC01:drive_r_io:0:0:140325134931
# 1:BLUBBSVC01:drive_r_ms:0:0:140325134931
# 1:BLUBBSVC01:drive_w_mb:0:0:140325134931
# 1:BLUBBSVC01:drive_w_io:0:0:140325134931
# 1:BLUBBSVC01:drive_w_ms:0:0:140325134931
# 5:BLUBBSVC02:compression_cpu_pc:0:0:140325134930
# 5:BLUBBSVC02:cpu_pc:1:2:140325134905
# 5:BLUBBSVC02:fc_mb:141:293:140325134755
# 5:BLUBBSVC02:fc_io:7469:12230:140325134750
# 5:BLUBBSVC02:sas_mb:0:0:140325134930
# 5:BLUBBSVC02:sas_io:0:0:140325134930
# [...]

# parses agent output into a structure like:
# {'Drives BLUBBSVC01': {'r_mb': 0,   'w_mb': 0,   'r_io': 0,    'w_io': 0,    'r_ms': 0, 'w_ms': 0},
#  'Drives BLUBBSVC02': {'r_mb': 0,   'w_mb': 0,   'r_io': 0,    'w_io': 0,    'r_ms': 0, 'w_ms': 0},
#  'Drives BLUBBSVC03': {'r_mb': 0,   'w_mb': 0,   'r_io': 0,    'w_io': 0,    'r_ms': 0, 'w_ms': 0},
#  'Drives BLUBBSVC04': {'r_mb': 0,   'w_mb': 0,   'r_io': 0,    'w_io': 0,    'r_ms': 0, 'w_ms': 0},
#  'MDisks BLUBBSVC01': {'r_mb': 1,   'w_mb': 16,  'r_io': 15,   'w_io': 865,  'r_ms': 5, 'w_ms': 1},
#  'MDisks BLUBBSVC02': {'r_mb': 3,   'w_mb': 6,   'r_io': 245,  'w_io': 361,  'r_ms': 6, 'w_ms': 0},
#  'MDisks BLUBBSVC03': {'r_mb': 28,  'w_mb': 5,   'r_io': 1194, 'w_io': 901,  'r_ms': 3, 'w_ms': 0},
#  'MDisks BLUBBSVC04': {'r_mb': 0,   'w_mb': 162, 'r_io': 0,    'w_io': 1414, 'r_ms': 7, 'w_ms': 0},
#  'VDisks BLUBBSVC01': {'r_mb': 0,   'w_mb': 0,   'r_io': 19,   'w_io': 110,  'r_ms': 2, 'w_ms': 0},
#  'VDisks BLUBBSVC02': {'r_mb': 101, 'w_mb': 13,  'r_io': 1105, 'w_io': 789,  'r_ms': 1, 'w_ms': 0},
#  'VDisks BLUBBSVC03': {'r_mb': 12,  'w_mb': 80,  'r_io': 1345, 'w_io': 1442, 'r_ms': 1, 'w_ms': 0},
#  'VDisks BLUBBSVC04': {'r_mb': 0,   'w_mb': 0,   'r_io': 0,    'w_io': 0,    'r_ms': 7, 'w_ms': 0}}

def ibm_svc_nodestats_parse(info):
    parsed = {}
    for node_id, node_name, stat_name, stat_current, stat_peak, stat_peak_time in info:
        if stat_name in ("vdisk_r_mb", "vdisk_w_mb", "vdisk_r_io", "vdisk_w_io", "vdisk_r_ms", "vdisk_w_ms"):
            if "VDisks %s" % node_name not in parsed.keys():
                parsed["VDisks %s" % node_name] = {}
            stat_name = stat_name.replace("vdisk_", "")
            parsed["VDisks %s" % node_name][stat_name] = int(stat_current)
        if stat_name in ("mdisk_r_mb", "mdisk_w_mb", "mdisk_r_io", "mdisk_w_io", "mdisk_r_ms", "mdisk_w_ms"):
            if "MDisks %s" % node_name not in parsed.keys():
                parsed["MDisks %s" % node_name] = {}
            stat_name = stat_name.replace("mdisk_", "")
            parsed["MDisks %s" % node_name][stat_name] = int(stat_current)
        if stat_name in ("drive_r_mb", "drive_w_mb", "drive_r_io", "drive_w_io", "drive_r_ms", "drive_w_ms"):
            if "Drives %s" % node_name not in parsed.keys():
                parsed["Drives %s" % node_name] = {}
            stat_name = stat_name.replace("drive_", "")
            parsed["Drives %s" % node_name][stat_name] = int(stat_current)
    return parsed

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

def inventory_ibm_svc_nodestats_diskio(info):
    inventory = []
    parsed = ibm_svc_nodestats_parse(info)
    for key in parsed.keys():
        inventory.append( (key, None) )
    return inventory

def check_ibm_svc_nodestats_diskio(item, _no_params, info):
    parsed = ibm_svc_nodestats_parse(info)

    if item not in parsed.keys():
        return 3, "%s not found in agent output" % item

    read_bytes = parsed[item]['r_mb'] * 1024 * 1024
    write_bytes = parsed[item]['w_mb'] * 1024 * 1024
    perfdata = [ ("read", read_bytes), ("write", write_bytes) ]

    return 0, "%s/s read, %s/s write" % \
        (get_bytes_human_readable(read_bytes), get_bytes_human_readable(write_bytes)), \
        perfdata

check_info["ibm_svc_nodestats.diskio"] = {
    "check_function"        : check_ibm_svc_nodestats_diskio,
    "inventory_function"    : inventory_ibm_svc_nodestats_diskio,
    "service_description"   : "Disk IO %s",
    "has_perfdata"          : True,
}

#.
#   .--iops----------------------------------------------------------------.
#   |                          _                                           |
#   |                         (_) ___  _ __  ___                           |
#   |                         | |/ _ \| '_ \/ __|                          |
#   |                         | | (_) | |_) \__ \                          |
#   |                         |_|\___/| .__/|___/                          |
#   |                                 |_|                                  |
#   '----------------------------------------------------------------------'

def inventory_ibm_svc_nodestats_iops(info):
    inventory = []
    parsed = ibm_svc_nodestats_parse(info)
    for key in parsed.keys():
        inventory.append( (key, None) )
    return inventory

def check_ibm_svc_nodestats_iops(item, _no_params, info):
    parsed = ibm_svc_nodestats_parse(info)

    if item not in parsed.keys():
        return 3, "%s not found in agent output" % item

    read_iops = parsed[item]['r_io']
    write_iops = parsed[item]['w_io']
    perfdata = [ ("read", read_iops), ("write", write_iops) ]

    return 0, "%s IO/s read, %s IO/s write" %  (read_iops, write_iops), perfdata

check_info["ibm_svc_nodestats.iops"] = {
    "check_function"        : check_ibm_svc_nodestats_iops,
    "inventory_function"    : inventory_ibm_svc_nodestats_iops,
    "service_description"   : "Disk IOPS %s",
    "has_perfdata"          : True,
}

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

def inventory_ibm_svc_nodestats_disk_latency(info):
    inventory = []
    parsed = ibm_svc_nodestats_parse(info)
    for key in parsed.keys():
        inventory.append( (key, None) )
    return inventory

def check_ibm_svc_nodestats_disk_latency(item, _no_params, info):
    parsed = ibm_svc_nodestats_parse(info)

    if item not in parsed.keys():
        return 3, "%s not found in agent output" % item

    read_latency  = parsed[item]['r_ms']
    write_latency = parsed[item]['w_ms']
    perfdata = [ ("read_latency", read_latency), ("write_latency", write_latency) ]

    return 0, "Latency is %s ms for read, %s ms for write" % (read_latency, write_latency), \
        perfdata

check_info["ibm_svc_nodestats.disk_latency"] = {
    "check_function"        : check_ibm_svc_nodestats_disk_latency,
    "inventory_function"    : inventory_ibm_svc_nodestats_disk_latency,
    "service_description"   : "Disk Latency %s",
    "has_perfdata"          : True,
}

#.
#   .--cpu-----------------------------------------------------------------.
#   |                                                                      |
#   |                           ___ _ __  _   _                            |
#   |                          / __| '_ \| | | |                           |
#   |                         | (__| |_) | |_| |                           |
#   |                          \___| .__/ \__,_|                           |
#   |                              |_|                                     |
#   |                                                                      |
#   '----------------------------------------------------------------------'

ibm_svc_cpu_default_levels = ( 90.0, 95.0 )

def inventory_ibm_svc_cpu(info):
    inventory = []
    for node_id, node_name, stat_name, stat_current, stat_peak, stat_peak_time in info:
        if stat_name == "cpu_pc":
            inventory.append( (node_name, "ibm_svc_cpu_default_levels") )
    return inventory

def check_ibm_svc_cpu(item, params, info):
    for node_id, node_name, stat_name, stat_current, stat_peak, stat_peak_time in info:
        if node_name == item and stat_name == "cpu_pc":
            return check_cpu_util(int(stat_current), params)

    return 3, "value cpu_pc not found in agent output for node %s" % item

check_info["ibm_svc_nodestats.cpu_util"] = {
    "check_function"        : check_ibm_svc_cpu,
    "inventory_function"    : inventory_ibm_svc_cpu,
    "service_description"   : "CPU utilization %s",
    "has_perfdata"          : True,
    "group"                 : "cpu_utilization_multiitem",
    "includes"              : [ "cpu_util.include" ],
}
#.
#   .--cache---------------------------------------------------------------.
#   |                                     _                                |
#   |                       ___ __ _  ___| |__   ___                       |
#   |                      / __/ _` |/ __| '_ \ / _ \                      |
#   |                     | (_| (_| | (__| | | |  __/                      |
#   |                      \___\__,_|\___|_| |_|\___|                      |
#   |                                                                      |
#   '----------------------------------------------------------------------'

# parses agent output into a structure like:
# {'BLUBBSVC01': {'total_cache_pc': 70, 'write_cache_pc': 0},
#  'BLUBBSVC02': {'total_cache_pc': 75, 'write_cache_pc': 0},
#  'BLUBBSVC03': {'total_cache_pc': 65, 'write_cache_pc': 0},
#  'BLUBBSVC04': {'total_cache_pc': 71, 'write_cache_pc': 0}}

def ibm_svc_cache_parse(info):
    parsed = {}
    for node_id, node_name, stat_name, stat_current, stat_peak, stat_peak_time in info:
        if stat_name in ("write_cache_pc", "total_cache_pc"):
            if node_name not in parsed.keys():
                parsed[node_name] = {}
            parsed[node_name][stat_name] = int(stat_current)
    return parsed

def inventory_ibm_svc_cache(info):
    inventory = []
    parsed = ibm_svc_cache_parse(info)
    for key in parsed.keys():
        inventory.append( (key, None) )
    return inventory

def check_ibm_svc_cache(item, _no_params, info):
    parsed = ibm_svc_cache_parse(info)

    if item not in parsed.keys():
        return 3, "%s not found in agent output" % item

    write_cache_pc = parsed[item]["write_cache_pc"]
    total_cache_pc = parsed[item]["total_cache_pc"]
    perfdata = [ ("write_cache_pc", write_cache_pc, None, None, 0, 100),
                 ("total_cache_pc", total_cache_pc, None, None, 0, 100) ]

    return 0, "Write cache usage is %d %%, total cache usage is %d %%" % \
           (write_cache_pc, total_cache_pc), perfdata

check_info["ibm_svc_nodestats.cache"] = {
    "check_function"        : check_ibm_svc_cache,
    "inventory_function"    : inventory_ibm_svc_cache,
    "service_description"   : "Cache %s",
    "has_perfdata"          : True,
}

#.
