76

I use vagrant for development. I forget to shut down a few of the VMs. When I go to log out of my host machine, the Ubuntu shutdown process appears to hang.

Might there be a way to script a close of all vagrant boxes with a bit of commandline-fu? Something like the following, but something that, well, works.

for f in $HOME/vagrant;
do;
  cd $f
  vagrant halt
done;
6
  • I don't know vagrant but it seems to be linked to VMWare, not VirtualBox. Are you actually using VirtualBox?
    – terdon
    Apr 28, 2014 at 23:04
  • @terdon: Vagrant only supported Vbox initially. I think they now support other type of VM formats (understand VMWare) Apr 28, 2014 at 23:10
  • @SylvainPineau ah, OK. I just had a quick look at their webpage and saw a "VMWare integration" link and assumed. Thanks for the clarification.
    – terdon
    Apr 28, 2014 at 23:14
  • 1
    I'd take a look at this script. The full blog post is here. Not tested Apr 28, 2014 at 23:16
  • Richard please don't edit the answer in your question. You are free to answer your own question in a separate answer. I did give you an upvote for a good question.
    – don.joey
    Apr 30, 2014 at 17:06

11 Answers 11

102

For a scriptable control of Virtual Box machines we can make use of the VBoxManage commands:

  • List running machines (returns name and UUID):

    VBoxManage list runningvms
    
  • Stop running VMs by "hibernating" them (reommended to avoid data loss)

    VBoxManage controlvm <name|uuid> savestate
    
  • Poweroff running VMs (not recommended because we may lose data in the guest)

    VBoxManage controlvm <name|uuid> poweroff
    
  • Use ACPI in an ACPI-aware guest OS (preferable to poweroff for graceful shutdown of guests)

    VBoxManage controlvm <name|uuid> acpipowerbutton
    

Also see: How to safely shutdown Guest OS in VirtualBox using command line

Update from OP

Based on this selected correct answer below, I've added this bash script "$HOME/bin/stop-vagrant.sh". So now I have something that can safely begin a stop of all vagrant VMs that I might have turned on yet forgotten about in a session.

vboxmanage list runningvms | sed -r 's/.*\{(.*)\}/\1/' | xargs -L1 -I {} VBoxManage controlvm {} savestate

Command Explained:

vboxmanage list runningvms | -- gets a list of all running vms under VirtualBox

sed -r 's/.*\{(.*)\}/\1/' | -- strips the string down to id number

xargs -L1 -I {} VBoxManage controlvm {} savestate -- runs the save state command on each box that's open.

On xargs

  • -L1 - take one line at a time
  • -I {} - uses {} as a place holder for the next command
4
  • Whoo Hoo! Given the above advice, this command line works magic: vboxmanage list runningvms | sed -r 's/.*\{(.*)\}/\1/' | xargs -L1 -I {} VBoxManage controlvm {} savestate
    – Rick
    Apr 30, 2014 at 16:48
  • 1
    Note, the -r option is unique to GNU Sed. Nov 14, 2015 at 21:52
  • Best magical one-liner I've seen in a while! Good job! :D
    – tftd
    Apr 28, 2016 at 22:21
  • 1
    On OSX/macOS, you'll need to use -E instead of -r. It's the flag for using extended regular expressions.
    – JayD3e
    Oct 8, 2016 at 16:15
26

The other answer is great for handling Virtualbox, but Vagrant features its own mechanisms for handling Virtual Machines, and as was mentioned in one of the comments, it supports more than just VirtualBox, just VMWare at the moment, but who knows later!

This seems to work for me:

vagrant global-status | awk '/running/{print $1}' | xargs -r -d '\n' -n 1 -- vagrant suspend

Note:

This works with Vagrant versions after 1.6, for older versions, you should probably upgrade, but if you can't, one of the other options which focuses on Virtualbox may be better.

4
  • 5
    this is obviously a much correcter(tm) answer. @Richard should consider accepting this one instead
    – nhed
    Dec 23, 2014 at 17:28
  • The global-status command was introduced in Vagrant 1.6. Users on older versions of Vagrant, particularly those who've installed it via apt-get and may still be on 1.4.3, will need to update their Vagrant install before they can use this command. Oct 21, 2015 at 19:37
  • 1
    BSD xargs doesn't support -r, therefore you may install gxargs via brew and use it instead.
    – kenorb
    Apr 8, 2016 at 14:33
  • 1
    This should be the accepted answer!
    – mastazi
    Nov 13, 2019 at 1:44
13

My mechanism for this:

vagrant global-status | grep virtualbox | cut -c 1-9 | while read line; do echo $line; vagrant halt $line; done;

  • global-status lists all boxes
  • filter that for lines containing virtualbox (Filters out the help text, will break if you're using some other provider)
  • Filter that to display only the first 9 characters (the global unique ID)
  • While we can still read a line from that input, read it as the variable $line then:
    • Print out that $line
    • run vagrant halt $line halting the vagrant for that global unique ID

This is better than the Virtualbox method above, because it'll run any vagrant-configured shutdown mechanisms too.

8
  • 3
    This command works for OS X hosts as well. Others fail due to differences in command-line arguments handling between OSX and Linux versions of sed and awk. Thanks! Jan 19, 2016 at 18:25
  • @AndrewАндрейЛисточкин Confirm - works on OS X 10 well. Doesn't tested on other OS although.
    – setevoy
    Jan 20, 2016 at 9:46
  • 2
    The above command tries to halt all boxes, no matter if there are running or not, thus taking a long time to execute. For me, as i only use virtualbox, i changed the "virtualbox" grep to "running", to get only the running ones.
    – Alex2php
    May 25, 2016 at 10:26
  • This is a good answer, but you may like to use vagrant suspend instead of vagrant halt to save the state and suspend for a quicker down and up. Oct 16, 2016 at 9:06
  • True, and if it works for you that's great. I've had massive timekeeping problems with suspended VMs under Virtualbox, so I wouldn't recommend it.
    – Aquarion
    Oct 16, 2016 at 18:23
6

In case other people get to this question: For those using VirtualBox, it already can take care of this, only involves editing a file:

# Contents of /etc/default/virtualbox
# ...
# ...
# SHUTDOWN_USERS="foo bar"  
#   check for running VMs of user 'foo' and user 'bar'
#   'all' checks for all active users
# SHUTDOWN=poweroff
# SHUTDOWN=acpibutton
# SHUTDOWN=savestate
#   select one of these shutdown methods for running VMs
#   acpibutton and savestate causes the init script to wait
#   30 seconds for the VMs to shutdown

## My original values
# SHUTDOWN_USERS=""
# SHUTDOWN=poweroff

## My current values
SHUTDOWN_USERS="all"
SHUTDOWN=savestate

The upside is that is not necessary to edit/create any logout or init.d stript to run the commands posted in the other answers. The downside is this solution is specific to VirtualBox.

Tested on Ubuntu 14.10 with VirtualBox 4.3.18.

All credit goes to this post.

6

Combining some of the other answers, this will close down all running virtualbox vagrant boxes:

vagrant global-status | awk '/virtualbox running/{ print $1 }' | xargs vagrant halt
1
4

I just use vagrant halt. If you run it without a further argument, it stops all the machines defined in the Vagrantfile.

1

If you're writing scripts to parse Vagrant commands, it's advised to parse machine-friendly output (--machine-readable) which is more consistent.

The format is:

timestamp,target,type,data...

so you can import it as CSV file, since it's comma-separated.

With shell, it's probably more difficult to parse, for example:

for id in $(vagrant global-status --machine-readable | cut -d, -f5 | grep -B3 running | egrep -o "[0-9a-f]{7}"); do
    vagrant suspend $id;
done

See: Vagrant - Machine readable output


However I find it easier to parse the standard output, e.g.

while read id name provider state path; do
  [ "$state" = "running" ] && vagrant suspend $id;
done < <(vagrant global-status)

Btw. Theoretically vagrant command should accept a regular expression for the list of VMs to suspend as per this GH post, for example:

vagrant suspend '*'

but it doesn't work and there is a bug #7221 which is pending in order to fix it.


Related GitHub tickets:

0

This may or may not work for you ;-) Works for me

vagrant_halt_all.sh

#!/usr/bin/env bash
if [ -z "$1" ]
then
  OPTS=""
else
  # force close if any arg passed
  OPTS="-f"
fi

for i in $(vagrant global-status | grep running | awk '{print $1}'); do 
  DIR=$(vagrant global-status | grep running | awk '{print $5}')
  cd "$DIR";
  OUT=$(vagrant halt);
  echo "attempted to halt $i: $OUT"
done
0

Here is a compilation of working one-liners as of September 2020. Thanks to all the previous authors for inspiration.

Halt all vagrant boxes

Version 1 (shorter)

vagrant global-status | awk '/virtualbox running/{ print $1 }' | xargs vagrant halt

Version 2 (more robust)

macOS/BSD compatible:

vagrant global-status --machine-readable | cut -d, -f5 | grep -B3 running | egrep -o '[0-9a-f]{7}' | xargs -n 1 -- vagrant halt

GNU compaible:

vagrant global-status --machine-readable | cut -d, -f5 | grep -B3 running | egrep -o '[0-9a-f]{7}' | xargs -r -d '\n' -n 1 -- vagrant halt

Alias

You can add this to an alias for quick execution. Add this code to ~/.bashrc, ~/.zshrc or your shell's equivalent.

macOS/BSD example:

alias vagrantHaltAll="vagrant global-status --machine-readable | cut -d, -f5 | grep -B3 running | egrep -o '[0-9a-f]{7}' | xargs -n 1 -- vagrant halt"

# Usage:
vagrantHaltAll

Suspend all vagrant boxes

Or if you want to suspend any running machines, the syntax is easy:

vagrant suspend --all

I recommend using halt for web servers; it saves disk space and may be faster.

0

Because vagrant halt requires VM metadata (you run it in the directory with the file Vagrantfile & the directory .vagrant) it cannot be used easily to halt all VMs.

In some cases it is enough to halt all VBoxes:

myvbox-halt-all() {
  VBoxManage list runningvms |& tr -d '\r' | while read name uuid; do
    VBoxManage controlvm "$uuid" acpipowerbutton
  done
}
0

vagrant global-status | grep virtualbox | cut -c 1-9 | xargs vagrant suspend will suspend all the machines created by Vagrant.

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .