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

factory_settings["postgres_stats_default_levels"] = {
    "never_analyze_vacuum": (0, 1000 * 365 * 24 * 3600),
}


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


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

    count = len(never_checked)
    infotext = "%d tables were never %s: %s%s" % (count, text, "/".join(
        never_checked[:5]), " (first 5 shown)" if count > 5 else "")
    yield 0, infotext

    last_ts = get_item_state(key)
    if last_ts is None:
        set_item_state(key, now)
        return
    yield check_levels(
        now - last_ts,
        None,
        params.get("never_analyze_vacuum"),
        human_readable_func=get_age_human_readable,
        infoname='Unhandled tables for',
    )


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:
        yield 0, "Table: %s" % oldest_element["tname"]
        oldest_age = now - int(oldest_element[stats_field])
        yield check_levels(oldest_age,
                           None,
                           params.get("last_%s" % paramskey),
                           human_readable_func=get_age_human_readable,
                           infoname='Time since last vacuum')

    for subresult in _check_never_checked(item, text, never_checked, params, now):
        yield subresult


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",
    "default_levels_variable": "postgres_stats_default_levels",
    "includes": ["postgres.include"],
}
