I wrote a bash script for dmenu which executes common VM actions (start, restart, shutdown...) in dom0

Intro

I always find it tedious to use the GUI Qube Manager because it takes time to open (1-2s) and requires using my mediocre trackpad. The GUI is especially tedious relative to common VM actions, such as starting, restarting, or shutting down.

To avoid the GUI, I instead wrote a dmenu script in which I first select a VM from a list, and then select an action to perform on that VM.

Instead of opening up the Qube Manager, selecting a VM, and then clicking a button, I can just press my script hotkey, type a few characters, and be on my way.

Disclaimer: I use i3 as my window manager, and I am biased towards typing, as well as against using the mouse. I still think that non-tiling wm users, however— especially those with mediocre trackpads or mice— would benefit from this script.

Demonstration

Almost immediately after pressing my hotkey to the script I get a dmenu prompt to choose a VM:

+------------------+
| Choose VM | _    |
+------------------+
|           | VM 1 |
|           | VM 2 |
|           | VM 3 |
|           |  ... |
|           | VM n |
+------------------+

If I go ahead and select VM 1, a second dmenu prompt immediately pops up for choosing the action I’d like to perform on VM 1.

+--------------------------+
| Choose Action | _        |
+--------------------------+
|               | start    |
|               | shutdown |
|               | restart  |
|               | pause    |
|               | unpause  |
|               | --back-- |
+--------------------------+

After selecting an action, the prompt immediately disappears and a respective command is executed (i.e. qvm-start for “start”). Selecting --back-- brings me back to the VM selection menu.

The script: qm-dmenu.sh

# A dmenu script for performing common VM actions
# without having to use the Qube Manager GUI.

# Generate list of VMs
VM_LIST=$(qvm-ls | awk '{print $1}' | tail -n +2)

# Define list of VM actions
ACTIONS='start\nshutdown\nrestart\npause\nunpause\nkill\n--back--'

# Preset $ACTION to use in a while loop which brings you
# back to the VM selection menu if you didn't choose an action
ACTION='--back--'

while [ "$ACTION" = "--back--" ]
do
        SELECTED_VM=$(echo "$VM_LIST" | dmenu -p "Choose VM")
        [ -z "$SELECTED_VM" ] && exit

        ACTION=$(echo -e "$ACTIONS" | dmenu -p "Choose Action")

        # Run action for VM (special case: restart)
        [ "$ACTION" = "restart" ] && qvm-shutdown --wait $SELECTED_VM &&
        qvm-start $SELECTED_VM || qvm-$ACTION $SELECTED_VM
done

More Comments:

  1. qvm-ls is the command that takes the longest to run. You could instead keep $VM_LIST in a file and have this script read that file, but then you need to update the file whenever a new VM (or even DispVM) is created/deleted (cron?), and you also have to deal with another file.

  2. This script makes use of the fact that many VM actions take the form of qvm-* commands, where * is start, shutdown, and so on, making it easy to pass dmenu output into the qvm-* command.

While it is possible to extend this script to include other VM actions available in the GUI, you’d need more tests for each specific action (like restart, which is not available as qvm-restart). The GUI also gives error messages, which are important. And sometimes the GUI presentation is just more useful (i.e. creating a new qube).

  1. More on restart (old): simply using qvm-shutdown && qvm-start does not work; sleep 5 is necessary to allow the VM to fully shut down before (re)starting because qvm-shutdown “completes” and proceeds to && qvm-start before the VM actually shuts down. Depending on your VM shutdown speed, you may need to sleep a longer time.

Edit: sleep was removed and --wait flag was added (see comment below).

  1. I use [ -z "$SELECTED_VM" ] && exit to exit if dmenu receives no input for the VM selection (i.e. if I press Esc). dmenu disappears immediately if it doesn’t receive input for $ACTION (although qvm- is still run and exits with an error).

I hope this helps anybody looking to move toward using the keyboard and I am always open for suggestions. I’ll also probably add some additional actions beyond what I’ve included here, and would be happy to update this post and figure out a way to host this script publicly in the cloud.

2 Likes

FWIW, you can avoid the sleep and use:

qvm-shutdown --wait "$VM_NAME" && qvm-start "$VM_NAME"

Besides that, great script!

1 Like

Hm, surely an interesting way to do it with a menu.

Personally I avoid menus in general though and stick with my command prompt shortcut in combination with [1].

[1] GitHub - 3hhh/qubes-terminal-hotkeys: keyboard efficient VM management for Qubes OS

1 Like

Great fix with --wait, thanks! Updated.