Just an update if anyone ever comes back to this topic:
I held off on updating this script, as my disconnects had been very minimal over the last year...
However, due to my recent issues in 8.3 (along with someone else's https://xcp-ng.org/forum/topic/10590/vusb-keeps-disappearing ) I decided to put some heavier investment into this script.
Long story short, it will attach USB Devices to VMs and start them automatically, Shutdown VMs and reattach VUSBs if they become disconnected and restart the VMs afterwards.
To Recap my setup, I have 6 CyberPower UPS's, and 6 VMs named "UPS1", "UPS2", etc to "UPS6"
I have updated this script to:
(Before this new logic, it does the previously written gathering of PUSB UUIDs, USB Group UUIDs, VM UUIDs, VM Power States, in addition to enabling passthrough for any PUSBs that need it)
First, logic checks existing VUSBs to see if they are in a "Disconnected" state from a running VM they are attached to... If so, it will shut off the VM
Second, if a VUSB is not detected as attached for a running Running UPS VM, it will shut off the VM
If a VM shutdown command was executed, the program will wait 5 seconds (MY VMs are minimal, you may need to adjust this timer if your VMs take longer to power off)
It will then rescan the VM Power States
After this is done, it runs my previous logic of Attaching the appropriate USB Group to a Virtual Machine if it's needed, and starts any non-running VM.
I have this setup on a cron timer every minute.
if run manually, you may see the following errors:
1)
The server failed to handle your request, due to an internal error. The given message may give details useful for debugging the problem.
message: xenopsd internal error: Device_common.QMP_Error(51, "{\"error\":{\"class\":\"DeviceNotFound\",\"desc\":\"Device 'vusb2-1.3' not found\",\"data\":{}},\"id\":\"qmp-000368-51\"}")
This error appears the first time a shutdown command to a VM is executed after the VUSB enters a "Disconnected". Happens when attempting to shutdown VM in XOA as well... Due to this, the code just executes the command a second time.
2)
USB_groups are currently restricted to contain no more than one VUSB.
This appears in the scenario where the VUSB is still present in the VM, just in a "disconnected" state, as it can't be reattached.
I'm sure I could modify the code to remove this dialogue, but it doesn't affect functionality.
Hopefully this helps someone.
#####set working directory
cd /home/UPSAutoConnect/TempFiles
#####remove old text files
rm -f *.txt
#####create list of all pUSBs
xe pusb-list > pusb.txt
#####split list per device and remove old list
csplit -sz pusb.txt /uuid/ '{*}'
rm -f pusb.txt
#####for all split files, if Vendor ID is CyberPower, create a txt file named by Physical USB Path, containing the USB uuid, and enable for passthrough
for i in xx*
do
var1=$(awk '/vendor-id/ {print $4}' "$i")
if [ "$var1" -eq 0764 ]
then path=$(awk '/path/ {print $4}' "$i")
awk '/uuid/ {print $5}' "$i" > "$path".txt
xe pusb-param-set uuid=$(cat "$path".txt) passthrough-enabled=true
xe usb-group-list PUSB-uuids=$(cat "$path".txt) > "$i"-2
awk '/uuid/ {print $5}' "$i"-2 > "$path"group.txt
fi
done
#####remove all csplit files
rm -f xx*
#####create list of all VMs
xe vm-list > vm.txt
#####split list per vm and remove old list
csplit -sz vm.txt /uuid/ '{*}'
rm -f vm.txt
#####for all split files, get UUID of needed VMs
for f in xx*
do
vmname=$(awk '/name/ {print $4}' "$f")
if [ "$vmname" == 'UPS1' ] || [ "$vmname" == 'UPS2' ] || [ "$vmname" == 'UPS3' ] || [ "$vmname" == 'UPS4' ] || [ "$vmname" == 'UPS5' ] || [ "$vmname" == 'UPS6' ]
then awk '/uuid/ {print $5}' "$f" > "$vmname".txt
awk '/power/ {print $4}' "$f" > "$vmname"state.txt
fi
done
#####remove all csplit files
rm -f xx*
#####create list of all vUSBs
xe vusb-list > vusb.txt
#####split list per device and remove old list
awk '/uuid/ {print $5}' "vusb.txt" > vusb2.txt
awk 'NF > 0' "vusb2.txt" > vusb3.txt
split -dl 1 vusb3.txt
rm -f vusb.txt
rm -f vusb2.txt
rm -f vusb3.txt
#####for all split files, if VM Running and device disconnected, halt VM
for g in x*
do
vmname2=$(xe vusb-param-get uuid=$(cat "$g") param-name=vm-name-label)
xe vusb-param-get uuid=$(cat "$g") param-name=vm-name-label > "$vmname2"vusb.txt
vmstate=$(cat "$vmname2"state.txt)
vusbattached=$(xe vusb-param-get uuid=$(cat "$g") param-name=currently-attached)
if ([ "$vmname2" == 'UPS1' ] || [ "$vmname2" == 'UPS2' ] || [ "$vmname2" == 'UPS3' ] || [ "$vmname2" == 'UPS4' ] || [ "$vmname2" == 'UPS5' ] || [ "$vmname2" == 'UPS6' ]) && [ "$vusbattached" == 'false' ] && [ "$vmstate" == 'running' ]
then xe vm-shutdown uuid=$(cat "$vmname2".txt) force=true
then xe vm-shutdown uuid=$(cat "$vmname2".txt) force=true
waitforshutdown=1
fi
done
#####remove all split files
rm -f x*
#####If no VUSB detected, halt VM
if [ ! -f UPS1vusb.txt ] && [ $(cat UPS1state.txt) == 'running' ]
then xe vm-shutdown uuid=$(cat UPS1.txt) force=true
waitforshutdown=1
fi
if [ ! -f UPS2vusb.txt ] && [ $(cat UPS2state.txt) == 'running' ]
then xe vm-shutdown uuid=$(cat UPS2.txt) force=true
waitforshutdown=1
fi
if [ ! -f UPS3vusb.txt ] && [ $(cat UPS3state.txt) == 'running' ]
then xe vm-shutdown uuid=$(cat UPS3.txt) force=true
waitforshutdown=1
fi
if [ ! -f UPS4vusb.txt ] && [ $(cat UPS4state.txt) == 'running' ]
then xe vm-shutdown uuid=$(cat UPS4.txt) force=true
waitforshutdown=1
fi
if [ ! -f UPS5vusb.txt ] && [ $(cat UPS5state.txt) == 'running' ]
then xe vm-shutdown uuid=$(cat UPS5.txt) force=true
waitforshutdown=1
fi
if [ ! -f UPS6vusb.txt ] && [ $(cat UPS6state.txt) == 'running' ]
then xe vm-shutdown uuid=$(cat UPS6.txt) force=true
waitforshutdown=1
fi
#####if any VM was shutdown by code, wait for process to finish
if [ "$waitforshutdown" == 1 ]
then sleep 5s
fi
#####rerun previous acquisition to update VM Power States
#####create list of all VMs
xe vm-list > vm.txt
#####split list per vm and remove old list
csplit -sz vm.txt /uuid/ '{*}'
rm -f vm.txt
#####for all split files, get UUID of needed VMs
for h in xx*
do
vmname=$(awk '/name/ {print $4}' "$h")
if [ "$vmname" == 'UPS1' ] || [ "$vmname" == 'UPS2' ] || [ "$vmname" == 'UPS3' ] || [ "$vmname" == 'UPS4' ] || [ "$vmname" == 'UPS5' ] || [ "$vmname" == 'UPS6' ]
then awk '/uuid/ {print $5}' "$h" > "$vmname".txt
awk '/power/ {print $4}' "$h" > "$vmname"state.txt
fi
done
#####remove all csplit files
rm -f xx*
#####if expected UPS is present, attach to expected VM
if test -f *-1.1group.txt
then
if [ $(cat UPS1state.txt) == 'halted' ]
then
xe vusb-create usb-group-uuid=$(cat *-1.1group.txt) vm-uuid=$(cat UPS1.txt)
xe vm-start uuid=$(cat UPS1.txt)
fi
fi
if test -f *-1.2group.txt
then
if [ $(cat UPS2state.txt) == 'halted' ]
then
xe vusb-create usb-group-uuid=$(cat *-1.2group.txt) vm-uuid=$(cat UPS2.txt)
xe vm-start uuid=$(cat UPS2.txt)
fi
fi
if test -f *-1.3group.txt
then
if [ $(cat UPS3state.txt) == 'halted' ]
then
xe vusb-create usb-group-uuid=$(cat *-1.3group.txt) vm-uuid=$(cat UPS3.txt)
xe vm-start uuid=$(cat UPS3.txt)
fi
fi
if test -f *-1.4group.txt
then
if [ $(cat UPS4state.txt) == 'halted' ]
then
xe vusb-create usb-group-uuid=$(cat *-1.4group.txt) vm-uuid=$(cat UPS4.txt)
xe vm-start uuid=$(cat UPS4.txt)
fi
fi
if test -f *-2.1group.txt
then
if [ $(cat UPS5state.txt) == 'halted' ]
then
xe vusb-create usb-group-uuid=$(cat *-2.1group.txt) vm-uuid=$(cat UPS5.txt)
xe vm-start uuid=$(cat UPS5.txt)
fi
fi
if test -f *-2.2group.txt
then
if [ $(cat UPS6state.txt) == 'halted' ]
then
xe vusb-create usb-group-uuid=$(cat *-2.2group.txt) vm-uuid=$(cat UPS6.txt)
xe vm-start uuid=$(cat UPS6.txt)
fi
fi
#remove leftover files
rm -f *.txt
waitforshutdown=0