Thanks for sharing @mtongnz. Here's my script I guess I'll share as well. This has more special haling built in for 1 GPU/multiple VM configurations to check and shutdown other VMs. In a way I like your simplified approach better but if you need to check for other running VMs you can steal from some of my functions below.
Use at your own risk, I'm not a coder and I don't have much bash scripting experience. Hopefully the experts on this forum can give me some feedback on what I can improve, I would really appreciate that!
Particularly, I'm calling this script from Home-Assistant and the only way I know how to is via SSH as the root user, would prefer a more secure solution if anybody has any suggestions.
Here's the User Script:
#!/bin/bash
# Script for starting stopping VMs via homeassitant
# Takes two arguments, a command (start or stop) and a VM name.
# If a start command issued, the script checks for any running VMs and shuts them down as I have a 1 GPU configuration at home
# Personally, I have this script run at array start up so it's loaded into RAM and can be called from the tmp folder by HASS, or manually
## Script includes a function to check for empty arguments or empty space and exits for the above reason (User Scripts provides an empty space as the first argument for some reason)
comm="$1"
vm_given="$2"
#List OSX VMs for special handling
osx_vm0="MacinaboxHighSierra"
function get_vm_names {
readarray -t vm_list < <(virsh list --all --name)
unset vm_list[-1]
}
function get_vm_state {
state=$(virsh domstate "$1")
}
# This function is not currently invoked, but can be usedful for debugging
function get_vm_info {
info=$(virsh dominfo "$1")
echo -e "$info \n\n"
}
function check_vm_name {
get_vm_names
for vm in "${vm_list[@]}"
do
if [[ "$vm" = "$vm_given" ]]; then
echo "$vm_given is a valid VM name, proceding"
return 1
else
:
fi
done
echo "$vm_given is not a valid VM name, go home"
exit
}
## Haven't finished writting this part yet, script will just exit at this point for OSX
## Reason for special handling is OSX doesn't shutdown when asked to by qemu
function check_if_OSX {
if [[ "$vm_given" == "$osx_vm0" ]] || [[ "$vm_given" == "$osx_vm1" ]] || [[ "$vm_given" == "$osx_vm2" ]]; then
echo "VM is one of listed OSX VMs, initiating special handling"
exit
else
return 1
fi
}
function start_vm {
echo "Starting $vm_given"
virsh start "$vm_given"
}
function shut_down_vm {
echo -e "Sending Shutdown signal to $vm"
virsh shutdown "$vm"
get_vm_state "$vm"
while [ "$state" != "shut off" ]; do
vm_down_poll "$vm"
done
}
function vm_down_poll {
get_vm_state "$vm"
echo "$vm is still running"
sleep 1
}
function loop_vms_for_shutdown {
for vm in "${vm_list[@]}"
do
get_vm_state "$vm"
if [ "$state" == "shut off" ]
then
echo -e "$vm is $state"
else
echo -e "$vm is $state, initiaing shutdown"
shut_down_vm "$vm"
fi
#Leaving this here for de-bugging purposes if needed
#get_vm_info "$vm"
done
}
## Checking if arguments were supplied, otherwise exit (or shuttdown all VMs if the flag is enabled to do so)
## Arguments will be provided by HASS automation (or you can manually invoke this via command line).
## Example of how to call this script from the terminal: /tmp/user.scripts/tmpScripts/00_start_stop_VMs/script start "Ubuntu"
if [[ $# -eq 0 ]] || [[ "$1" == "" ]]; then
if [[ shutdown_all == "enabled" ]]; then echo "No arguments supplied, shutting down all running VMs"; loop_vms_for_shutdown; else echo "No arguments provided"; fi
elif [[ "$1" == "start" ]]; then
echo "Starting $2 VM, shutting down other running VMs first"
check_vm_name "$2"
loop_vms_for_shutdown
sleep 5
start_vm
elif [[ "$1" == "stop" ]]; then
echo "Shutting down $2 VM"
check_vm_name "$2"
shut_down_vm "$2"
else
echo "Ok I don't what you're trying to do here, $1 doesn't mean anything to me"
fi
Here's the switch configured in Home-Assistant (in configuration.yaml). Once it's an entity in HASS there are endless possibilities for adding buttons or starting/stopping VMs via automation.
switch:
- platform: command_line
switches:
win10_vm:
command_on: "ssh
[email protected] '/tmp/user.scripts/tmpScripts/00_start_stop_VMs/script start \"Windows 10\"'"
command_off: "ssh
[email protected] '/tmp/user.scripts/tmpScripts/00_start_stop_VMs/script stop \"Windows 10\"'"
command_state: "ssh
[email protected] 'if [[ $(virsh domstate \"Windows 10\") == \"shut off\" ]]; then echo 1; else echo 0; fi'""
value_template: '{{ value == "0" }}'
friendly_name: Windows 10 VM
ubuntu_vm:
command_on: "ssh
[email protected] '/tmp/user.scripts/tmpScripts/00_start_stop_VMs/script start \"Ubuntu\"'"
command_off: "ssh
[email protected] '/tmp/user.scripts/tmpScripts/00_start_stop_VMs/script stop \"Ubuntu\"'"
command_state: "ssh
[email protected] 'if [[ $(virsh domstate \"Ubuntu\") == \"shut off\" ]]; then echo 1; else echo 0; fi'"
value_template: '{{ value == "0" }}'
friendly_name: Ubuntu VM