Scott's Weblog The weblog of an IT pro specializing in virtualization, networking, open source, and cloud computing

An Improved Way to use YAML with Vagrant

In this post, I’d like to share with you an improved way to use YAML with Vagrant. I first discussed the use of YAML with Vagrant in a post on simplifying multi-machine Vagrant environments, where I simply factored out variable data into an external YAML file. The original approach I described had (at least) one significant drawback, though, which this new approach adddresses.

(By the way, this “improved” way is probably just a matter of better coding. I’m not an expert with Ruby, so Ruby experts may look at this and find it to be quite obvious.)

Here’s the original snippet of a Vagrantfile that I shared in that first Vagrant/YAML post:

# -*- mode: ruby -*-
# # vi: set ft=ruby :
# Specify minimum Vagrant version and Vagrant API version
Vagrant.require_version ">= 1.6.0"
# Require YAML module
require 'yaml'
# Read YAML file with box details
servers = YAML.load_file('servers.yaml')
# Create boxes
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  # Iterate through entries in YAML file
  servers.each do |servers|
    config.vm.define servers["name"] do |srv| = servers["box"] "private_network", ip: servers["ip"]
      srv.vm.provider :virtualbox do |vb| = servers["name"]
        vb.memory = servers["ram"]

The “magic,” so to speak, comes from the servers = YAML.load_file('servers.yml') line, where Vagrant loads the information from the external YAML file named “servers.yml” into an array. The servers.each loop later iterates through the entries in the array, creating and configuring a VM for each record in the YAML file.

This works fabulously well, with one exception: you can’t use vagrant commands outside of the directory where the Vagrantfile and the YAML file are stored.

What do I mean by this? You may be aware that once a Vagrant environment has been created (you’ve run vagrant up on the environment and haven’t yet run vagrant destroy), then you can run this command from any directory to get a list of created Vagrant environments:

vagrant global-status

The output of that command will look something like this (along with some other text after the listing):

id       name    provider      state       directory
8fa3dfc  trusty  vmware_fusion not running /home/slowe/vagrant/trusty

Using the value in the id column (8fa3dfc, in this example), you could run various Vagrant commands, like vagrant up 8fa3dfc or vagrant halt 8fa3dfc, even when you aren’t in the directory where the Vagrant environment was defined. This is a pretty handy feature, but it doesn’t work if you use the Vagrant + YAML approach listed above. It errors out, indicating that it can’t find the referenced YAML file (servers.yml, for example).

The fix for this is to modify the line where Vagrant loads the data from the YAML file. This is the original line, which produces the inability to use global Vagrant commands:

servers = YAML.load_file('servers.yaml')

The fixed/corrected/improved version looks like this:

servers = YAML.load_file(File.join(File.dirname(__FILE__), 'servers.yml'))

The difference here is that the second command creates the full path to the referenced YAML file (by determining the directory name of the Vagrantfile, referred to by the special __FILE__ variable, and then appending the name of the YAML file itself).

With this approach, you’re now able to use global Vagrant commands from any directory without an error. I’ve recently modified all the Vagrant environments in my GitHub “learning-tools” repository to use this new approach, so that should make those environments a bit easier to use.

Be social and share this post!