Using Puppet Templates
Puppet supports templates and templating via ERB, which is part of the Ruby standard library and is used for many other projects including Ruby on Rails. Templates allow you to manage the content of template files, for example configuration files that cannot yet be managed as a Puppet type.
Evaluating templates
Templates are evaluated via a simple function:
$value = template("mytemplate.erb")
You can specify the full path to your template, or you can put all your templates in Puppet’s templatedir, which usually defaults to /var/puppet/templates (you can find out what it is on your system by running puppet —configprint templatedir).
Templates are always evaluated by the parser, not by the client. This means that if you are using puppetmasterd, then the templates only need to be on the server, and you never need to download them to the client. There’s no difference to the client between using a template and specifying all of the text as a string. This also means that any client-specific variables (facts) are learned first by puppetmasterd during the client start-up phase, then those variables are available for substitution within templates.
Using templates
Templating is pretty simple: You can directly reference any variables within your template that are defined within the enclosing scope.
This is especially useful for generating complete files; here is how I generate the Apache configuration for my Trac sites:
define tracsite($cgidir, $tracdir) {
file { "trac-$name":
path => "/etc/apache2/trac/$name.conf",
owner => root,
group => root,
mode => 644,
require => File[apacheconf],
content => template("tracsite.erb"),
notify => Service[apache2]
}
symlink { "tracsym-$name":
path => "$cgidir/$name.cgi",
ensure => "/usr/share/trac/cgi-bin/trac.cgi"
}
}
And then here’s my template:
<Location "/cgi-bin/ <%= name %>.cgi">
SetEnv TRAC_ENV "/export/svn/trac/<%= name %>"
</Location>
# You need something like this to authenticate users
<Location "/cgi-bin/<%= name %>.cgi/login">
AuthType Basic
AuthName "Trac"
AuthUserFile /etc/apache2/auth/svn
Require valid-user
</Location>
You can see that I put each Trac configuration into a separate file, and then I just tell Apache to load all of these files:
Include /etc/apache2/trac/[^.#]*
The above template is quite simple, in that it only uses the Puppet-defined name variable, but it provides a clean separation between the format of the configuration file and how I generate it.
Combining templates
You can also put several templates together by specifying
template(/path/to/template1,/path/to/template2)
Iteration
Puppet’s templates also support iteration. If the variable you are accessing is an array, you can iterate over it. Given Puppet code like this:
$values = [val1, val2, otherval]
You could have a template like this:
<% values.each do |val| -%>
Some stuff with <%= val %>
<% end -%>
This would produce:
Some stuff with val1
Some stuff with val2
Some stuff with otherval
Note that normally, ERB template lines that just have code on them would get translated into blank lines. To prevent this, we use the close tag –%> instead of %>.
Internally, Puppet’s values get translated to real Ruby values, including true and false, so you can be pretty confident that variables will behave as you might expect.
Conditionals
The ERB templating supports conditionals. Such a construct:
<% if broadcast != "NONE" %> broadcast <%= broadcast %> <% end %>
is a quick and easy way to conditionally put content in templates.
Templates and variables
You can also use templates to create variables not just file content.
myvariable = template('/var/puppet/template/myvar')
Undefined variables
You may try to use a undefined variable in a template. Puppet can handle this.
<% if has_variable?("myvar") then %>
myvar has <%= myvar %> value
<% end %>
Out of scope variables
You can access out of scope variables explicitly with the lookupvar function, similar to the use of variables in Writing Your Own Functions . For example:
<%= scope.lookupvar('apache::user') %>
Access to defined tags and classes
Starting with Puppet version 0.24.6, it is possible from a template to get the list of defined classes, the list of tags in the current scope and the list of all tags as ruby arrays. For example:
This snippet will print all the tags defined in the current scope.
<% tags.each do |tag| -%>
The tag <%= tag %> is part of the current scope
<% end -%>
This snippet will print all the defined tags in the catalog
<% all_tags.each do |tag| -%>
The tag <%= tag %> is defined
<% end -%>
And this snippet will print all the defined class in the catalog
<% classes.each do |klass| -%>
The class <%= klass %> is defined
<% end -%>
Functions in Templates
Inside templates you have access to a scope object. All of the functions that you can access in the puppet manifests can be accessed via that scope object, although not via the same name. Prepend “function_” to the beginning of the function name. For example, including one template inside another:
<%= scope.function_template("template2.erb") %>
Syntax Checking
ERB files are easy to syntax check. For a file mytemplate.erb, run
erb -x -T '-' mytemplate.erb | ruby -c
The trim option specified corresponds to what Puppet uses.