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

# <<<veritas_vcs>>>
# ClusState                RUNNING
# ClusterName              c7dbacpt
# #System    Attribute             Value
# ecldbr03   SysState              RUNNING
# ecldbr04   SysState              RUNNING
# #Group         Attribute             System     Value
# ClusterService State                 ecldbr04   |OFFLINE|
# db01sg         State                 ecldbr04   |OFFLINE|
# db02sg         State                 ecldbr04   |OFFLINE|
# db03sg         State                 ecldbr04   |OFFLINE|
# db04sg         State                 ecldbr04   |OFFLINE|
# db05sg         State                 ecldbr04   |OFFLINE|
# net01sg        State                 ecldbr04   |ONLINE|
# #Resource      Attribute             System     Value
# csgnic         State                 ecldbr04   ONLINE
# db01-db        State                 ecldbr04   OFFLINE
# db01-dg        State                 ecldbr04   OFFLINE
# db01-ip        State                 ecldbr04   OFFLINE
# db01-mnt       State                 ecldbr04   OFFLINE
# db01-nic-proxy State                 ecldbr04   ONLINE
# db01-vol       State                 ecldbr04   OFFLINE
# db02-db        State                 ecldbr04   OFFLINE
# db02-dg        State                 ecldbr04   OFFLINE
# db02-ip        State                 ecldbr04   OFFLINE
# db02-mnt       State                 ecldbr04   OFFLINE
# db02-nic-proxy State                 ecldbr04   ONLINE
# db02-vol       State                 ecldbr04   OFFLINE
# db03-db        State                 ecldbr04   OFFLINE
# db03-dg        State                 ecldbr04   OFFLINE
# db03-ip        State                 ecldbr04   OFFLINE
# db03-mnt       State                 ecldbr04   OFFLINE
# db03-nic-proxy State                 ecldbr04   ONLINE
# db03-vol       State                 ecldbr04   OFFLINE
# db04-db        State                 ecldbr04   OFFLINE
# db04-dg        State                 ecldbr04   OFFLINE
# db04-ip        State                 ecldbr04   OFFLINE
# db04-mnt       State                 ecldbr04   OFFLINE
# db04-nic-proxy State                 ecldbr04   ONLINE
# db04-vol       State                 ecldbr04   OFFLINE
# db05-db        State                 ecldbr04   OFFLINE
# db05-dg        State                 ecldbr04   OFFLINE
# db05-ip        State                 ecldbr04   OFFLINE
# db05-mnt       State                 ecldbr04   OFFLINE
# db05-nic-proxy State                 ecldbr04   ONLINE
# db05-vol       State                 ecldbr04   OFFLINE
# net01-nic      State                 ecldbr04   ONLINE
# net01-phantom  State                 ecldbr04   ONLINE
# webip          State                 ecldbr04   OFFLINE

# Possible values for ClusState: RUNNING
# Possible values for SysState: RUNNING, FAULTED, EXITED
# Possible values for SG State: ONLINE, OFFLINE, FAULTED
# Possible values for resource State: ONLINE, OFFLINE, FAULTED, OFFLINE|STATE UNKNOWN, ONLINE|STATE UNKNOWN
# the STATE UNKNOWN is treated as UNKNOWN

# parsed in case of Check_MK cluster definition:
# parsed = {
#    "cluster" : {
#        u'c7dbacpt' : [
#           ('server-1', 'RUNNING', None),
#           ('server-2', 'OFFLINE', None),
#        ]
#   },
#   "resource" : {
#       u'db05-db': [
#           ('server-1', 'ONLINE',  u'c7dbacpt' ),
#           ('server-2', 'OFFLINE', u'c7dbacpt' ),
#       ]
#   }
#   "group": {...},
#   "system": {...},
# }

# parsed in case of single node:
# parsed = {
#    "cluster" : {
#        u'c7dbacpt' : [
#           (None, 'RUNNING', None),
#        ]
#   },


def parse_veritas_vcs(info):
    parsed = {
        "cluster"  : {},
        "resource" : {},
        "group"    : {},
        "system"   : {},
    }

    for line in info:
        node = line[0]

        if line[1] == "ClusState":
            cluster_state = line[2]

        elif line[1] == "ClusterName":
            cluster_name = line[2]
            parsed["cluster"].setdefault(cluster_name, []).append((node, cluster_state, None))

        elif line[1] == "#System":
            section = "system"
            state_index = 3

        elif line[1] == "#Group":
            section = "group"
            state_index = 4

        elif line[1] == "#Resource":
            section = "resource"
            state_index = 4

        else:
            item_state = line[state_index].replace("|","")
            if "UNKNOWN" in item_state:
                item_state = "UNKNOWN"

            if len(line) > 3:
                parsed[section].setdefault(line[1], []).append((node, item_state, cluster_name))

    return parsed



# Handle states
def veritas_vcs_aggregate_states_in_cluster(states):
    if "FAULTED" in states:
        return 2
    elif "UNKNOWN" in states:
        return 3
    elif "OFFLINE" in states and len(set(states)) == 1:
        return 2
    elif "ONLINE" in states or "RUNNING" in states:
        return 0
    else:
        return 1


def inventory_veritas_vcs(parsed, item_type):
    for item_name in parsed[item_type]:
        yield item_name, None


def check_veritas_vcs(item, params, parsed, item_type):
    if item not in parsed[item_type]:
        return # vanished

    states = []
    infotexts = []
    cluster_info = ""
    for node, state_name, cluster_name in parsed[item_type][item]:
        states.append(state_name)

        infotext = state_name.lower()
        if node:
            infotext = "%s: %s" % (node, infotext)
        infotexts.append(infotext)

        if cluster_name:
            cluster_info = ", cluster: %s" % cluster_name

    state_map = {
        "ONLINE"  : 0,
        "RUNNING" : 0,
        "OK"      : 0,
        "OFFLINE" : 1,
        "EXITED"  : 1,
        "PARTIAL" : 1,
        "FAULTED" : 2,
        "UNKNOWN" : 3,
    }

    if len(states) == 1:
        state = state_map[states[0]]
    else:
        state = veritas_vcs_aggregate_states_in_cluster(states)

    return state, "%s%s" % (", ".join(infotexts), cluster_info)



#   .--cluster-------------------------------------------------------------.
#   |                         _           _                                |
#   |                     ___| |_   _ ___| |_ ___ _ __                     |
#   |                    / __| | | | / __| __/ _ \ '__|                    |
#   |                   | (__| | |_| \__ \ ||  __/ |                       |
#   |                    \___|_|\__,_|___/\__\___|_|                       |
#   |                                                                      |
#   +----------------------------------------------------------------------+
#   |                           main check                                 |
#   '----------------------------------------------------------------------'


check_info['veritas_vcs'] = {
    'parse_function'       : parse_veritas_vcs,
    'inventory_function'   : lambda parsed: inventory_veritas_vcs(parsed, 'cluster'),
    'check_function'       : lambda item, params, parsed: \
                                 check_veritas_vcs(item, params, parsed, "cluster"),
    'service_description'  : 'VCS Cluster %s',
    'node_info'            : True,
}

#.
#   .--system--------------------------------------------------------------.
#   |                                 _                                    |
#   |                   ___ _   _ ___| |_ ___ _ __ ___                     |
#   |                  / __| | | / __| __/ _ \ '_ ` _ \                    |
#   |                  \__ \ |_| \__ \ ||  __/ | | | | |                   |
#   |                  |___/\__, |___/\__\___|_| |_| |_|                   |
#   |                       |___/                                          |
#   '----------------------------------------------------------------------'

check_info['veritas_vcs.system'] = {
    'inventory_function'   : lambda parsed: inventory_veritas_vcs(parsed, "system"),
    'check_function'       : lambda item, params, parsed: \
                                 check_veritas_vcs(item, params, parsed, "system"),
    'service_description'  : 'VCS System %s',
    'node_info'            : True,
}

#.
#   .--service group-------------------------------------------------------.
#   |                        _                                             |
#   |    ___  ___ _ ____   _(_) ___ ___    __ _ _ __ ___  _   _ _ __       |
#   |   / __|/ _ \ '__\ \ / / |/ __/ _ \  / _` | '__/ _ \| | | | '_ \      |
#   |   \__ \  __/ |   \ V /| | (_|  __/ | (_| | | | (_) | |_| | |_) |     |
#   |   |___/\___|_|    \_/ |_|\___\___|  \__, |_|  \___/ \__,_| .__/      |
#   |                                     |___/                |_|         |
#   '----------------------------------------------------------------------'

check_info['veritas_vcs.servicegroup'] = {
    'inventory_function'   : lambda parsed: inventory_veritas_vcs(parsed, 'group'),
    'check_function'       : lambda item, params, parsed: \
                                 check_veritas_vcs(item, params, parsed, 'group'),
    'service_description'  : 'VCS Service Group %s',
    'node_info'            : True,
}

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

check_info['veritas_vcs.resource'] = {
    'inventory_function'   : lambda parsed: inventory_veritas_vcs(parsed, 'resource'),
    'check_function'       : lambda item, params, parsed: \
                                 check_veritas_vcs(item, params, parsed, 'resource'),
    'service_description'  : 'VCS Resource %s',
    'node_info'            : True,
}
