Make Puppet, Vagrant and Hiera play together

Testing your Puppet code locally with Vagrant is great. Fast and clean development and testing of your code can be done in this comfortable way. The base setup is easy:

  1. Download and install Vagrant
  2. Download and install VirtualBox
  3. Download and install Puppet

So far, so good. When it comes to Hiera, I was struggling around with a setup that actually uses Hiera data. I couldn’t convince Vagrant to notice my Hiera configuration. And so none of my keys and values inside my YAML files found their way into my Puppet manifests. vagrant provision puppet_dev  always failed with this error:

==> puppet_dev: Error: Could not find data item backuppc::key in any Hiera data file and no default supplied at /tmp/vagrant-puppet/modules-7de7a4fc15d45b89f16013b5dc73de0e/backuppc/manifests/init.pp:7 on node puppet-dev

Installation and configuration of Hiera seems to be very easy and straight forward. Everything starts with an hiera.yaml and one specialty with :datadir: Use two different hiera.yaml files for Vagrant and for real life Puppet provisioning on your servers. In Vagrant use a relative path to your hiera yaml files. In real life use a absolute path.

---

:backends:
  - yaml

:logger: console

:yaml:
   :datadir: hiera

:hierarchy:
  - "%{::fqdn}"
  - "%{::hostname}"
  - common

Create a datadir and place a common.yaml file into it. My filesystem structure looks like this:

├── Gemfile
├── Rakefile
├── Vagrantfile
├── hiera
│   └── common.yaml
├── hiera.yaml
├── manifests
│   └── site.pp
├── modules
│   ├── module1
│   ├── module2
│   └── vendor
└── puppet.conf

All we need now is a proper Vagrantfile to make vagrant provision puppet_dev work. Vagrant’s Hiera documentation (scroll down to the bottom) tells us how to change the Vagrantfile. Unfortunately this is not the whole truth. After an extensive Google search, I found a working configuration which is as follows.

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/trusty64"
  config.vm.synced_folder "hiera", "/tmp/vagrant-puppet/hiera"

  config.vm.provision :puppet, :options => ["--yamldir /hiera"] do |puppet|
    puppet.manifests_path    = "manifests"
    puppet.manifest_file     = "site.pp"
    puppet.module_path       = ["modules", "modules/vendor"]
    puppet.hiera_config_path = "hiera.yaml"
    puppet.working_directory = "/tmp/vagrant-puppet"
  end

  config.vm.provider :virtualbox do |vb|
    vb.customize [
      "modifyvm", :id,
      "--memory", "512",
    ]
  end

  config.vm.define :puppet_dev do |box|
    box.vm.network :private_network, ip: '192.168.90.10'
    box.vm.hostname = "puppet-dev"
  end
end

The interesting part lies in lines 3 and 5. Sync your Hiera datadir to Vagrant’s temporary directory so everything is on the spot and tell the Puppet provisioner explicitly to use a yamldir.

As a side note, I needed to quote an absolute path to :datadir: inside hiera.yaml. Otherwise my puppetmaster and by association my puppet agent (client) ignored my Hiera data as well.