Search code examples
puppethiera

Assigning a class to a node based on host name via Hiera


I used to use Puppet a lot, from 0.x up to around the release of 1.0, then changed jobs but now I'm back at it. Hiera in Puppet is new to me (along with a ton of other stuff).

Am I correct in the understanding that it is basically impossible to assign classes to groups of nodes based on host name (or cert name) pattern matching with Hiera?

I used to, for example, assign ntp server classes if the host was something like "ntp1.foo.com". This is pretty easy with straight node definitions in site.pp, and I'm trying to move this concept into a Hiera-based world. I have Hiera assigning other classes and was hoping to lump all of those assignments into one place.

The only way I have found to do this to set a parameter via some non-Hiera means and using its value in Hiera to match a path. For example, in my enc script I export a parameter like this:

echo "parameters:"
if [ ... ]; do echo "  ntpRole: server; else echo "  ntpRole: client"; fi

and in Hiera I would do something like:

- "roles/ntp-%{ntpRole}"

I think one could also do this via a custom fact.

This works, but seems like a kludge. Is there a better/recommended alternative?

One problem with this is that every node must have a value (everything is assigned a ntp-something class). This works for NTP, since all the machines are either an NTP client or server, but for something existential it doesn't.

For example: a web server role. Some machines wouldn't be web servers, so I don't want to include that class, but for others I do, and I don't really want to have to maintain that in per-node files and don't really want to have empty *-none role classes everywhere (e.g. web-none vs. web-server). I want all machines named www*, or based on some other criteria, to load the roles/web class. Can this be done with Hiera?


Solution

  • If your roles have a relation to server facts, then you can use a custom fact to assign roles. Since you said you were formerly doing node classification based on server name, I will assume this is the route you want to go.

    # custom role fact
    require 'facter'
    
    Facter.add(:role) do
      case Facter.value(:hostname)
      when /ntp/ then 'ntp-server'
      when /www/ then 'web-server'
      else abort 'Hostname does not provide a role.'
      end
    end    
    

    You can then set up a hiera config like this:

    :hierarchy:
      - "nodes/%{::trusted.certname}"
      - role/%{role}
      - "common"
    

    Inside your role data files, you can provide an array of class names:

    # role/web-server.yaml
    classes:
      - web-server
    

    Inside your main manifest (normally $environment/manifest/site.pp:

    # if no classes array, traverse the else block
    if hiera('classes', false) {
      hiera_include('classes')
    }
    else {
      # logic for your 'none' situations since the classes array was not present
    }
    

    Check this for hiera_include information: https://docs.puppet.com/hiera/3.2/puppet.html#assigning-classes-to-nodes-with-hiera-hierainclude. Note it will merge in classes from your specific fqdn.yaml data files also.

    This will give you the functionality you are requesting and uses Hiera to include classes by node grouping/hostname.