When working with Vagrant and Puppet integration, Hiera's datadir configuration becomes particularly tricky due to the dynamic nature of mounted directories. The standard relative path approach fails because Vagrant mounts your project directories at temporary paths like /tmp/vagrant-puppet-2
during provisioning.
Here are three proven methods to handle the datadir configuration:
1. Absolute Path Resolution
The most reliable approach is to use an absolute path constructed from environment variables:
# hiera.yaml updated version
:yaml:
:datadir: "<%= File.expand_path('manifests/configuration', ENV['VAGRANT_PUPPET_DIR'] || '.') %>"
2. ERB Templating Solution
Create a dynamic hiera.yaml.erb template:
# puppet/templates/hiera.yaml.erb
:yaml:
:datadir: "<%= scope.lookupvar('::vagrant_puppet_dir') %>/manifests/configuration"
Then modify your Vagrantfile:
servername.vm.provision :puppet do |puppet|
puppet.template_dir = "puppet/templates"
# ... other configuration
end
3. Environment Variable Approach
Set the base path in Vagrantfile:
puppet.facter = {
"vagrant_puppet_dir" => "/tmp/vagrant-puppet-#{rand(100)}",
# ... other facts
}
Then in hiera.yaml:
:yaml:
:datadir: "/tmp/%{::vagrant_puppet_dir}/manifests/configuration"
For production environments, consider this enhanced structure:
# hiera.yaml
:yaml:
:datadir: "<%=
if File.exists?('/tmp/vagrant-puppet')
'/tmp/vagrant-puppet/manifests/configuration'
else
'/etc/puppetlabs/code/environments/%{environment}/hieradata'
end
%>"
Add this to your manifests for debugging:
notice("Hiera data directory: ${lookup('hiera_yaml_path')}")
notice("Current working directory: ${system::env('PWD')}")
When working with Puppet and Vagrant integration, one common pain point emerges around Hiera's :datadir:
configuration. The core issue stems from path relativity versus absolute paths during provisioning. Here's what's happening under the hood:
Vagrantfile → Puppet Provisioner → Hiera Lookup
├── Relative paths break when files are mounted
└── Absolute paths become environment-dependent
The most robust approach combines Vagrant's synced folders with Puppet's built-in variables:
# Updated hiera.yaml
:yaml:
:datadir: "<%= ::settings::confdir %>/configuration"
# Alternative for Puppet 4+:
# :datadir: "<%= lookup('puppet_environmentpath') %>/<%= ::environment %>/hieradata"
Here's a production-tested configuration that works across Vagrant and bare-metal:
# Vagrantfile excerpt
config.vm.provision :puppet do |puppet|
puppet.hiera_config_path = "puppet/hiera.yaml"
puppet.module_path = ["puppet/modules", "puppet/site-modules"]
# Critical for path resolution
puppet.temp_dir = "/tmp/vagrant-puppet"
puppet.working_directory = "/vagrant"
end
# hiera.yaml using Puppet's dynamic evaluation
:backends:
- yaml
:yaml:
:datadir: "<%= File.join(File.dirname(__FILE__), 'hieradata') %>"
:hierarchy:
- "nodes/%{::trusted.certname}"
- "env/%{::environment}"
- common
When troubleshooting, these commands reveal the actual paths being used:
# From inside the Vagrant VM:
puppet config print confdir
puppet master --configprint confdir
hiera -c /path/to/hiera.yaml myvar debug=true
For complex environments, consider this directory structure:
puppet/
├── environments/
│ ├── production/
│ │ ├── hieradata/
│ │ └── manifests/
│ └── vagrant/
│ ├── hieradata/
│ └── manifests/
└── hiera.yaml # Shared config
With corresponding Hiera configuration:
:yaml:
:datadir: "<%= File.join(environments, environment, 'hieradata') %>"
:hierarchy:
- "nodes/%{::fqdn}"
- "location/%{::datacenter}"
- "role/%{::role}"
- "common"