#!/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 sys  # pylint: disable=C0413
import urllib.parse  # pylint: disable=C0413

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

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

DESCRIPTION = """Returns statistics for members of HA cluster from Forti Appliances like FortiGate
                 running FortiOS via FortiOS REST API. Warns if the number of HA members is more
                 or less than expected (default: 2). The authentication is done via a single API
                 token (Token-based authentication), not via Session-based authentication, which
                 is stated as "legacy"."""

DEFAULT_COUNT = 2
DEFAULT_INSECURE = False
DEFAULT_NO_PROXY = False
DEFAULT_TIMEOUT  = 3


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

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

    parser.add_argument(
        '--always-ok',
        help='Always returns OK.',
        dest='ALWAYS_OK',
        action='store_true',
        default=False,
    )

    parser.add_argument(
        '--count',
        help='Number of expected cluster members. Default: %(default)s',
        dest='COUNT',
        type=int,
        default=DEFAULT_COUNT,
    )

    parser.add_argument(
        '-H', '--hostname',
        help='FortiOS-based Appliance address, optional including port ("192.168.1.1:443").',
        dest='HOSTNAME',
        required=True,
    )

    parser.add_argument(
        '--insecure',
        help='This option explicitly allows to perform "insecure" SSL connections. Default: %(default)s',
        dest='INSECURE',
        action='store_true',
        default=DEFAULT_INSECURE,
    )

    parser.add_argument(
        '--no-proxy',
        help='Do not use a proxy. Default: %(default)s',
        dest='NO_PROXY',
        action='store_true',
        default=DEFAULT_NO_PROXY,
    )

    parser.add_argument(
        '--password',
        help='FortiOS REST API Single Access Token.',
        dest='PASSWORD',
        required=True,
    )

    parser.add_argument(
        '--timeout',
        help='Network timeout in seconds. Default: %(default)s (seconds)',
        dest='TIMEOUT',
        type=int,
        default=DEFAULT_TIMEOUT,
    )

    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)

    # fetch data
    url = 'https://{}/api/v2/monitor/system/ha-statistics/select/?access_token={}'.format(args.HOSTNAME, urllib.parse.quote(args.PASSWORD))
    result = lib.base.coe(lib.url.fetch_json(url, insecure=args.INSECURE, no_proxy=args.NO_PROXY, timeout=args.TIMEOUT))
    member_count = len(result['results'])

    # we expect for example 2 members in our ha cluster
    if member_count != args.COUNT:
        state = STATE_WARN
    else:
        state = STATE_OK

    msg = 'Found {} HA cluster {}{}, which handled {} sessions and {} traffic so far.'.format(
        member_count,
        lib.txt.pluralize('member', member_count),
        lib.base.state2str(state, prefix= ' (', suffix=')'),
        sum(item['sessions'] for item in result['results']),
        lib.human.bytes2human(sum(item['tbyte'] for item in result['results']))
    )

    perfdata = ''
    for sensor in result['results']:
        name = sensor['hostname']
        perfdata += lib.base.get_perfdata('{}_sessions'.format(name), sensor['sessions'], None, None, None, 0, None)
        perfdata += lib.base.get_perfdata('{}_net_usage'.format(name), sensor['net_usage'], '%', None, None, 0, 100)
        perfdata += lib.base.get_perfdata('{}_tbyte'.format(name), sensor['tbyte'], None, None, None, 0, None)
        perfdata += lib.base.get_perfdata('{}_cpu_usage'.format(name), sensor['cpu_usage'], '%', None, None, 0, 100)
        perfdata += lib.base.get_perfdata('{}_mem_usage'.format(name), sensor['mem_usage'], '%', None, None, 0, 100)

    # over and out
    lib.base.oao(msg, state, perfdata, always_ok=args.ALWAYS_OK)


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