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

# Example output from old agent until version 1.2.6
#<<<lnx_quota>>>
#[[[/home]]]
#root      -- 62743228       0       0      0  137561     0     0      0
#proxy     --   288648       0       0      0   14370     0     0      0
#http      --      208       0       0      0      53     0     0      0
#mysql     --  7915856       0       0      0     173     0     0      0

# Example output from new agent since version 1.2.8
#[[[usr:/home]]]
#root      -- 62743228       0       0      0  137561     0     0      0
#proxy     --   288648       0       0      0   14370     0     0      0
#http      --      208       0       0      0      53     0     0      0
#mysql     --  7915856       0       0      0     173     0     0      0
#[[[grp:/home]]]
#root      -- 62743228       0       0      0  137561     0     0      0
#proxy     --   288648       0       0      0   14370     0     0      0
#http      --      208       0       0      0      53     0     0      0
#mysql     --  7915856       0       0      0     173     0     0      0

def parse_lnx_quota(info):
    parsed = {}
    mode = None
    fs = None

    for line in info:
        if line[0].startswith('[[['):
            # new filesystem detected
            parts = line[0][3:-3].split(':')

            # compatible check for old format
            # was changed in version 1.2.8
            if len(parts) == 1:
                mode = 'usr'
                fs = line[0][3:-3]
            elif len(parts) == 2:
                # new format for check data
                mode, fs = parts

            # new filesystem for quota
            parsed.setdefault(fs, {})
            parsed[fs].setdefault(mode, {})

        elif fs and mode and len(line) == 10:
            # new table entry for quota
            parsed[fs][mode][line[0]] = map(int, line[2:])

    return parsed


def lnx_quota_limit_check(mode, what, user, used, soft, hard, grace):
    fmt = lambda value, what: what == 'files' and '%d' % value \
                                or get_bytes_human_readable(value*1000, 1000)

    if mode == 'usr':
        txt = 'User %s' % user
    elif mode == 'grp':
        txt = 'Group %s' % user

    if used > hard:
        # check, if hard limit is exceeded
        state = 2
        if what == 'blocks':
            txt += ' exceeded space hard limit %s/%s' % (fmt(used, what), fmt(hard, what))
        elif what == 'files':
            txt += ' exceeded file hard limit %s/%s' % (fmt(used, what), fmt(hard, what))
    elif used > soft:
        # check, if soft limit is exceeded
        state = 1
        if what == 'blocks':
            txt += ' exceeded space soft limit %s/%s' % (fmt(used, what), fmt(soft, what))
        elif what == 'files':
            txt += ' exceeded file soft limit %s/%s' % (fmt(used, what), fmt(soft, what))

        if grace != 0:
            # check, if grace time is specified
            if grace <= time.time():
                # check, if it was in grace time
                state = 2
                txt += ', grace time exceeded'
            else:
                # check, if it is in grace time
                state = 1
                txt += ', within grace time'
    else:
        state = 0
        txt = None
    return state, txt


def inventory_lnx_quota(parsed):
    inv = []

    for item in parsed.keys():
        inv.append((item, { 'user': True }))
    return inv


def check_lnx_quota(item, params, parsed):
    perfdata = []

    if item not in parsed:
        yield 3, 'Quota info not found for this filesystem'

    if not params:
        # old discovery until version 1.2.6
        # params were empty dictionary and enabled by standard user checking
        params = { 'user': True }

    for param_key, perf_prefix, thing, name in [
        ('user',  '',       'usr', 'users'),
        ('group', 'group_', 'grp', 'groups')
       ]:
        if params.get(param_key) == True:
            at_least_one_problematic = False
            for user, values in parsed[item][thing].items():
                for what, (used, soft, hard, grace) in [
                    ('blocks', values[:4]),
                    ('files',  values[4:]) ]:

                    if soft == 0 and hard == 0:
                        continue # skip entries without limits

                    state, txt = lnx_quota_limit_check(thing, what, user, used, soft, hard, grace)

                    perfdata.append(('%s%s_%s' % (perf_prefix, user, what),
                                    used*1000, soft*1000, hard*1000, 0, hard*1000))

                    if txt:
                        at_least_one_problematic = True
                        yield state, (txt + ', '), perfdata
                    else:
                        yield state, None, perfdata

            if not at_least_one_problematic:
                yield 0, 'All %s within quota limits' % name

    if params.get('user') == False and params.get('group') == False:
        yield 0, 'Disabled quota checking'


check_info['lnx_quota'] = {
    'parse_function'          : parse_lnx_quota,
    'check_function'          : check_lnx_quota,
    'inventory_function'      : inventory_lnx_quota,
    'service_description'     : 'Quota %s',
    'has_perfdata'            : True,
    'group'                   : 'lnx_quota',
}
