Skip to main content
Hero Background Image

How To Streamline a Vagrant workflow with vagrant-exec

February 23, 2016

Tools of the Trade: vagrant-exec

Using Vagrant to manage virtual machines in a development workflow has become a life-saver and standard practice in many cases. Running a project server inside a virtual machine sidesteps the majority of the custom configuration that used to be required on a developer’s machine, but at the same time it introduces a new machine to connect to and manage.

The most common solution I’ve seen for running local commands on the virtual machine is to keep two terminal sessions running: one always connected into the virtual machine and another locally on the host machine. This solves the issue of running the frequent commands like drush and grunt that need to be run on the virtual machine, but as a developer with a heavily customized terminal I was always frustrated switching over to the SSH terminal where none of the local configuration I’m so used to (like shell aliases, custom prompts or colored output) is available.

Introducing vagrant-exec

I lived with this annoyance for a long time, but I’ve finally come across a Vagrant plugin to save the day: vagrant- exec.

The description of the project summed up exactly what I was looking for:

You will probably use the plugin if you don’t want to SSH into the box to execute commands simply because your machine environment is already configured (e.g. I use ZSH and TextMate bundles to run specs/features).

Once I tried it out, I was not disappointed. It delivered exactly what I was looking for and allowed for even more convenience with only minor configuration steps.

Setting it up

Assuming you already use Vagrant in your standard workflow, setting up the plugin and configuring it is a very straightforward process. Here’s how to do it:

Install the plugin:

    vagrant plugin install vagrant-exec

Configuring the plugin is well documented here, but setting it up in a local Vagrantfile to avoid forcing it into the project’s shared Vagrantfile was easy.

By default, whenever Vagrant runs a command it loads and merges a series of files for the full set of configuration to be used. By using this mechanism it’s easy to define your own local configuration without forcing it on anyone else who might need to run your projects locally.

Any of this configuration may still be added to a project’s specific Vagrantfile, but for this tutorial we’ll assume a preference to apply at least the general configuration across all of our Vagrant machines. To do this, we’ll need to create and add this configuration to a local file at ~/.vagrant.d/Vagrantfile:

# ~/.vagrant.d/Vagrantfile

Vagrant.configure('2') do |config|
  if Vagrant.has_plugin?("vagrant-exec")
    config.exec.commands '*', directory: '/vagrant'
    config.exec.commands 'drush', directory: '/vagrant/public'
    config.exec.commands 'cap', prepend: 'bundle exec'

This configuration is entirely related to the vagrant- exec plugin and is pretty intuitive to read through.

if Vagrant.has_plugin?("vagrant-exec")

This is a quick check to make sure the plugin is available before adding the configuration for it. For a personal setup this is less critical, but when applying it to a shared project configuration it is wise to add this check to avoid causing errors if someone else doesn’t have the plugin installed.

config.exec.commands '*', directory: '/vagrant'

This tells vagrant-exec to run all of its commands (any commands matching *) in the /vagrant directory. This is where all of our project files are mounted by default, but if your project files are mounted elsewhere you’ll want to use that path instead.

config.exec.commands 'drush', directory: '/vagrant/public'

This tells vagrant-exec to handle the drush command with some special configuration not common to every other command that might be run through vagrant-exec. In this case the directory where drush should be run from is overridden to /vagrant/public where we expect to find the Drupal root.

config.exec.commands 'cap', prepend: 'bundle exec'

Finally, this configuration is an example of prepending arguments to a command passing through vagrant-exec. In this case, calls to use Capistrano through the cap command should always run through Bundler to ensure the proper gems are used. With this configuration in place, any calls to cap will automatically expand to bundle exec cap and will run from the /vagrantdirectory because of the previous rule applying to all commands.

Using it

Using vagrant-exec is really simple. With the configuration in place and the virtual machine started, any commands may be run from the host machine using the format vagrant exec .... The arguments given after vagrant exec are then translated through the various configuration options it matches before it’s executed transparently over SSH on the virtual machine.

Bonus: Shortcut aliases

For my own convenience I set up the following shell aliases to cut down on typing the commands that I run repeatedly on the virtual machine:

# Vagrant management shortcuts  
alias vg='vagrant'  
alias vgp='vagrant provision'  
## The following require the vagrant-exec plugin  
alias ve='vagrant exec'  
alias vdr='vagrant exec drush'  
alias vgr='vagrant exec grunt'

Additional Resources
Decoupled Drupal 8 | Blog 
A First Look at Behavior Driven Development with Behat in Drupal | Blog 
Level Up Your Drush-Fu With Aliases That Work Across All Environments | Blog