Jose Catre-Vandis
February 23rd, 2009, 10:00 PM
HOWTO: Gracefully Shutdown VirtualBox VMs on Reboot or Shutdown of Ubuntu
I always forget I have a GUI virtual machine open when I go to shutdown, usually because it is on another desktop, out of sight. This howto will show you how to avoid the same thing, and to put any VMs you have open into a saved state, ready for a quick start up next time.
Before we go any further...
What this howto will not do:
1. Save VMs when you CTRL+ALT+BKSPACE.
2. Save VMS when you Log Out.
3. Save VMs from VMware, Xen, Qemu, etc.
That out of the way, all the work is done by a bash script and a bit of configuration on your system. As with all things, there are some caveats
to be mentioned. The script will work on headless as well as GUI virtual machines, however, there seems to be a bug in VirtualBox that will not allow a saved GUI VM open up as Headless. A saved Headless VM will happily open up as a GUI VM, but for some reason not around the other way. My focus is on sorting things out for desktop GUI VMs.
The difficulties arise in using a script like vboxtool (which handles headless VMs well, is that all the work has to happen while the window and display managers (GDM/GNOME or GDM/XFCE) are still up and running, hence why you cannot simply write a script and pop it in "init.d" and then update-rc.d it. I know, I spent a week on it!
So we have to run the script from the desktop while the GUI is up, in order to safely close/save desktop VMs. Adding on the shutdown and reboot routines just adds to the fun :)
Requirements:
1. Virtualbox (tested on closed source version 2.1.4)
2. Installed virtual machines (do your own thing here)
3. Debian derivative distro with sudoers file (requires editing)
4. Zenity (for GUI dialogs)
5. Replacement of <!user!> with your username in the script and in the sudoers file
This username should be the logged on user and that of the creator /installer of VirtualBox. (So take a default installation of Ubuntu where you create a user as a part of the install. Once complete you install VBox as that user, and so on)
Setup:
Assumes knowledge of installing VirtualBox and VMs
Copy the script to your home directory and make executable
chmod +x ~/shut.vm
Install zenity:
sudo apt-get install zenity
Edit your sudoers file (in a terminal):
sudo visudo
scroll to the bottom of the file and add the following
<!user!> ALL = NOPASSWD: /sbin/shutdown
<!user!> ALL = NOPASSWD: /etc/init.d/vboxdrv
<!user!> ALL = NOPASSWD: /etc/init.d/preload
replacing <!user!> with your username
And save out the file. The effects are immediate.
These changes allow your user (you) to run the shutdown, vboxdrv stop
and preload stop commands without having to enter your password.
Look in the script for any lines that contain:
sudo -H -u -<!user!>
and replace <!user!> with your username (there are 4 lines!)
sudo nano ~/shut.vm
Running the script:
Assuming code is in your home directory and you have made it executable,
you can then run the script from a terminal:
~/shut.vm
An easier way is to set up a launcher and point the launcher
to the script. Because of the different ways of doing this in various
distros the actual process of adding a button to your taskbar will
not be covered here, but documentation is widely available.
Comments:
I found that I needed to close the vboxdrv and preload services on
my test machine, before shutdown/reboot. If you don't have preload
installed, the command doesn't appear to have any adverse effect.
If it does, then remove the lines with
sudo /etc/init.d/preload stop
in them, or comment them out with a "#" at the beginning of the line.
sudo nano ~/shut.vm
to edit.
If you run the script from a terminal, apart from the zenity dialogs
you should get plenty of feedback about what is going on and where
you are in the process.
Also plenty of more info in the script about what is going on :)
The script in all its glory:
#!/bin/bash
# /shut.vm
# Author: Jose Catre-Vandis (Joe90)
# Web: www.bimma.me.uk
# Tested on XUBUNTU 8.10 with VirtualBox 2.1.4 (2.1_2.1.4-42893)
################################################## ######################
# Requirements
# Virtualbox
# Installed virtual machines
# Debian derivative distro with sudoers file (requires editing)
# Zenity
# Replacement of <!user!> with your username in the script and in
#+the sudoers file
# This username should be the logged on user and that of the creator
#+/installer of VirtualBox. (So take a default installation of Ubuntu
#+where you create a user as a part of the install. Once complete you
#+install VBox as that user, and so on)
################################################## ######################
# Setup
# Assumes knowledge of installing VirtualBox and VMs
# Install zenity: "sudo apt-get install zenity"
# edit your sudoers file (in a terminal):
# sudo visudo
# scroll to the bottom of the file and add the following
#+(don't include the #'s in the sudoers file!):
# <!user!> ALL = NOPASSWD: /sbin/shutdown
# <!user!> ALL = NOPASSWD: /etc/init.d/vboxdrv
# <!user!> ALL = NOPASSWD: /etc/init.d/preload
# replacing <!user!> with your username
# And save out the file. The effects are immediate.
# Look in the script for any lines that contain:
# sudo -H -u -<!user!>
# replace <!user!> with your username
################################################## ######################
# Running the script
# Script Location. you can put it anywhere you like. I run it out of
#+my home directory. You will need to make it executable:
# chmod +x ~/shut.vm
# You can then run the script from a terminal:
# ~/shut.vm
# An easier way is to set up a launcher and point the launcher
#+to the script. Because of the different ways of doing this in various
#+distros the actual process of adding a button to your taskbar will
#+not be covered here, but documentation is widely available.
################################################## ######################
# Lists running VMs and puts in array RUNVMLIST
# Here we first iterate through a list of any VMs that
#+are running, then we extract the names of the VMs and
#+add them to an array.
# Then we report (in a terminal if run that way), which
#+VMs are running and how many there are.
################################################## ######################
declare -a RUNVMLIST
vmnum=0
for running in $(VBoxManage -nologo list runningvms)
do
name=$(VBoxManage -nologo showvminfo $running | grep "Name:" | awk 'BEGIN{FS="Name: "}{print $2}')
RUNVMLIST=( "${RUNVMLIST[@]}" "$name")
vmnum=$(($vmnum + 1))
done
if [ ! "$running" ]
then
echo "No VMs running"
else
echo "Running VMs = "${RUNVMLIST }
echo "Number of VMs Running = "${#RUNVMLIST }
fi
################################################## ######################
# Takes all this info and uses it as you shut down or reboot
# to gracefully close and save any open VMs
# First off you get a Zenity dialog asking if you want to
#+Shutdown or Reboot, or Cancel the closedown. If you click
#+OK, you then are provided with a second Zenity dialog asking
#+if you want to Shutdown (OK) or Reboot (Cancel).
# If you choose OK (the Shutdown routine) the script then has a
#+look at the array to see if there are any running VMs. If there
#+are no running VMs, the script will proceed directly to Shutdown.
# If there are running VMs, the script will first save the state of
#+each VM in turn, putting up a Zenity progress dialog which you
#+can leave alone as it auto closes, then we proceed to Shutdown.
# A similar thing happens if you choose Cancel (the Reboot routine)
#+only that after the save of states, you go to Reboot.
# I found that I needed to close the vboxdrv and preload services on
#+my test machine, before shutdown/reboot. If you don't have preload
#+installed, the command doesn't appear to have any adverse effect.
#+If it does, then remove the lines with "sudo /etc/init.d/preload stop"
#+in them, or comment them out with a "#" at the beginning of the line.
################################################## ######################
zenity --text="Click OK if you want to Shutdown or Reboot. Click Cancel to resume." --title="Shutdown or Reboot?" --width="320" --height="150" --question
closeorcancel=$?
if [ "${closeorcancel}" == "0" ]
then
echo "You chose to Shutdown or Reboot"
else
echo "You chose to Cancel and resume your work"
exit
fi
zenity --text="Click OK if you want to Shutdown. Click Cancel to Reboot." --title="Shutdown or Reboot?" --width="320" --height="150" --question
shutorboot=$?
if [ "${shutorboot}" == "0" ]
then
echo "You chose to Shutdown"
if [ ! ${RUNVMLIST }]
then
echo "No VMs open, straight to shutdown"
sudo -H -u <!user!> /etc/init.d/vboxdrv stop
sudo /etc/init.d/preload stop
sudo /sbin/shutdown -h now
else
echo "All open VMs will be closed to a saved state"
for vm in ${RUNVMLIST }
do
(VBoxManage controlvm $vm savestate) | zenity --progress --pulsate --width="320" --height="150" --title="Please Wait while VMs are Saved" --auto-close
echo "$vm was closed to a saved state"
done
echo "Shutting down now"
sudo -H -u <!user!> /etc/init.d/vboxdrv stop
sudo /etc/init.d/preload stop
sudo /sbin/shutdown -h now
fi
else
echo "You chose to Reboot"
if [ ! ${RUNVMLIST }]
then
echo "No VMs open, straight to reboot"
sudo -H -u <!user!> /etc/init.d/vboxdrv stop
sudo /etc/init.d/preload stop
sudo /sbin/shutdown -r now
else
echo "All open VMs will be closed to a saved state"
for vm in ${RUNVMLIST }
do
(VBoxManage controlvm $vm savestate) | zenity --progress --pulsate --width="320" --height="150" --title="Please Wait while VMs are Saved" --auto-close
echo "$vm was closed to a saved state"
done
echo "Rebooting Now"
sudo -H -u <!user!> /etc/init.d/vboxdrv stop
sudo /etc/init.d/preload stop
sudo /sbin/shutdown -r now
fi
fi
exit
I have also attached the script in a zip file for downloading.
Undoing what you have done:
1. Delete the script!
2. Reverse the changes made in your sudoers file
3. Uninstall zenity (though not necessary)
sudo apt-get remove zenity
Happy to help with questions, comments, problems, etc, and will probably add some simpler scripts for just saving VMs or gathering info. Will also welcome any suggestions for improvements or developments of the script. I would particularly like to know how to link this up with the standard shutdown/reboot buttons in Ubuntu/Xubuntu to avoid having to create a new shortcut to the script, and streamline things...
Credits to the writer/s of vboxtool, the best starter-stopper of headless VMs there is (imho), for a couple of snippets of code here and there, and to markba on Ubuntuforums, and TerryE on virtualbox forums for help and pointers
I always forget I have a GUI virtual machine open when I go to shutdown, usually because it is on another desktop, out of sight. This howto will show you how to avoid the same thing, and to put any VMs you have open into a saved state, ready for a quick start up next time.
Before we go any further...
What this howto will not do:
1. Save VMs when you CTRL+ALT+BKSPACE.
2. Save VMS when you Log Out.
3. Save VMs from VMware, Xen, Qemu, etc.
That out of the way, all the work is done by a bash script and a bit of configuration on your system. As with all things, there are some caveats
to be mentioned. The script will work on headless as well as GUI virtual machines, however, there seems to be a bug in VirtualBox that will not allow a saved GUI VM open up as Headless. A saved Headless VM will happily open up as a GUI VM, but for some reason not around the other way. My focus is on sorting things out for desktop GUI VMs.
The difficulties arise in using a script like vboxtool (which handles headless VMs well, is that all the work has to happen while the window and display managers (GDM/GNOME or GDM/XFCE) are still up and running, hence why you cannot simply write a script and pop it in "init.d" and then update-rc.d it. I know, I spent a week on it!
So we have to run the script from the desktop while the GUI is up, in order to safely close/save desktop VMs. Adding on the shutdown and reboot routines just adds to the fun :)
Requirements:
1. Virtualbox (tested on closed source version 2.1.4)
2. Installed virtual machines (do your own thing here)
3. Debian derivative distro with sudoers file (requires editing)
4. Zenity (for GUI dialogs)
5. Replacement of <!user!> with your username in the script and in the sudoers file
This username should be the logged on user and that of the creator /installer of VirtualBox. (So take a default installation of Ubuntu where you create a user as a part of the install. Once complete you install VBox as that user, and so on)
Setup:
Assumes knowledge of installing VirtualBox and VMs
Copy the script to your home directory and make executable
chmod +x ~/shut.vm
Install zenity:
sudo apt-get install zenity
Edit your sudoers file (in a terminal):
sudo visudo
scroll to the bottom of the file and add the following
<!user!> ALL = NOPASSWD: /sbin/shutdown
<!user!> ALL = NOPASSWD: /etc/init.d/vboxdrv
<!user!> ALL = NOPASSWD: /etc/init.d/preload
replacing <!user!> with your username
And save out the file. The effects are immediate.
These changes allow your user (you) to run the shutdown, vboxdrv stop
and preload stop commands without having to enter your password.
Look in the script for any lines that contain:
sudo -H -u -<!user!>
and replace <!user!> with your username (there are 4 lines!)
sudo nano ~/shut.vm
Running the script:
Assuming code is in your home directory and you have made it executable,
you can then run the script from a terminal:
~/shut.vm
An easier way is to set up a launcher and point the launcher
to the script. Because of the different ways of doing this in various
distros the actual process of adding a button to your taskbar will
not be covered here, but documentation is widely available.
Comments:
I found that I needed to close the vboxdrv and preload services on
my test machine, before shutdown/reboot. If you don't have preload
installed, the command doesn't appear to have any adverse effect.
If it does, then remove the lines with
sudo /etc/init.d/preload stop
in them, or comment them out with a "#" at the beginning of the line.
sudo nano ~/shut.vm
to edit.
If you run the script from a terminal, apart from the zenity dialogs
you should get plenty of feedback about what is going on and where
you are in the process.
Also plenty of more info in the script about what is going on :)
The script in all its glory:
#!/bin/bash
# /shut.vm
# Author: Jose Catre-Vandis (Joe90)
# Web: www.bimma.me.uk
# Tested on XUBUNTU 8.10 with VirtualBox 2.1.4 (2.1_2.1.4-42893)
################################################## ######################
# Requirements
# Virtualbox
# Installed virtual machines
# Debian derivative distro with sudoers file (requires editing)
# Zenity
# Replacement of <!user!> with your username in the script and in
#+the sudoers file
# This username should be the logged on user and that of the creator
#+/installer of VirtualBox. (So take a default installation of Ubuntu
#+where you create a user as a part of the install. Once complete you
#+install VBox as that user, and so on)
################################################## ######################
# Setup
# Assumes knowledge of installing VirtualBox and VMs
# Install zenity: "sudo apt-get install zenity"
# edit your sudoers file (in a terminal):
# sudo visudo
# scroll to the bottom of the file and add the following
#+(don't include the #'s in the sudoers file!):
# <!user!> ALL = NOPASSWD: /sbin/shutdown
# <!user!> ALL = NOPASSWD: /etc/init.d/vboxdrv
# <!user!> ALL = NOPASSWD: /etc/init.d/preload
# replacing <!user!> with your username
# And save out the file. The effects are immediate.
# Look in the script for any lines that contain:
# sudo -H -u -<!user!>
# replace <!user!> with your username
################################################## ######################
# Running the script
# Script Location. you can put it anywhere you like. I run it out of
#+my home directory. You will need to make it executable:
# chmod +x ~/shut.vm
# You can then run the script from a terminal:
# ~/shut.vm
# An easier way is to set up a launcher and point the launcher
#+to the script. Because of the different ways of doing this in various
#+distros the actual process of adding a button to your taskbar will
#+not be covered here, but documentation is widely available.
################################################## ######################
# Lists running VMs and puts in array RUNVMLIST
# Here we first iterate through a list of any VMs that
#+are running, then we extract the names of the VMs and
#+add them to an array.
# Then we report (in a terminal if run that way), which
#+VMs are running and how many there are.
################################################## ######################
declare -a RUNVMLIST
vmnum=0
for running in $(VBoxManage -nologo list runningvms)
do
name=$(VBoxManage -nologo showvminfo $running | grep "Name:" | awk 'BEGIN{FS="Name: "}{print $2}')
RUNVMLIST=( "${RUNVMLIST[@]}" "$name")
vmnum=$(($vmnum + 1))
done
if [ ! "$running" ]
then
echo "No VMs running"
else
echo "Running VMs = "${RUNVMLIST }
echo "Number of VMs Running = "${#RUNVMLIST }
fi
################################################## ######################
# Takes all this info and uses it as you shut down or reboot
# to gracefully close and save any open VMs
# First off you get a Zenity dialog asking if you want to
#+Shutdown or Reboot, or Cancel the closedown. If you click
#+OK, you then are provided with a second Zenity dialog asking
#+if you want to Shutdown (OK) or Reboot (Cancel).
# If you choose OK (the Shutdown routine) the script then has a
#+look at the array to see if there are any running VMs. If there
#+are no running VMs, the script will proceed directly to Shutdown.
# If there are running VMs, the script will first save the state of
#+each VM in turn, putting up a Zenity progress dialog which you
#+can leave alone as it auto closes, then we proceed to Shutdown.
# A similar thing happens if you choose Cancel (the Reboot routine)
#+only that after the save of states, you go to Reboot.
# I found that I needed to close the vboxdrv and preload services on
#+my test machine, before shutdown/reboot. If you don't have preload
#+installed, the command doesn't appear to have any adverse effect.
#+If it does, then remove the lines with "sudo /etc/init.d/preload stop"
#+in them, or comment them out with a "#" at the beginning of the line.
################################################## ######################
zenity --text="Click OK if you want to Shutdown or Reboot. Click Cancel to resume." --title="Shutdown or Reboot?" --width="320" --height="150" --question
closeorcancel=$?
if [ "${closeorcancel}" == "0" ]
then
echo "You chose to Shutdown or Reboot"
else
echo "You chose to Cancel and resume your work"
exit
fi
zenity --text="Click OK if you want to Shutdown. Click Cancel to Reboot." --title="Shutdown or Reboot?" --width="320" --height="150" --question
shutorboot=$?
if [ "${shutorboot}" == "0" ]
then
echo "You chose to Shutdown"
if [ ! ${RUNVMLIST }]
then
echo "No VMs open, straight to shutdown"
sudo -H -u <!user!> /etc/init.d/vboxdrv stop
sudo /etc/init.d/preload stop
sudo /sbin/shutdown -h now
else
echo "All open VMs will be closed to a saved state"
for vm in ${RUNVMLIST }
do
(VBoxManage controlvm $vm savestate) | zenity --progress --pulsate --width="320" --height="150" --title="Please Wait while VMs are Saved" --auto-close
echo "$vm was closed to a saved state"
done
echo "Shutting down now"
sudo -H -u <!user!> /etc/init.d/vboxdrv stop
sudo /etc/init.d/preload stop
sudo /sbin/shutdown -h now
fi
else
echo "You chose to Reboot"
if [ ! ${RUNVMLIST }]
then
echo "No VMs open, straight to reboot"
sudo -H -u <!user!> /etc/init.d/vboxdrv stop
sudo /etc/init.d/preload stop
sudo /sbin/shutdown -r now
else
echo "All open VMs will be closed to a saved state"
for vm in ${RUNVMLIST }
do
(VBoxManage controlvm $vm savestate) | zenity --progress --pulsate --width="320" --height="150" --title="Please Wait while VMs are Saved" --auto-close
echo "$vm was closed to a saved state"
done
echo "Rebooting Now"
sudo -H -u <!user!> /etc/init.d/vboxdrv stop
sudo /etc/init.d/preload stop
sudo /sbin/shutdown -r now
fi
fi
exit
I have also attached the script in a zip file for downloading.
Undoing what you have done:
1. Delete the script!
2. Reverse the changes made in your sudoers file
3. Uninstall zenity (though not necessary)
sudo apt-get remove zenity
Happy to help with questions, comments, problems, etc, and will probably add some simpler scripts for just saving VMs or gathering info. Will also welcome any suggestions for improvements or developments of the script. I would particularly like to know how to link this up with the standard shutdown/reboot buttons in Ubuntu/Xubuntu to avoid having to create a new shortcut to the script, and streamline things...
Credits to the writer/s of vboxtool, the best starter-stopper of headless VMs there is (imho), for a couple of snippets of code here and there, and to markba on Ubuntuforums, and TerryE on virtualbox forums for help and pointers