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

import lib.args
import lib.base
import lib.shell
from lib.globals import STATE_CRIT, STATE_OK, STATE_UNKNOWN, STATE_WARN

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

DESCRIPTION = """Lists all virtual machines on a KVM host using "virsh list" and checks their states.
Alerts on VMs that are not in the expected running state. Reports VM name, state,
autostart configuration, and persistent status.
Requires root or sudo."""


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

    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)

    # fetch data
    stdout, stderr, retc = lib.base.coe(
        lib.shell.shell_exec('virsh list --all'),
    )
    if stderr or retc != 0:
        lib.base.oao(f'{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,
    )
    if vm_list:
        for vm in vm_list:
            vm = ' '.join(
                vm.replace('shut off', 'shut_off')
                .replace('in shutdown', 'in_shutdown')
                .split()
            )
            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:

            # build the message
            msg += f'{running} running, '
        if shut_off:
            msg += f'{shut_off} shut_off, '
        if in_shutdown:
            msg += f'{in_shutdown} in_shutdown, '

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

        if crashed:
            msg += f'{crashed} crashed (CRIT), '
            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,
        _min=0,
    )
    perfdata += lib.base.get_perfdata(
        'vm_idle',
        idle,
        _min=0,
    )
    perfdata += lib.base.get_perfdata(
        'vm_paused',
        paused,
        _min=0,
    )
    perfdata += lib.base.get_perfdata(
        'vm_in_shutdown',
        in_shutdown,
        _min=0,
    )
    perfdata += lib.base.get_perfdata(
        'vm_shut_off',
        shut_off,
        _min=0,
    )
    perfdata += lib.base.get_perfdata(
        'vm_crashed',
        crashed,
        _min=0,
    )
    perfdata += lib.base.get_perfdata(
        'vm_pmsuspended',
        pmsuspended,
        _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()
