Configuring Hiera datadir Path in Vagrant-Puppet Environments: Relative Path Solutions


2 views

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"