#!/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
import json
import sys

import lib.args
import lib.base
import lib.huawei
import lib.human
import lib.lftest
import lib.txt
from lib.globals import STATE_CRIT, STATE_OK, STATE_UNKNOWN, STATE_WARN

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

DESCRIPTION = """Checks overall system health, capacity, and performance of a Huawei OceanStor Dorado
storage system via the REST API (/system endpoint). Reports health status, running
status, storage capacity, and I/O performance metrics.
Alerts when the system reports a non-normal health or running state."""

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=f'%(prog)s: v{__version__} by {__author__}',
    )

    parser.add_argument(
        '--always-ok',
        help=lib.args.help('--always-ok'),
        dest='ALWAYS_OK',
        action='store_true',
        default=False,
    )

    parser.add_argument(
        '--cache-expire',
        help=lib.args.help('--cache-expire') + ' Default: %(default)s',
        dest='CACHE_EXPIRE',
        type=int,
        default=DEFAULT_CACHE_EXPIRE,
    )

    parser.add_argument(
        '-c',
        '--critical',
        help=lib.args.help('--critical') + ' 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=lib.args.help('--insecure'),
        dest='INSECURE',
        action='store_true',
        default=DEFAULT_INSECURE,
    )

    parser.add_argument(
        '--no-proxy',
        help=lib.args.help('--no-proxy'),
        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=lib.args.help('--test'),
        dest='TEST',
        type=lib.args.csv,
    )

    parser.add_argument(
        '--timeout',
        help=lib.args.help('--timeout') + ' 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=lib.args.help('--warning') + ' Default: >= %(default)s',
        dest='WARN',
        type=int,
        default=DEFAULT_WARN,
    )

    args, _ = parser.parse_known_args()
    return args


def main():
    """The main function. This is where the magic happens."""

    # parse the command line
    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(f'Got no valuable response from {args.URL}.')
    if result.get('error').get('code') != 0:
        lib.base.oao(
            f'{result.get("error").get("description")}'
            f' {result.get("error").get("suggestion")}',
            STATE_UNKNOWN,
        )

    # init some vars
    msg = ''
    state = STATE_OK
    perfdata = ''
    data = result.get('data')

    # analyze 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
    health_status = lib.huawei.get_health_status(
        data.get('HEALTHSTATUS'),
    )
    health_str = lib.base.state2str(
        health_state,
        prefix=' ',
        empty_ok=True,
    )
    running_status = lib.huawei.get_running_status(
        data.get('RUNNINGSTATUS'),
    )
    running_str = lib.base.state2str(
        running_state,
        prefix=' ',
        empty_ok=True,
    )
    msg += (
        f'{data.get("productModeString")}'
        f' {data.get("pointRelease")},'
        f' UUID: {lib.huawei.get_uuid(data)},'
        f' Name: {data.get("NAME")},'
        f' Location: {data.get("LOCATION")},'
        f' Health Status: {health_status}{health_str},'
        f' Running Status: {running_status}{running_str}\n'
    )
    used_cap = lib.human.number2human(data.get('USEDCAPACITY'))
    total_cap = lib.human.number2human(data.get('TOTALCAPACITY'))
    capa_str = lib.base.state2str(capa_state, prefix=' ')
    sp_used_cap = lib.human.number2human(
        data.get('STORAGEPOOLUSEDCAPACITY'),
    )
    sp_total_cap = lib.human.number2human(
        data.get('STORAGEPOOLCAPACITY'),
    )
    sp_str = lib.base.state2str(sp_state, prefix=' ')
    msg += (
        f'Sectors: Total {capa_used}% used'
        f' ({used_cap}/{total_cap}){capa_str},'
        f' Storage Pool {sp_used}% used'
        f' ({sp_used_cap}/{sp_total_cap}){sp_str}\n'
    )
    counter = result.get('counter', 0)
    msg += f'\nFetched API {counter} {lib.txt.pluralize("time", counter)}'

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

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

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


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