#!/usr/bin/env python3
# -*- coding: utf-8; py-indent-offset: 4 -*-
#
# Author:  Linuxfabrik GmbH, Zurich, Switzerland
# Contact: info (at) linuxfabrik (dot) ch
#          https://www.linuxfabrik.ch/
# License: The Unlicense, see LICENSE file.

# https://github.com/Linuxfabrik/monitoring-plugins/blob/main/CONTRIBUTING.md

"""See the check's README for more details.
"""

import argparse  # pylint: disable=C0413
import os  # pylint: disable=C0413
import sys  # pylint: disable=C0413

import lib.base  # pylint: disable=C0413
import lib.human  # pylint: disable=C0413
import lib.time  # pylint: disable=C0413
from lib.globals import (STATE_CRIT, STATE_OK,  # pylint: disable=C0413
                          STATE_UNKNOWN, STATE_WARN)

__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland'
__version__ = '2024031401'

DESCRIPTION = 'Checks the date and return code of the last borgbackup, according to the logfile.'

DEFAULT_CRIT = None
DEFAULT_WARN = 24


def parse_args():
    """Parse command line arguments using argparse.
    """
    parser = argparse.ArgumentParser(description=DESCRIPTION)

    parser.add_argument(
        '-V', '--version',
        action='version',
        version='{0}: v{1} by {2}'.format('%(prog)s', __version__, __author__)
    )

    parser.add_argument(
        '-c', '--critical',
        help='Set the critical threshold for the time difference to the start of the '
             'last backup (in hours). '
             'Default: %(default)s',
        dest='CRIT',
        type=int,
        default=DEFAULT_CRIT,
    )

    parser.add_argument(
        '-w', '--warning',
        help='Set the warning threshold for the time difference to the start of the '
             'last backup (in hours). '
             'Default: %(default)s',
        dest='WARN',
        type=int,
        default=DEFAULT_WARN,
    )

    return parser.parse_args()


def main():
    """The main function. Hier spielt die Musik.
    """

    # parse the command line, exit with UNKNOWN if it fails
    try:
        args = parse_args()
    except SystemExit:
        sys.exit(STATE_UNKNOWN)

    perfdata = ''
    path = '/var/log/borg/borg.log'

    # content of the log file:
        # start: 2020-04-08 23:00:01
        # prune_retc: 0
        # create_retc: 0
        # end: 2020-04-08 23:00:13

    if os.path.exists(path) <= 0 and not os.path.isfile(path):
        lib.base.cu('Logfile {} not found or empty.'.format(path))

    mount_lines = ''
    with open('/proc/mounts') as mountlist:
        for line in mountlist:
            if 'borgfs' in line:
                mount_lines += '* ' + line

    if mount_lines:
        lib.base.oao('There are active borg mounts.\n\n{}'.format(mount_lines), STATE_WARN)


    logfile = open(path, 'r')
    for line in logfile:
        if line.startswith('start'):
            starttime = line.split(": ")[1].strip()

        if line.startswith('end'):
            endtime = line.split(": ")[1].strip()

        if line.startswith('create_retc'):
            create_retc = int(line.split(": ")[1])

        if line.startswith('prune_retc'):
            prune_retc = int(line.split(": ")[1])

    # check if all variables are defined (looks a little bit weird, pylint complains:
    # Statement seems to have no effect (pointless-statement) ;-)
    try:
        starttime
        endtime
        create_retc
        prune_retc
    except UnboundLocalError:
        lib.base.cu('Could not find all expected values in the logfile.')

    # We ignore retc 1, as it means operation reached its normal end, but there were warnings from borg.
    state = STATE_OK
    create_retc_state = lib.base.get_state(create_retc, 2, None, _operator='ge')
    state = lib.base.get_worst(state, create_retc_state)
    perfdata += lib.base.get_perfdata('create_retc', create_retc, None, 1, 2, 0, None)

    prune_retc_state = lib.base.get_state(prune_retc, 2, None, _operator='ge')
    state = lib.base.get_worst(state, prune_retc_state)
    perfdata += lib.base.get_perfdata('prune_retc', prune_retc, None, 1, 2, 0, None)

    now = lib.time.now(as_type='iso')
    delta = lib.time.timestrdiff(now, starttime)

    last_starttime_state = lib.base.get_state(delta, args.WARN * 60 * 60 if args.WARN is not None else None, args.CRIT * 60 * 60 if args.CRIT is not None else None)
    state = lib.base.get_worst(state, last_starttime_state)

    duration = lib.time.timestrdiff(endtime, starttime)     # in seconds
    perfdata += lib.base.get_perfdata('duration', duration, 's', None, None, 0, None)

    msg = 'Last Backup started {}, ended {}, took {}.\n'.format(starttime, endtime, lib.human.seconds2human(duration))
    if state != STATE_OK:
        if last_starttime_state != STATE_OK:
            msg = 'Last backup is too long ago. ' + msg
        else:
            msg = 'One or more errors. ' + msg
    msg += '* Create retc: {}, State: {}\n'.format(create_retc, lib.base.state2str(create_retc_state))
    msg += '* Prune retc: {}, State: {}'.format(prune_retc, lib.base.state2str(prune_retc_state))

    # over and out
    lib.base.oao(msg, state, perfdata)


if __name__ == '__main__':
    try:
        main()
    except Exception:   # pylint: disable=W0703
        lib.base.cu()
