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

# In cooperation with Thorsten Bruhns from OPITZ Consulting

# <<<oracle_recovery_state:sep(124)>>>
# TUX2|tux2|PRIMARY|MOUNTED|1|1405456155|ONLINE||NO|2719061
# TUX2|tux2|PRIMARY|MOUNTED|2|1405456155|ONLINE||NO|2719061
# new format with backupmode
# <<<oracle_recovery_status:sep(124)>>>
# TUX2|tux2|PRIMARY|READ WRITE|1|1419771465|317|ONLINE|NO|YES|8149107|NOT ACTIVE|489
# TUX2|tux2|PRIMARY|READ WRITE|2|1419771465|317|ONLINE|NO|YES|8149107|NOT ACTIVE|489

# Databases seem to also report lines with some data missing:
# PV|PV|PRIMARY|READ WRITE|397|1433251398|7297|ONLINE|NO|YES|10740614283
# PV|PV|PRIMARY|READ WRITE|398|1433251398|7297|ONLINE|NO|YES|10740614283
# PV|PV|PRIMARY|READ WRITE|399|||ONLINE|||0
# PV|PV|PRIMARY|READ WRITE|400|||ONLINE|||0
# PV|PV|PRIMARY|READ WRITE|401|||ONLINE|||0

def inventory_oracle_recovery_status(info):
    return [ ( line[0], {} ) for line in info ]

def check_oracle_recovery_status(item, params, info):
    state = 0
    offlinecount = 0
    oldest_checkpoint_age = -1

    oldest_backup_age = -1
    backup_count = 0

    perfdata = []

    itemfound = False
    for line in info:
        if line[0] == item:
            itemfound = True

            if len(line) == 11:
                db_name, db_unique_name, database_role, open_mode, filenr, \
                checkpoint_time, checkpoint_age, datafilestatus, recovery, fuzzy, checkpoint_change = line

                backupmode = 'not checked'
                backup_state = 'unknown'

            elif len(line) == 13:
                db_name, db_unique_name, database_role, open_mode, filenr, \
                checkpoint_time, checkpoint_age, datafilestatus, recovery, \
                fuzzy, checkpoint_change, backup_state, backup_age = line

            if params.get("levels"):
                warn, crit = params["levels"]

            if backup_state == 'ACTIVE':
                backup_count += 1
                oldest_backup_age = max(int(backup_age), oldest_backup_age)

            if datafilestatus == 'ONLINE':
                if checkpoint_age:
                    checkpoint_age = int(checkpoint_age)
                    oldest_checkpoint_age = max(oldest_checkpoint_age, checkpoint_age)
            else:
                offlinecount += 1

    if itemfound == True:
        infotext = "%s database" % (database_role.lower())

        if oldest_checkpoint_age == -1:
            infotext += ", no online datafiles found(!!)"
            state = 2
        else:
            infotext += ", oldest Checkpoint %s ago" \
                       % (get_age_human_readable(int(oldest_checkpoint_age)))

        if (database_role == 'PRIMARY' and db_name == '_MGMTDB' and db_unique_name == '_mgmtdb') \
           or not params.get("levels"):
            # We ignore the state of the check when no parameters are known
            # _mgmtdb is new internal instance from 12.1.0.2 on Grid-Infrastructure
            perfdata.append(['checkpoint_age', oldest_checkpoint_age])
        else:
            if database_role == 'PRIMARY':
                # checkpoint age should not higher on primary as well
                # There is no CRIT for older checkoint age as this is mostly not an
                # serios issue.
                # otherwise the standby will produca a warning or crit as well
                if oldest_checkpoint_age >= warn:
                    infotext += '(!)'
                    state = max(1, state)

                perfdata.append(['checkpoint_age', oldest_checkpoint_age, warn])
            else:
                perfdata.append(['checkpoint_age', oldest_checkpoint_age, warn, crit])

                # check the checkpoint age on a non primary database!
                if oldest_checkpoint_age >= crit:
                    infotext += '(!!)'
                    state = 2
                elif oldest_checkpoint_age >= warn:
                    infotext += '(!)'
                    state = max(1, state)

            infotext += ' (levels at %s/%s )' % (get_age_human_readable(warn), get_age_human_readable(crit))

        if offlinecount > 0:
            infotext += " %i datafiles offline(!!)" \
                        % (offlinecount)
            state = 2

        if oldest_backup_age > 0:
            infotext += " %i datafiles in backup mode oldest is %s" % ( \
                         backup_count, get_age_human_readable(oldest_backup_age))

            if params.get("backup_age"):

                warn, crit = params["backup_age"]
                infotext += " levels at (%s/%s)" % (get_age_human_readable(warn), get_age_human_readable(crit))
                perfdata.append(['backup_age', oldest_backup_age, warn, crit])

                if oldest_backup_age >= crit:
                    infotext += '(!!)'
                    state = 2
                elif oldest_backup_age >= warn:
                    infotext += '(!)'
                    state = max(1, state)
            else:
                perfdata.append(['backup_age', oldest_backup_age])
        else:

            # create a 'dummy' performance data with 0
            # => The age from plugin is only valid when a datafile is in backup mode!
            perfdata.append(['backup_age', 0])


        return state, infotext, perfdata

    # In case of missing information we assume that the login into
    # the database has failed and we simply skip this check. It won't
    # switch to UNKNOWN, but will get stale.
    raise MKCounterWrapped("Login into database failed")


check_info['oracle_recovery_status'] = {
    "check_function"          : check_oracle_recovery_status,
    "inventory_function"      : inventory_oracle_recovery_status,
    "service_description"     : "ORA %s Recovery Status",
    "has_perfdata"            : True,
    "group"                   : "oracle_recovery_status",
}
