Puppet variables not always working
I want to apply the "DRY" (don't repeat yourself) principle in the nodes.pp by grouping machines, e.g. RH5 and RH6 machines instead of adding multiple lines of includes for all RH5 and RH6 servers.
Puppet on the tst-01 works fine when using:
node "tst-01" inherits basenode {
But it breaks when I try to organize servers into groups with this configuration:
node "tst-01" inherits redhat6server {
The error with "inherits redhat6server" is:
err: Could not retrieve catalog; skipping run
[root@tst-01 ~]# puppet agent --test
err: Could not retrieve catalog from remote server: Error 400 on SERVER: Failed to parse template ldap/access.conf: Could not find value for 'netgroup' at 124:/etc/puppet/modules/ldap/templates/access.conf at /etc/puppet/modules/ldap/manifests/init.pp:82 on node tst-01.tst.it.test.com
warning: Not using cache on failed catalog
err: Could not retrieve catalog; skipping run
This is the access.conf file, that works fine if inherits is set to "inherits basenode".
[root@puppet]# grep -v "#" /etc/puppet/modules/ldap/templates/access.conf
+ : root : LOCAL
+ : @<%= netgroup %> : ALL
- : ALL : ALL
[root@puppet]#
This is the configuration in /etc/puppet/manifests/nodes.pp.
# Basenode configuration
node "basenode" {
include resolv_conf
include sshd
include ntpd
include motd
}
# Groups
node "redhat6server" inherits basenode {
include ldap_auth
}
# Testservers
node "tst-01" inherits redhat6server {
$netgroup = tst-01
}
It probably fails because inheritance occurs before the $netgroup
variable is evaluated, and therefore, catalog compilation fails. However, using this method to separate code from data has limitations and should be avoided.
I have refactored my puppet code to use hierarchical data for databindings and to achieve the same effect of grouping similar nodes. A simplified example, assuming you only need to group RHEL servers, would be:
-
The hierarchical data will be retrieved using the following definition:
hiera.yaml --- :backends: - yaml :hierarchy: - %{::operatingsystem} - %{::hostname} - common :yaml: :datadir: /etc/puppet/hieradata/
Both
operatingsystem
andhostname
arefacts
. Hiera will attempt data resolution in this order for a Red Hat system whose hostname issome-rhel-hostname
:- RedHat.yaml
- some-rhel-hostname.yaml
- common.yaml
-
This expects the following directory structure and files:
/etc/puppet/hieradata/ ├── common.yaml ├── RedHat.yaml ├── some-rhel-hostname.yaml └── tst-01.yaml
-
The contents of the example yaml files:
common.yaml --- classes: - resolv_conf - sshd - ntpd - motp RedHat.yaml --- classes: - ladp_auth some-rhel6-hostname.yaml --- classes: - this_host_only ldap_auth::netgroup: foo-bar tst-01.yaml --- ldap_auth::netgroup: tst-01 nodes.pp default { hiera_include(classes) }
Note the use of the
hiera_include
function, that will return an array of all the values for each node (those fromcommon.yaml
and those comming from the hierarchy resolution, i.e.,some-rhel-hostname
will include all classes fromcommon.yaml
plusldap_auth
fromRedHat.yaml
andthis_host_only
from its own yaml file).How to use databindings in your modules is done differently depending on which version of
puppet
you are using. Check here for pointers.