All of your source code is in your version control system, but what about your build environment?
If your development machine crashed, would you be able to recreate your build environment?
Do you dread the thought of bringing on another developer?
You won't have these issues if you use Vagrant to create portable, reproducible build environments.
Vagrant is essentially a wrapper for VirtualBox to make it easier to configure, manage and interact with virtual machines. We can use these virtual machines to create build environments which can be easily saved and consistently reproduced.
In a previous article, I created a C project example for which the build system had a few dependencies (i.e. Ruby and Rake).
With Vagrant -- instead of giving you a bunch of instructions to install and configure the project dependencies -- I can just give you a Vagrantfile and a provisioning script. And, it doesn't matter what OS you're running. Here's how:
First, you'll need to install Vagrant and VirtualBox. Vagrant also uses ssh. If you're on Windows and don't alreay have it, Vagrant recommends to install it with Cygwin, MinGW or Git.
Then:
- Download my Vagrantfile and provisioning script to some folder on your machine (or clone my GitHub repo). Don't let your system rename the files or add extensions, the should be named
Vagrantfile
andprovision.sh
. - Open a terminal/shell and run
vagrant up
from the folder where you downloaded the files. Note that the first time we bring up the machine it will take a little while. This is because Vagrant needs to do an initial download of the entire base box image and run the provisioning script. - You now have a virtual build machine running. Use
vagant ssh
to log in to it. You are now in the/vagrant
folder. - The example project was downloaded to
/vagrant/try-tdd-with-ceedling
. Switch to this folder withcd /vagrant/try-tdd-with-ceedling
. - Run
rake test:all
to run the project unit tests from the example.
That's it. That was pretty easy, right? Lets look at what we did there in a little more detail.
Vagrant uses a Vagrantfile to define how each virtual machine is configured. This is plain text file which is easily stored in version control. Here's ours:
# -*- mode: ruby -*-
# vi: set ft=ruby :
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
# Use Ubuntu 14.04 64-bit.
config.vm.box = "ubuntu/trusty64"
# Run the provisioning script.
config.vm.provision :shell, path: "provision.sh"
# Fix for VirtualBox and Ubuntu losing internet connection.
config.vm.provider "virtualbox" do |v|
v.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
v.customize ["modifyvm", :id, "--natdnsproxy1", "on"]
end
end
Vagrant configurations are specified by starting with a "base" Vagrant box. This is the starting point for the system and generally represents a clean install of some operating system. In this example we're using the ubuntu/trusty64
base box, which is Ubuntu 14.04 (64-bit).
Then this Vagrantfile specifies that we should run the provision.sh
script to provision the box. Provisioning is an operation executed by Vagrant from inside the virtual machine after it is first created. Ours is just a bash script that installs our build environment dependencies:
#!/bin/bash
# This is the provisioning script which is executed when the virtual machine is first created.
# Here is where we install all of the dependencies for our project.
# Configure the machine to switch us to the shared folder immediately upon login.
printf 'cd /vagrant' >> /home/vagrant/.bashrc
# Rake is a dependency for projects built with Ceedling.
apt-get -y install rake
# Some other tools we might want to use in the future.
# apt-get -y install doxygen
# apt-get -y install splint
# apt-get -y install pandoc
# Developer tools.
apt-get -y install git
# apt-get -y install subversion
# Get the test repository used in this example.
cd /vagrant
git clone https://github.com/ElectronVector/try-tdd-with-ceedling.git
Ruby is included with this Ubuntu image, so the only critical dependency is Rake. It gets installed with the command apt-get -y install rake
.
Git is installed for source code revision control, and there are a few other tools referenced that might be useful in the future.
The last thing the script does is to pull down my example code from GitHub.
Also note that Vagrant creates a shared folder between your host and the virtual machine. By default, the virtual machine /vagrant
folder is shared with the host folder containing the Vagrantfile. So, you should be able to see the try-tdd-with-ceedling
source from your host.
This means that you can build with Vagrant inside the virtual machine and still use your favorite editor on your host machine.
There are other Vagrant commands we can use as well. To exit the ssh session, just use exit
. Use vagrant suspend
to suspend the machine or vagrant halt
to shut it down. The same vagrant up
starts it again from either state.
In summary, Vagrant is a way automate the creation of a build environment. We take our build environment and define it in a way that we can easily distribute it to anyone... or save it for just in case.
With a little effort up front, it's just one less thing we'll have to worry about during development.
For more information, see the Vagrant "getting started" documentationn.