# Using Variables in a Hiera Hierachy

I am looking for a way to assign roles to a group of servers easily. These values are arbitrary and facter cannot determine them. This is my current hiera.yaml:

---
:backends:
- yaml

:yaml:

:hierarchy:
- "servers/%{::fqdn}"
- "roles/%{::role}"
- common

:logger: console

:merge_behavior: deeper


The idea I had was to use something like site.pp to create these roles like so:

node 'puppet.prod.dc.mycompany.net' {
$role = "puppetmaster" }  However this does not seem to work as expected. Is there anyway to approximate something similar? edit retag close merge delete ## 4 Answers Sort by » oldest newest most voted You should not rely on node-level variables at all. I am not sure where I read or heard this but support for such variables might go away in future Puppet releases. This only leaves top-scope variables and proper facts, which is what you should be using. Why not simply create a custom, external fact named role, making use of Facter's support for external facts? Something like this: # mkdir -p /etc/facter/facts.d # echo "role=puppetmaster" > /etc/facter/facts.d/role.txt  Then facter -p role will return "puppetmaster" on that node. Of course this is impractical to do manually on multiple nodes so you either need to find a way to set up such facts at provisioning time, or with Puppet and a file resource, or "out of band", possibly using MCollective, Capistrano, or even parallel SSH. That said, you seem to be making life for yourself more difficult by trying it this way. We assign roles to nodes this way: Our /etc/puppet/environments/production/manifests/site.pp only contains this: node default {$role = hiera('role')
include $role }  Then in the data file for a node like db01.example.com: $ cat /etc/puppet/hieradata/production/nodes/db01.example.com.yaml
---
role: '::role::postgresql_server'
...


Or for our Puppet masters:

$cat /etc/puppet/hieradata/production/nodes/puppet02.example.com.yaml --- role: '::role::puppet_master_worker' ...  Or a default role for nodes that don't have their own data file: $ cat /etc/puppet/hieradata/production/common.yaml
---
role: '::role::standard_server'


This makes assigning roles to nodes very easy and it can all be done from Hiera by editing Yaml files.

The role classes are set up pretty much exactly like documented and explained in any of the following resources:

• http://garylarizza.com/blog/2014/02/17/puppet-workflow-part-1/
• http://garylarizza.com/blog/2014/02/17/puppet-workflow-part-2/
more

I ended up being able to write a custom fact to define the role as a colleague decided to inform me our host names in the new environment would be predictable. Your info certainly helped me out though - thanks.

( 2014-06-26 09:25:39 -0500 )edit

If you want to use "role" or other "runtime" defined variables in hiera, you can define them in the ENC. We use both "role" and "app_tier" in our hiera.yaml, both defined in "TheForeman" for the hostgroup, but I am sure that PE would work the same.

more

A slight variant on daff's solution would be to add this to your site manifest:

hiera_include('classes', [])


This saves the step of assigning the hiera lookup to a variable and then include $role. The empty array ensures that hiera_include does not fail when no hiera response is found, and also that pre-commit checks don't flag your site manifest as invalid (because pre-commit checks usually have no valid hiera source). more I tried Daff's solution for a while, but eventually ran into problems with hierarchy flexibility. Writing a fact based on hostname ended up being the solution that PuppetLabs support had me do and it has worked wonderfully. Here's my code for {module_name}\lib\facter\application_tier.rb: require 'facter' Facter.add(:application_tier) do setcode do location = case Facter.value(:hostname) when /dev(\d|)$/ then 'development'
when /test(\d|)\$/ then 'test'
else 'production'
end
end
end


You can place the fact in any module, and it will be applied via pluginsync. If you're using Vagrant without a Puppet Master, like I am, then you'll need to define FACTERLIB too. I use a shell provisioner with the following line in it:

echo 'export FACTERLIB="/vagrant/modules/roles/lib/facter"' > /etc/profile.d/facterlib.sh


One tip is to be sure to use the hostname, and not the FQDN. The FQDN fact takes forever to run, while hostname is very fast.

My hiera.yaml file then looks like this:

:hierarchy:
- "vagrant"
- "node/%{::hostname}"
- "tier/%{::application_tier}"
- "secrets"
- "common"

more