XCP-ng
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Register
    • Login

    Script to auto mount USBs on Boot/Reboot. Monitoring Multiple UPS

    Scheduled Pinned Locked Moved XCP-ng
    7 Posts 2 Posters 472 Views 2 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • S Offline
      seanmcg182
      last edited by seanmcg182

      Hey, I'm not a huge poster, but I've been working on a short script to solve a problem I've been having.

      Long story short, I have 5 CyberPower UPSs that I want to monitor over USB.
      I know NUT exists, but I hear it's a hassle, and I like the trending/reporting that's available in the CyberPower Software.
      Unfortunately, I can only monitor 1 UPS per instance of the software.
      And on top of that, when/if the server reboots, all USB Passthrough is reset, as the USB UUID changes.
      However I noticed that in "xe pusb-list" there is a static "Path" designation which I realized I could use to my advantage

      So I built this script to run at startup (probably going to add a 1-2 minute delay on the front end, as sometimes the USB drivers take a minute to load, I'm learning). It grabs the UUID of a USB and saves it to a txt file based on the "Path". It then grabs the UUID of my designated VMs (UPS1-UPS5, just single core 1GB Ram ubuntu to run the software). Main reason I did this instead of hardcoding the UUID is in case I ever need to delete/restore the VM from backup and the UUID Changes. and Finally it starts the VM.

      I haven't finished installing all of the UPSs, so I only have 3 of the 5 VMs programmed currently, but it's in a good enough state That I wanted to share it in case anyone else has been looking to solve a similar problem.

      #set working directory
      cd /home/temp
      
      #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 Serial Number, 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' ]
              then  awk '/uuid/ {print $5}' "$f" > "$vmname".txt
              fi
      done
      
      #remove all csplit files
      rm -f xx*
      
      #if expected UPS is present, attach to expected VM
      if test -f 2-2.1group.txt
      then xe vusb-create usb-group-uuid=$(cat 2-2.1group.txt) vm-uuid=$(cat UPS1.txt)
      xe vm-start uuid=$(cat UPS1.txt)
      fi
      
      if test -f 2-2.2group.txt
      then xe vusb-create usb-group-uuid=$(cat 2-2.2group.txt) vm-uuid=$(cat UPS2.txt)
      xe vm-start uuid=$(cat UPS2.txt)
      fi
      
      if test -f 2-2.4group.txt
      then xe vusb-create usb-group-uuid=$(cat 2-2.4group.txt) vm-uuid=$(cat UPS5.txt)
      xe vm-start uuid=$(cat UPS5.txt)
      fi
      
      #remove leftover txt files
      rm -f *.txt
      

      I am by no means an expert in scripting or linux... This has all been a learning endeavor for me... so if anyone has any suggestions on how to improve this script, I do welcome feedback.

      1 Reply Last reply Reply Quote 0
      • olivierlambertO Online
        olivierlambert Vates 🪐 Co-Founder CEO
        last edited by

        That's interesting, I wonder why we have to reset all USB uuids after a reboot. Probably something to investigate when you have the time to do so 😆

        S 1 Reply Last reply Reply Quote 1
        • S Offline
          seanmcg182 @olivierlambert
          last edited by

          @olivierlambert Y'know, I thought I smelled a bit of sarcasm there, so I went and double checked... and i think now I'm more confused lmao

          So I rebooted, UUIDs and Paths didn't change.
          Then I unplugged, and moved one of the USBs I'm currently using.... and moving that one USB changed the Path and UUID of all 3 USBs that were attached.

          Guess the Paths weren't as static as I thought 😞

          1 Reply Last reply Reply Quote 0
          • olivierlambertO Online
            olivierlambert Vates 🪐 Co-Founder CEO
            last edited by

            Haha no it was really intriguing, but to be fair, it's "another question" in the pile of many others 😓 Something to take a look when we can, I wonder how does this work in a bare metal OS.

            S 1 Reply Last reply Reply Quote 1
            • S Offline
              seanmcg182 @olivierlambert
              last edited by

              @olivierlambert The never ending struggle of development. always more questions.

              while I did notice that the overall path changed, I did notice that some parts were consistent still...
              IE, My Paths changed from 2-2.1, 2-2.2, and 2-2.4 to 1-2.1, 1-2.2, and 1-2.4 respectively.

              Ideally I would be using the Serial Number readout to sort these more efficiently, but for some reason my rack mounted CyberPower UPSs don't have Serial Numbers reporting even in the software when direct connected to my desktop... hence why I'm trying to find another way to "statically" identify my devices.

              I'm going to keep working on this program, and will update at a later point when I make some more significant progress, maybe with some "Options" for people to swap in.

              Next objective is for it to detect whether a running VM has its proper USB attached still, and if it became detached, to stop the VM, mount the USB, and then start it... main reason for this is in case a UPS gets unplugged, or is removed for maintenance.

              S 1 Reply Last reply Reply Quote 1
              • S Offline
                seanmcg182 @seanmcg182
                last edited by seanmcg182

                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
                
                1 Reply Last reply Reply Quote 1
                • S seanmcg182 referenced this topic on
                • olivierlambertO Online
                  olivierlambert Vates 🪐 Co-Founder CEO
                  last edited by

                  Ping @stormi so we track this somewhere internally

                  1 Reply Last reply Reply Quote 2
                  • First post
                    Last post