#!/bin/bash
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
source "$(dirname "$0")/lib/ulib/ulib" || exit 1
urequire DEFAULTS virsh

function display_help() {
    uecho "$scriptname: lancer une machine virtuelle kvm

USAGE
    $scriptname [options] vmName
    $scriptname {-l|-A|-g}

OPTIONS
    -n, --check
        Ne rien faire excepté s'assurer que les modules kvm sont chargés
    -u, --user
        Lancer l'opération avec les droits de l'utilisateur courant. Par défaut,
        ce script tente d'acquérir les droits de root.
    -l, --list
        Lister les machines virtuelles
    -s, --start
        Démarrer la machine virtuelle (par défaut)
        Si le nom de la machine virtuelle n'est pas spécifiée, un menu est
        affiché
    -k, --stop
        Arrêter la machine virtuelle
    -H, --destroy
        Arrêter sauvagement la machine virtuelle
    -r, --restart
        Redémarrer la machine virtuelle
    -S, --managed-save
        Enregistrer l'état de la machine virtuelle
    -A, --stop-all
        Arrêter toutes les machines virtuelles qui tournent actuellement
    -g, --gui
        Afficher le gestionnaire de machines virtuelle"
}

function build_arrays() {
    # Construire les listes avms, rvms, svms
    # rvms: les vms qui tournent
    # avms: toutes les vms
    # svms: les vms qui sont arrêtées
    rvms=()
    eval "$(virsh_list | awk '{print $2}' | csort | sed 's/^/array_add rvms /g')"
    avms=()
    eval "$(virsh_list --all | awk '{print $2}' | csort | sed 's/^/array_add avms /g')"
    svms=()
    for avm in "${avms[@]}"; do
        array_contains rvms "$avm" || array_add svms "$avm"
    done
}

function is_numeric() {
    [ -n "$1" -a -z "${1//[0-9]/}" ]
}

function select_vm() {
    # Afficher un menu pour sélectionner la machine virtuelle
    simple_menu "${2:-vm}" "${1:-avms}" \
        -t "Machines virtuelles" \
        -m "${3:-Choisissez la VM}"
}

function start_virtmanager() {
    # Lancer le gestionnaire de machines virtuelles
    # Les mesures prises le sont pour compatibilité avec Fedora, si la commande
    # est lancée depuis le menu. En effet, toutes les processus fils sont tués
    # s'ils ne sont pas détachés avant la fin de la commande du menu. Le délai
    # est donc pour laisser le temps à virt-manager de s'initialiser.
    nohup >/dev/null 2>&1 virt-manager &
    sleep 3
}

sudo=1
action=start
stopaction=shutdown
parse_opts + "${PRETTYOPTS[@]}" \
    --help '$exit_with display_help' \
    -u,--user sudo= \
    -n,--check action=nop \
    -l,--list action=list \
    -s,--start action=start \
    -k,-t,--stop '$action=stop; stopaction=shutdown' \
    -H,--destroy '$action=stop; stopaction=destroy' \
    -r,--restart '$action=stop; stopaction=reboot' \
    -S,--managedsave,--managed-save '$action=stop; stopaction=managedsave' \
    -A,--stopall,--stop-all action=stopall \
    -g,--gui action=gui \
    @ args -- "$@" && set -- "${args[@]}" || die "$args"

if ! is_root && [ -n "$sudo" ]; then
    # reconstruire la ligne de commande
    case "$action" in
    nop) opt=-n;;
    list) opt=-l;;
    start) opt=-s;;
    stop)
        case "$stopaction" in
        shutdown) opt=-k;;
        destroy) opt=-H;;
        reboot) opt=-r;;
        managedsave) opt=-S;;
        *) opt=-k;;
        esac
        ;;
    stopall) opt=--stopall;;
    gui) opt=-g;;
    esac
    run_as_root "$opt" "$@"
fi

"$scriptdir/EnsureVM" kvm || die
[ "$action" == "nop" ] && exit 0

build_arrays

vm="$1"; shift
if [ -n "$vm" ]; then
    if ! array_contains avms "$vm" && is_numeric "$vm"; then
        vm=$(($vm - 1))
        vm="${avms[$vm]}"
        enote "Sélection de la VM $vm"
    fi
fi

if [ "$action" == list ]; then
    for avm in "${avms[@]}"; do
        if array_contains rvms "$avm"; then
            avm="$(get_color @ g)$avm [running]$(get_color z)"
        fi
        echo "$avm$state"
    done

elif [ "$action" == start ]; then
    if [ -z "$vm" -a -n "${svms[*]}" ]; then
        [ -n "${rvms[*]}" ] &&
        einfo "Les machines virtuelles suivantes sont déjà démarrées:
$(array_join rvms "
" "" "    ")" #"
        select_vm svms vm "Choisissez la VM à démarrer"
    fi

    if [ -n "$vm" ]; then
        virsh start "$vm" "$@"
    else
        ewarn "Aucune VM à démarrer n'a été trouvée"
    fi

elif [ "$action" == stop ]; then
    if [ -z "$vm" -a "${rvms[*]}" ]; then
        select_vm rvms vm "Choisissez la VM à arrêter avec la méthode $stopaction"
    fi

    if [ -n "$vm" ]; then
        virsh "$stopaction" "$vm"
    fi

elif [ "$action" == stopall ]; then
    # Arrêter toutes les machines virtuelles. Au bout de 10 minutes maximum,
    # forcer l'arrêt de toutes celles qui restent
    estep "Arrêt de toutes les machines virtuelles"
    for vm in "${rvms[@]}"; do
        virsh shutdown "$vm"
    done

    # laisser 10 secondes pour l'arrêt initial
    estep "Attente de l'arrêt des machines..."
    sleep 10

    # Puis attendre au maximum 10 minutes pour l'arrêt de toutes les machines
    max=10
    all_stopped=
    while [ $max -gt 0 ]; do
        build_arrays
        if [ -z "${rvms[*]}" ]; then
            all_stopped=1
            break
        else
            einfo "Il y a encore ${#rvms[*]} machine(s) en fonctionnement. Attente de $max minute(s)..."
            sleep 60
            max=$(($max - 1))
        fi
    done

    # Puis forcer l'arrêt des machines
    if [ -z "$all_stopped" ]; then
        build_arrays
        eattention "Forçage de l'arrêt des machines ${rvms[*]}"
        for vm in "${rvms[@]}"; do
            virsh destroy "$vm"
        done
    fi

elif [ "$action" == gui ]; then
    start_virtmanager
fi
