People often ask me how do you iterate through an array in Puppet when you can do it easily in a template ?
Puppet uses declarative programming and is a domain specific language therefore it cannot do loops which you are probably used to doing in most languages.
Define iteration
For a while it has been possible to sort of iterate in Puppet manifests by using a define resource:
1 2 3 |
define foo ( $bar ) { notice("${bar} says hello to ${name}") } |
1 2 3 |
foo { ['tom', 'bob'] : bar => 'jen', } |
Which produces:
1 2 3 4 5 |
puppet apply define.pp Notice: Scope(Foo[tom]): jen says hello to tom Notice: Scope(Foo[bob]): jen says hello to bob Notice: Compiled catalog for blog.bluemalkin.net in environment production in 0.02 seconds Notice: Finished catalog run in 0.04 seconds |
The name of the foo resource takes an array where each element calls the foo define.
Define resources are commonly used for apache configurations for example (see http://docs.puppetlabs.com/learning/definedtypes.html).
However since every resource name must be unique, it is impossible to call a define twice, using the same values in the array.
Also if you want to iterate through an array inside a define, you’d have to call another define which can get messy.
Future Parser
Since Puppet version 3.2 experimental features are available http://docs.puppetlabs.com/puppet/3/reference/experiments_overview.html and it includes an array iteration feature !
Important note:
The future parser is an experimental feature and is not officially supported by Puppet Labs. It is not recommended for production environments, so enable it at your own risk and ensure you have gone through the new language restrictions at http://docs.puppetlabs.com/puppet/3/reference/experiments_future.html#new-language-restrictions
The non-capitalized variables compatibility and using variables in templates without @ prefixing (or scope.lookupvar) are two areas that need attention since there are quite a few Puppet Forge modules that still use them.
To enable the future parser on your puppetmaster, edit /etc/puppet/puppet.conf and add:
1 2 3 |
[main] … parser = future |
Restart the puppetmaster and check the syslog for any issues compiling catalogues for nodes. This is where you can find future parser compatibility issues.
To test array iteration with a puppet apply, it’s as simple as:
1 2 |
$names = ['tom','bob'] each($names) |$value| { notice "Hi ${value}" } |
1 2 3 4 5 |
puppet apply --parser=future iterate.pp Notice: Scope(Class[main]): Hi tom Notice: Scope(Class[main]): Hi bob Notice: Compiled catalog for blog.bluemalkin.net in environment production in 0.30 seconds Notice: Finished catalog run in 0.04 seconds |
If you’re coding your Puppet modules in Geppetto, set the “Puppet target version” to “future” in the Preferences, to avoid the bad syntax highlighting.
Happy iterating !
Hi
According to puppetlab’s doc, parser=future is supposed to work with puppet version 3.3 or higher. Your doc looks great too. I’m on 3.7.1 which falls under https://docs.puppetlabs.com/puppet/latest/reference/experiments_future.html, but it has not worked for me at all. Interestingly it works fine if I run just CLI puppet apply –parser=future xyz.pp. Once I enable it on my puppet masters, clients just keep getting ‘Error: Could not retrieve catalog from remote server: Error 400 on SERVER: Could not parse for environment production: Do not add methods to model classes directly, add them to the ClassModule instead on node xxxxxx’. The ruby version on both masters and clients is ruby-1.8.7.352-13.el6.x86_64.
Any idea know why?
Hi Larry,
Enabling the future parser can break quite a few things, as it requires all the Puppet code to adhere to the language restrictions (see https://docs.puppetlabs.com/puppet/latest/reference/experiments_future.html#new-language-restrictions ).
The best way to check that the new language restrictions are compliant, is to view the syslog on the Puppetmaster. Then your catalogues should compile.