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

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

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

DESCRIPTION = """Batch query basic information about HyperMetroPairs of a Huawei OceanStor Dorado
                 storage system via the REST Interface, using the ``/hypermetropair`` endpoint."""

DEFAULT_CACHE_EXPIRE = 15 # minutes; default session timeout period is 20 minutes
DEFAULT_INSECURE = True
DEFAULT_NO_PROXY = False
DEFAULT_SCOPE = 0
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(
        '--cache-expire',
        help='The amount of time after which the credential cache expires, in minutes. '
             'Default: %(default)s',
        dest='CACHE_EXPIRE',
        type=int,
        default=DEFAULT_CACHE_EXPIRE,
    )

    parser.add_argument(
        '--device-id',
        help='Huawei OceanStor Dorado API Device ID.',
        dest='DEVICE_ID',
        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='Huawei OceanStor Dorado API Password.',
        dest='PASSWORD',
        required=True,
    )

    parser.add_argument(
        '--scope',
        help='Huawei OceanStor Dorado API Scope.',
        dest='SCOPE',
        default=DEFAULT_SCOPE,
    )

    parser.add_argument(
        '--test',
        help='For unit tests. Needs "path-to-stdout-file,path-to-stderr-file,expected-retc".',
        dest='TEST',
        type=lib.args.csv,
    )

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

    parser.add_argument(
        '-u', '--url',
        help='Huawei OceanStor Dorado API URL.',
        dest='URL',
        required=True,
    )

    parser.add_argument(
        '--username',
        help='Huawei OceanStor Dorado API Username.',
        dest='USERNAME',
        required=True,
    )

    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)

    if not args.URL.startswith('http'):
        lib.base.cu('--url parameter has to start with "http://" or https://".')

    # fetch data
    if args.TEST is None:
        result = lib.huawei.get_data('hypermetropair', args)
    else:
        # do not call the command, put in test data
        stdout, stderr, retc = lib.lftest.test(args.TEST)
        result = json.loads(stdout)

    # no valuable result?
    if not result:
        lib.base.cu('Got no valuable response from {}.'.format(args.URL))
    if result.get('error').get('code') != 0:
        lib.base.oao('{} {}'.format(
            result.get('error').get('description'),
            result.get('error').get('suggestion'),
        ), STATE_UNKNOWN)

    # init some vars
    msg = ''
    state = STATE_OK
    perfdata = ''

    # analyze the data
    table_data = []
    for hypermetropair in result.get('data'):
        health_state = STATE_OK
        if lib.huawei.get_health_status(hypermetropair.get('HEALTHSTATUS')) != 'Normal (1)':
            health_state = STATE_WARN
            state = lib.base.get_worst(state, health_state)

        running_state = STATE_OK
        if lib.huawei.get_running_status(hypermetropair.get('RUNNINGSTATUS')) != 'Normal (1)' and \
           lib.huawei.get_running_status(hypermetropair.get('RUNNINGSTATUS')) != 'Synchronizing (23)':
            running_state = STATE_WARN
            state = lib.base.get_worst(state, running_state)

        linkstatus_state = STATE_OK
        if hypermetropair.get('LINKSTATUS') != '1':
            linkstatus_state = STATE_WARN
            state = lib.base.get_worst(state, linkstatus_state)

        localdata_state = STATE_OK
        if hypermetropair.get('LOCALDATASTATE') != '1':
            localdata_state = STATE_WARN
            state = lib.base.get_worst(state, localdata_state)

        remotedata_state = STATE_OK
        if hypermetropair.get('REMOTEDATASTATE') != '1':
            remotedata_state = STATE_WARN
            state = lib.base.get_worst(state, remotedata_state)

        hypermetropair['UUID'] = lib.huawei.get_uuid(hypermetropair)
        hypermetropair['sync_duration'] = int(hypermetropair['ENDTIME']) - int(hypermetropair['STARTTIME'])

        perfdata += lib.base.get_perfdata('{}_HEALTHSTATUS'.format(hypermetropair['UUID']), hypermetropair['HEALTHSTATUS'], None, None, 2, 0, 2)
        perfdata += lib.base.get_perfdata('{}_RUNNINGSTATUS'.format(hypermetropair['UUID']), hypermetropair['RUNNINGSTATUS'], None, None, None, 0, None)
        perfdata += lib.base.get_perfdata('{}_LINKSTATUS'.format(hypermetropair['UUID']), hypermetropair['LINKSTATUS'], None, 2, None, 0, 2)
        perfdata += lib.base.get_perfdata('{}_LOCALDATASTATE'.format(hypermetropair['UUID']), hypermetropair['LOCALDATASTATE'], None, 2, None, 0, 2)
        perfdata += lib.base.get_perfdata('{}_LOCALHOSTACCESSSTATE'.format(hypermetropair['UUID']), hypermetropair['LOCALHOSTACCESSSTATE'], None, None, None, 0, 3)
        perfdata += lib.base.get_perfdata('{}_REMOTEDATASTATE'.format(hypermetropair['UUID']), hypermetropair['REMOTEDATASTATE'], None, 2, None, 0, 2)
        perfdata += lib.base.get_perfdata('{}_REMOTEHOSTACCESSSTATE'.format(hypermetropair['UUID']), hypermetropair['REMOTEHOSTACCESSSTATE'], None, None, None, 0, 5)
        perfdata += lib.base.get_perfdata('{}_SYNCPROGRESS'.format(hypermetropair['UUID']), hypermetropair['SYNCPROGRESS'], '%', None, None, 0, 100)

        hypermetropair['health_state'] = lib.base.state2str(health_state, empty_ok=False)
        hypermetropair['running_state'] = lib.base.state2str(running_state, empty_ok=False)
        hypermetropair['sync_duration'] = '{}'.format(
            lib.human.seconds2human(hypermetropair['sync_duration']),
        )
        hypermetropair['sync_last'] = '{} ({} ago)'.format(
            lib.time.epoch2iso(int(hypermetropair['ENDTIME'])),
            lib.human.seconds2human(lib.time.now(as_type='epoch') - int(hypermetropair['ENDTIME'])),
        )
        hypermetropair['LINKSTATUS'] = lib.base.state2str(linkstatus_state, empty_ok=False)
        hypermetropair['LOCALDATASTATE'] = lib.base.state2str(localdata_state, empty_ok=False)
        hypermetropair['LOCALHOSTACCESSSTATE'] = lib.huawei.get_host_access_state(hypermetropair['LOCALHOSTACCESSSTATE'])
        hypermetropair['REMOTEDATASTATE'] = lib.base.state2str(remotedata_state, empty_ok=False)
        hypermetropair['REMOTEHOSTACCESSSTATE'] = lib.huawei.get_host_access_state(hypermetropair['REMOTEHOSTACCESSSTATE'])

        table_data.append(hypermetropair)

    if table_data:
        keys = ['UUID', 'LINKSTATUS', 'sync_last', 'sync_duration', 'SYNCPROGRESS', 'LOCALOBJNAME', 'LOCALDATASTATE', 'LOCALHOSTACCESSSTATE', 'REMOTEOBJNAME', 'REMOTEDATASTATE', 'REMOTEHOSTACCESSSTATE', 'health_state', 'running_state']
        headers = ['UUID', 'Link', 'Last Sync', 'Duration', 'Progr (%)', 'LocalJob', 'DataState', 'Access', 'RemoteJob', 'DataState', 'Access', 'Health', 'Running']
        msg += lib.base.get_table(table_data, keys, header=headers)

    msg += '\nFetched API {} {}'.format(
        result.get('counter', 0),
        lib.txt.pluralize('time', result.get('counter', 0),),
    )

    if state == STATE_CRIT:
        msg = 'There are critical errors.\n\n' + msg
    elif state == STATE_WARN:
        msg = 'There are warnings.\n\n' + msg
    else:
        msg = 'Everything is ok.\n\n' + msg

    # 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()
