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

# <<<postgres_stats>>>
# [databases_start]
# postgres
# testdb
# datenbank
# [databases_end]
# datname;sname;tname;vtime;atime
# postgres;pg_catalog;pg_statistic;-1;-1
# postgres;pg_catalog;pg_type;-1;-1
# postgres;pg_catalog;pg_authid;-1;-1
# postgres;pg_catalog;pg_attribute;-1;-1


def inventory_postgres_stats(parsed):
    for db in parsed:
        yield "VACUUM %s"  % db, {}
        yield "ANALYZE %s" % db, {}


def check_postgres_stats(item, params, parsed):
    item_type, database = item.split(" ", 1)

    if database not in parsed:
        # 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")

    if item_type.startswith("VACUUM"):
        stats_field, paramskey, text = "vtime", "vacuum", "vacuumed"
    else:
        stats_field, paramskey, text = "atime", "analyse", "analyzed"

    # namespace,  tablename, last_vacuum,  last_analyze
    # ['public', 'my_table', '1424352356', '1424352356'],
    oldest_element = None
    never_checked  = []
    for line in parsed[database]:
        # Tables with metadata are ignored
        if line["sname"] == "pg_catalog":
            continue

        value = line[stats_field]
        if value == "-1" or value == "":
            never_checked.append(line["tname"])
            continue

        last_time = int(value)
        if not oldest_element or last_time < oldest_element[stats_field]:
            oldest_element = line

    now = time.time()
    if oldest_element:
        oldest_time = int(oldest_element[stats_field])
        warn, crit  = params.get("last_%s" % paramskey, (None, None))
        yield 0, "Table: %s" % oldest_element["tname"]

        state = 0
        if crit and now - crit > oldest_time:
            state = 2
        elif warn and now - warn > oldest_time:
            state = 1

        extra_info = ""
        if state:
            extra_info = " (warn/crit at %s/%s)" % (get_age_human_readable(warn), get_age_human_readable(crit))
        yield state, "Time since last vacuum %s%s" % (get_age_human_readable(now - oldest_time), extra_info)

    key = "postgres_stats.%s" % item
    if not never_checked:
        set_item_state(key, now)
        yield 0, "No never checked tables"

    elif never_checked:
        infotext = "%d tables were never %s: %s%s" % \
                   (len(never_checked), text, "/".join(never_checked[:5]),
                    len(never_checked) > 5 and " (first %d shown)" % min(5, len(never_checked)) or "")

        if "never_analyze_vacuum" in params:
            last_ts = get_item_state(key)
            if last_ts is None:
                set_item_state(key, now)
                yield 0, infotext
                return

            age = now - last_ts
            warn, crit = params["never_analyze_vacuum"]
            state = 0
            if age >= crit:
                state = 2
            elif age >= warn:
                state = 1
            if state:
                infotext += " (warn/crit at %s/%s)" % \
                            (get_age_human_readable(warn),
                             get_age_human_readable(crit),)
            yield state, infotext

        else:
            yield 1, infotext


check_info['postgres_stats'] = {
    "parse_function"          : parse_postgres_dbs,
    "check_function"          : check_postgres_stats,
    "inventory_function"      : inventory_postgres_stats,
    "service_description"     : "PostgreSQL %s",
    "group"                   : "postgres_maintenance",
    "includes"                : ["postgres.include"],
}

