#!/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 lib.base  # pylint: disable=C0413
import lib.shell  # pylint: disable=C0413
from lib.globals import (STATE_CRIT, STATE_OK,  # pylint: disable=C0413
                          STATE_UNKNOWN, STATE_WARN)

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

DESCRIPTION = 'Check VMs on a KVM host using "virsh list".'


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(
        '--always-ok',
        help='Always returns OK.',
        dest='ALWAYS_OK',
        action='store_true',
        default=False,
    )

    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)

    # execute the shell command and return its result and exit code
    stdout, stderr, retc = lib.base.coe(
        lib.shell.shell_exec('virsh list --all'),
    )
    if stderr or retc != 0:
        lib.base.oao('{}'.format(stderr), STATE_WARN)
    # we got a VM list and their states - strip first two header and last two empty rows
    vm_list = stdout.strip().split('\n')[2:]

    # init some vars
    perfdata = ''
    state = STATE_OK
    table_data = []

    # count the VM states
    running, idle, paused, in_shutdown, shut_off, crashed, pmsuspended = 0, 0, 0, 0, 0, 0, 0 # pylint: disable=C0301
    if vm_list:
        for vm in vm_list:
            vm = ' '.join(vm.replace('shut off', 'shut_off').replace('in shutdown', 'in_shutdown').split()) # pylint: disable=C0301
            vm_id, vm_name, vm_state = vm.split(' ')
            table_data.append({
                'vm_id': vm_id,
                'vm_name': vm_name,
                'vm_state': vm_state,
            })

            running     += 1 if vm_state == 'running' else 0
            idle        += 1 if vm_state == 'idle' else 0
            paused      += 1 if vm_state == 'paused' else 0
            in_shutdown += 1 if vm_state == 'in_shutdown' else 0
            shut_off    += 1 if vm_state == 'shut_off' else 0
            crashed     += 1 if vm_state == 'crashed' else 0
            pmsuspended += 1 if vm_state == 'pmsuspended' else 0

        msg = 'VMs: '
        if running:
            msg += '{} running, '.format(running)
        if shut_off:
            msg += '{} shut_off, '.format(shut_off)
        if in_shutdown:
            msg += '{} in_shutdown, '.format(in_shutdown)

        if idle:
            msg += '{} idle (WARN), '.format(idle)
            state = lib.base.get_worst(state, STATE_WARN)
        if paused:
            msg += '{} paused (WARN), '.format(paused)
            state = lib.base.get_worst(state, STATE_WARN)
        if pmsuspended:
            msg += '{} pmsuspended (WARN), '.format(pmsuspended)
            state = lib.base.get_worst(state, STATE_WARN)

        if crashed:
            msg += '{} crashed (CRIT), '.format(crashed)
            state = lib.base.get_worst(state, STATE_CRIT)
        msg = msg[:-2]
    else:
        msg = 'No VMs running.'
    msg += '\n\n'

    if table_data:
        msg += lib.base.get_table(
            table_data,
            [
              'vm_id',
              'vm_name',
              'vm_state',
            ],
            header=[
              'ID',
              'VM Name',
              'State',
            ]
        )

    perfdata += lib.base.get_perfdata('vm_running', running, None, None, None, 0, None) # pylint: disable=C0301
    perfdata += lib.base.get_perfdata('vm_idle', idle, None, None, None, 0, None) # pylint: disable=C0301
    perfdata += lib.base.get_perfdata('vm_paused', paused, None, None, None, 0, None) # pylint: disable=C0301
    perfdata += lib.base.get_perfdata('vm_in_shutdown', in_shutdown, None, None, None, 0, None) # pylint: disable=C0301
    perfdata += lib.base.get_perfdata('vm_shut_off', shut_off, None, None, None, 0, None) # pylint: disable=C0301
    perfdata += lib.base.get_perfdata('vm_crashed', crashed, None, None, None, 0, None) # pylint: disable=C0301
    perfdata += lib.base.get_perfdata('vm_pmsuspended', pmsuspended, None, None, None, 0, None) # pylint: disable=C0301

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