Chef

Table Of Contents

About Templates

A cookbook template is an Embedded Ruby (ERB) template that is used to generate files based on the variables and logic contained within the template. Templates may contain Ruby expressions and statements and are a great way to manage configuration files across an organization. Use the template resource to add cookbook templates to recipes; place the corresponding Embedded Ruby (ERB) template in a cookbook’s /templates directory.

Note

The chef-client uses Erubis for templates, which is a fast, secure, and extensible implementation of embedded Ruby. Erubis should be familiar to members of the Ruby on Rails, Merb, or Puppet communities. For more information about Erubis, see: http://www.kuwata-lab.com/erubis/.

Requirements

To use a template, two things must happen:

  1. A template resource must be added to a recipe
  2. An Embedded Ruby (ERB) template must be added to a cookbook

For example, the following template file and template resource settings can be used to manage a configuration file named /etc/sudoers. Within a cookbook that uses sudo, the following resource could be added to recipes/default.rb:

template "/etc/sudoers" do
  source "sudoers.erb"
  mode 0440
  owner "root"
  group "root"
  variables({
     :sudoers_groups => node[:authorization][:sudo][:groups],
     :sudoers_users => node[:authorization][:sudo][:users]
  })
end

And then create a template called sudoers.erb and save it to templates/default/sudoers.erb:

#
# /etc/sudoers
#
# Generated by Chef for <%= node[:fqdn] %>
#

Defaults        !lecture,tty_tickets,!fqdn

# User privilege specification
root          ALL=(ALL) ALL

<% @sudoers_users.each do |user| -%>
<%= user %>   ALL=(ALL) <%= "NOPASSWD:" if @passwordless %>ALL
<% end -%>

# Members of the sysadmin group may gain root privileges
%sysadmin     ALL=(ALL) <%= "NOPASSWD:" if @passwordless %>ALL

<% @sudoers_groups.each do |group| -%>
# Members of the group '<%= group %>' may gain root privileges
%<%= group %> ALL=(ALL) <%= "NOPASSWD:" if @passwordless %>ALL
<% end -%>

And then set the default attributes in attributes/default.rb:

default["authorization"]["sudo"]["groups"] = [ "sysadmin","wheel","admin" ]
default["authorization"]["sudo"]["users"]  = [ "jerry","greg"]

Variables

A template is an Embedded Ruby (ERB) template. An Embedded Ruby (ERB) template allows Ruby code to be embedded inside a text file within specially formatted tags. Ruby code can be embedded using expressions and statements. An expression is delimited by <%= and %>. For example:

``<%= "my name is #{$ruby}" %>``

A statement is delimited by a modifier, such as if, elseif, and else. For example:

if false
   # this won't happen
elsif nil
   # this won't either
else
   # code here will run though
end

Using a Ruby expression is the most common approach for defining template variables because this is how all variables that are sent to a template are referenced. Whenever a template needs to use an each, if, or end, use a Ruby statement.

When a template is rendered, Ruby expressions and statements are evaluated by the chef-client. The variables listed in the resource’s variables parameter and the node object are evaluated. The chef-client then passes these variables to the template, where they will be accessible as instance variables within the template; the node object can be accessed just as if it were part of a recipe, using the same syntax.

For example, a simple template resource like this:

node[:fqdn] = "latte"
template "/tmp/foo" do
  source "foo.erb"
  variables({
    :x_men => "are keen"
  })
end

And a simple Embedded Ruby (ERB) template like this:

The node <%= node[:fqdn] %> thinks the x-men <%= @x_men %>

Would render something like:

The node latte thinks the x-men are keen

Even though this is a very simple example, the full capabilities of Ruby can be used to tackle even the most complex and demanding template requirements.

File Specificity

A cookbook will frequently be designed to work across many platforms and will often be required to distribute a specific file to a specific platform. A cookbook can be designed to support distributing files across platforms, but ensuring that the right file ends up on each system.

The pattern for file specificity is as follows:

  1. host-node[:fqdn]
  2. node[:platform]-node[:platform_version]
  3. node[:platform]-version_components: The version string is split on decimals and searched from greatest specificity to least; for example, if the location from the last rule was centos-5.7.1, then centos-5.7 and centos-5 would also be searched.
  4. node[:platform]
  5. default

A cookbook may have a /templates directory structure like this:

templates/
  windows-6.2
  windows-6.1
  windows-6.0
  windows
  default

and a resource that looks something like the following:

template "C:\path\to\file\text_file.txt" do
  source "text_file.txt"
  mode 0755
  owner "root"
  group "root"
end

This resource would be matched in the same order as the /templates directory structure. For a node named “host-node-desktop” that is running Windows 7, the second item would be the matching item and the location:

/templates
  windows-6.2/text_file.txt
  windows-6.1/text_file.txt
  windows-6.0/text_file.txt
  windows/text_file.txt
  default/text_file.txt

Host Notation

The naming of folders within cookbook directories must literally match the host notation used for template specificity matching. For example, if a host is named foo.example.com, then the folder must be named host-foo.example.com.

Transfer Frequency

The chef-client caches a template when it is first requested. On each subsequent request for that template, the chef-client compares that request to the template located on the Chef server. If the templates are the same, no transfer occurs.

Partial Templates

A template can be built in a way that allows it to contain references to one (or more) smaller template files. (These smaller template files are also referred to as partials.) A partial can be referenced from a template file in one of the following ways:

  • By using the Ruby render method in the template file
  • By using the template resource and the variables parameter.

render Method

Use the render method in a template to reference a partial template file with the following syntax:

<%= render "partial_name.txt.erb", :option => {} %>

where partial_name.txt.erb is the name of the partial template file and :option is one (or more) of the following options:

Option Description
:cookbook By default, a partial template file is assumed to be located in the cookbook that contains the top-level template. Use this option to specify the path to a different cookbook
:local Indicates that the name of the partial template file should be interpreted as a path to a file in the local file system or looked up in a cookbook using the normal rules for template files. Set to true to interpret as a path to a file in the local file system and to false to use the normal rules for template files
:source By default, a partial template file is identified by its file name. Use this option to specify a different name or a local path to use (instead of the name of the partial template file)
:variables A hash of variable_name => value that will be made available to the partial template file. When this option is used, any variables that are defined in the top-level template that are required by the partial template file must have them defined explicitly using this option

For example:

<%= render "simple.txt.erb", :variables => {:user => Etc.getlogin }, :local => true %>