Vagrant Plugins for Less Mess

If you've ever used Vagrant to develop locally, you know its fantastic.  With a few plugins, it can be even more so.

A common scenario is to experiment with builds, try new servers, new boxes, and before you know it, your hosts file is filled with hundreds of sites pointing to 127.0.0.1

But there's a better way.

Vagrant Plugins

On my dev box, coldframe, I require two plugins for vagrant.  This is a big deal as I don't like a lot of requirements.  But these make life so much easier.  Lets see what both do and how to add them to your own Vagrantfile:

vagrant-hostsupdater

vagrant plugin install vagrant-hostsupdater

hostsupdater is an excellent utility that adds entries to your /etc/hosts file.  I'm not sure how support for Windows is, and if you're using Windows, well, I feel bad for you son...  If not, go ahead and install the plugin and you with a few lines in your Vagrantfile, you can make sure your hosts are pointed to the correct local ip for the box.  This allows you not only to develop with site_slug.deva instead of 192.168.3.123, but also to have multiple domains pointing to the same Vagrant box, to be routed by apache or nginx within.

Once the plugin is installed, you use it like so:

config.vm.network :private_network, ip: "192.168.3.10"
config.vm.hostname = "www.testing.de"
config.hostsupdater.aliases = ["alias.testing.de", "alias2.somedomain.com"]

Nicely, in the latest release, the plugin also removes the box's rules when you vagrant halt, vagrant destroy, or vagrant suspend.

All well and good, but I prefer to keep my boxes dynamic.  When I was initially building coldframe, I had one box per site.  That was not only heavy on my computer, but wasteful.  So I improved things to have just one box per team. Even so, I have a few teams I work with, so I have a number of boxes in flux.  So as not to have to worry about ip's again, I use this simple script to find the latest number in my series, and create any new box with the next number.  Have a look:

require 'ipaddr'
hostsfile = "/etc/hosts"
ip = File.read(hostsfile).scan(/192.168.42.\d{1,3}/).sort_by! {
    |ip| ip.split('.').map{
        |octet| octet.to_i
    }
}.last or ip = "192.168.42.1"
ips = [ip]
ips << IPAddr.new(ips.last).succ.to_s
latest_ip = ips.last
config.vm.network :private_network, ip: latest_ip
...

What this does is read through your hosts file, looking for any ip's that match your preferred string, mine is 192.168.42.xx , then finds the highest number from the .xx part (using .1 if there's none yet).  Then it adds one to that number, rebuilds the ip and sets it as the ip for the vm's network.  Easy as that.

On github at: https://github.com/cogitatio/vagrant-hostsupdater


vagrant-triggers

vagrant plugin install vagrant-triggers

This isn't necessary, but I use it to appeal to my sense of cleanliness.  In my ansible build script, I require certain roles to be installed into a vendor folder before things start.  This is because I don't want those in my repo, much like bower_components or node_modules.  But I don't want to have to install those manually, and really, I don't need them on my machine if the box isn't operating.  So, I use a bit of ruby in my Vagrantfile to run the command I would normally have to type out.  Like so:

ANSIBLE_PATH = 'ansible'
config.trigger.before :up do
    requirements = File.join(ANSIBLE_PATH, 'vendor/')
    if !File.exists?(requirements)
        system "ansible-galaxy install -r #{ANSIBLE_PATH}/requirements.yml -p #{ANSIBLE_PATH}/vendor/roles"
    end
end

config.trigger.after :destroy do
    system "rm -Rf #{ANSIBLE_PATH}/vendor"
end

And now, when I vagrant up, the roles are installed, when I destroy the box, they're removed.  If I wanted, I could do the same on halt or suspend, but I don't want to have to redownload them if I'm actively using the box.

On github at: https://github.com/emyl/vagrant-triggers


So, there you have it, a few helpers to make your development easier and less messy.  Do you use any similar plugins in your workflow?