#!/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.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 = """Query basic status and performance data about a Huawei OceanStor Dorado storage
                 system via the REST Interface, using the ``/system/`` endpoint."""

DEFAULT_CACHE_EXPIRE = 15 # minutes; default session timeout period is 20 minutes
DEFAULT_CRIT = 95
DEFAULT_INSECURE = True
DEFAULT_NO_PROXY = False
DEFAULT_SCOPE = 0
DEFAULT_TIMEOUT  = 3
DEFAULT_WARN = 90


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(
        '-c', '--critical',
        help='Set the CRIT threshold as a percentage. '
             'Default: >= %(default)s',
        dest='CRIT',
        type=int,
        default=DEFAULT_CRIT,
    )

    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,
    )

    parser.add_argument(
        '-w', '--warning',
        help='Set the WARN threshold as a percentage. '
             '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)

    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:
        # Do not miss the last slash (/) at the end of the URL.
        result = lib.huawei.get_data('system/', 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 = ''
    data = result.get('data')

    # analyze the data
    health_state = STATE_OK
    if lib.huawei.get_health_status(data.get('HEALTHSTATUS')) != 'Normal (1)':
        health_state = STATE_CRIT
        state = lib.base.get_worst(state, health_state)

    running_state = STATE_OK
    if lib.huawei.get_running_status(data.get('RUNNINGSTATUS')) != 'Normal (1)':
        running_state = STATE_WARN
        state = lib.base.get_worst(state, running_state)

    sp_used = round(float(data.get('STORAGEPOOLUSEDCAPACITY')) / float(data.get('STORAGEPOOLCAPACITY')) * 100)
    sp_state = lib.base.get_state(sp_used, args.WARN, args.CRIT)
    state = lib.base.get_worst(state, sp_state)

    capa_used = round(float(data.get('USEDCAPACITY')) / float(data.get('TOTALCAPACITY')) * 100)
    capa_state = lib.base.get_state(capa_used, args.WARN, args.CRIT)
    state = lib.base.get_worst(state, capa_state)

    # build the message
    msg += '{} {}, UUID: {}, Name: {}, Location: {}, Health Status: {}{}, Running Status: {}{}\n'.format(
        data.get('productModeString'),
        data.get('pointRelease'),
        lib.huawei.get_uuid(data),
        data.get('NAME'),
        data.get('LOCATION'),
        lib.huawei.get_health_status(data.get('HEALTHSTATUS')),
        lib.base.state2str(health_state, prefix=' ', empty_ok=True),
        lib.huawei.get_running_status(data.get('RUNNINGSTATUS')),
        lib.base.state2str(running_state, prefix=' ', empty_ok=True),
    )
    msg += 'Sectors: Total {}% used ({}/{}){}, Storage Pool {}% used ({}/{}){}\n'.format(
        capa_used,
        lib.human.number2human(data.get('USEDCAPACITY')),
        lib.human.number2human(data.get('TOTALCAPACITY')),
        lib.base.state2str(capa_state, prefix=' '),
        sp_used,
        lib.human.number2human(data.get('STORAGEPOOLUSEDCAPACITY')),
        lib.human.number2human(data.get('STORAGEPOOLCAPACITY')),
        lib.base.state2str(sp_state, prefix=' '),
    )
    msg += '\nFetched API {} {}'.format(
        result.get('counter', 0),
        lib.txt.pluralize('time', result.get('counter', 0),),
    )

    perfdata += lib.base.get_perfdata('sectors-capacity-percent', capa_used, '%', args.WARN, args.CRIT, 0, 100)
    perfdata += lib.base.get_perfdata('sectors-storagepool-percent', sp_used, '%', args.WARN, args.CRIT, 0, 100)

    perfdata += lib.base.get_perfdata('HEALTHSTATUS', data.get('HEALTHSTATUS'), None, None, 2, 0, 2)
    perfdata += lib.base.get_perfdata('RUNNINGSTATUS', data.get('RUNNINGSTATUS'), None, None, None, 0, None)
    perfdata += lib.base.get_perfdata('FREEDISKSCAPACITY', data.get('FREEDISKSCAPACITY'), None, None, None, 0, data.get('TOTALCAPACITY'))
    perfdata += lib.base.get_perfdata('HOTSPAREDISKSCAPACITY', data.get('HOTSPAREDISKSCAPACITY'), None, None, None, 0, data.get('TOTALCAPACITY'))
    perfdata += lib.base.get_perfdata('UNAVAILABLEDISKSCAPACITY', data.get('UNAVAILABLEDISKSCAPACITY'), None, None, None, 0, data.get('TOTALCAPACITY'))
    perfdata += lib.base.get_perfdata('USEDCAPACITY', data.get('USEDCAPACITY'), None, None, None, 0, data.get('TOTALCAPACITY'))
    perfdata += lib.base.get_perfdata('STORAGEPOOLFREECAPACITY', data.get('STORAGEPOOLFREECAPACITY'), None, None, None, 0, data.get('STORAGEPOOLCAPACITY'))
    perfdata += lib.base.get_perfdata('STORAGEPOOLHOSTSPARECAPACITY', data.get('STORAGEPOOLHOSTSPARECAPACITY'), None, None, None, 0, data.get('STORAGEPOOLCAPACITY'))
    perfdata += lib.base.get_perfdata('STORAGEPOOLRAWCAPACITY', data.get('STORAGEPOOLRAWCAPACITY'), None, None, None, 0, None)
    perfdata += lib.base.get_perfdata('STORAGEPOOLUSEDCAPACITY', data.get('STORAGEPOOLUSEDCAPACITY'), None, None, None, 0, data.get('STORAGEPOOLCAPACITY'))
    perfdata += lib.base.get_perfdata('THICKLUNSALLOCATECAPACITY', data.get('THICKLUNSALLOCATECAPACITY'), None, None, None, 0, None)
    perfdata += lib.base.get_perfdata('THICKLUNSUSEDCAPACITY', data.get('THICKLUNSUSEDCAPACITY'), None, None, None, 0, None)
    perfdata += lib.base.get_perfdata('THINLUNSALLOCATECAPACITY', data.get('THINLUNSALLOCATECAPACITY'), None, None, None, 0, data.get('THINLUNSMAXCAPACITY'))
    perfdata += lib.base.get_perfdata('THINLUNSUSEDCAPACITY', data.get('THINLUNSUSEDCAPACITY'), None, None, None, 0, data.get('THINLUNSMAXCAPACITY'))
    perfdata += lib.base.get_perfdata('mappedLunsCountCapacity', data.get('mappedLunsCountCapacity'), None, None, None, 0, None)
    perfdata += lib.base.get_perfdata('unMappedLunsCountCapacity', data.get('unMappedLunsCountCapacity'), None, None, None, 0, None)
    perfdata += lib.base.get_perfdata('userFreeCapacity', data.get('userFreeCapacity'), None, None, None, 0, None)

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