Chef

Table Of Contents

template

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/.

A resource is a key part of a recipe that defines the actions that can be taken against a piece of the system. These actions are identified during each chef-client run as the resource collection is compiled. Once identified, each resource (in turn) is mapped to a provider, which then configures each piece of the system.

The template resource is used to manage file contents with an embedded Ruby (erb) template. This resource includes actions and attributes from the file resource. Template files managed by the template resource follow the same file specificity rules as the remote_file and file resources.

Syntax

The syntax for using the template resource in a recipe is as follows:

template "name" do
  source "template_name.erb"
  attribute "value" # see attributes section below
  ...
  action :action # see actions section below
end

where

  • template tells the chef-client to use the Chef::Provider::File::Template provider during the chef-client run
  • name is the path to the location in which a file will be created and the name of the file to be managed; for example: /var/www/html/index.html, where /var/www/html/ is the path to the location and index.html is the name of the file
  • source is the template file that will be used to create the file on the node, for example: index.html.erb; the template file is located in the /templates directory of a cookbook
  • attribute is zero (or more) of the attributes that are available for this resource
  • :action is the step that the resource will ask the provider to take during the chef-client run

Actions

This resource has the following actions:

Action Description
:create Default. Use to create a file.
:create_if_missing Use to create a file only if the file does not exist. (When the file exists, nothing happens.)
:delete Use to delete a file.
:touch Use to touch a file. This updates the access (atime) and file modification (mtime) times for a file. (This action may be used with this resource, but is typically only used with the file resource.)

Attributes

This resource has the following attributes:

Attribute Description
atomic_update Indicates whether atomic file updates are used on a per-resource basis. Set to true for atomic file updates. Set to false for non-atomic file updates. (This setting overrides file_atomic_update, which is a global setting found in the client.rb file.) Default value: true.
backup The number of backups to be kept. Set to false to prevent backups from being kept. Default value: 5.
cookbook The cookbook in which a file is located (if it is not located in the current cookbook). The default value is the current cookbook.
force_unlink Use to specify how the chef-client handles certain situations when the target file turns out not to be a file. For example, when a target file is actually a symlink. Set to true to have the chef-client delete the non-file target and replace it with the specified file. Set to false for the chef-client to raise an error. Default value: false.
group A string or ID that identifies the group owner by group name, including fully qualified group names such as domain\group or group@domain. If this value is not specified, existing groups will remain unchanged and new group assignments will use the default POSIX group (if available).
helper Use to define a helper method inline. For example: helper(:hello_world) { "hello world" } or helper(:app) { node["app"] } or helper(:app_conf) { |setting| node["app"][setting] }. Default value: {}.
helpers Use to define a helper module inline or in a library. For example, an inline module: helpers do, which is then followed by a block of Ruby code. And for a library module: helpers(MyHelperModule). Default value: [].
inherits Microsoft Windows only. Indicates that a file inherits rights from its parent. Default value: true.
local Use to load a template from a local path. By default, the chef-client loads templates from a cookbook’s /templates directory. When this attribute is set to true, use the source attribute specify the path to a template on the local node. Default value: false.
manage_symlink_source Indicates that the chef-client will detect and manage the source file for a symlink. Possible values: nil, true, or false. When this value is set to nil, the chef-client will manage a symlink’s source file and emit a warning. When this value is set to true, the chef-client will manage a symlink’s source file and not emit a warning. Default value: nil. The default value will be changed to false in a future version.
mode

The octal mode for a file. If mode is not specified and if the file already exists, the existing mode on the file is used. If mode is not specified, the file does not exist, and the :create action is specified, the chef-client will assume a mask value of 0777 and then apply the umask for the system on which the file will be created to the mask value. For example, if the umask on a system is 022, the chef-client would use the default value of 0755.

The behavior is different depending on the platform.

UNIX- and Linux-based systems: The octal mode that is passed to chmod. If the value is specified as a quoted string, it will work exactly as if the chmod command was passed. If the value is specified as an integer, prepend a zero (0) to the value to ensure it is interpreted as an octal number. For example, to assign read, write, and execute rights for all users, use 0777 or '777'; for the same rights, plus the sticky bit, use 01777 or '1777'.

Microsoft Windows: The octal mode that is translated into rights for Microsoft Windows security. Values up to 0777 are allowed (no sticky bits) and mean the same in Microsoft Windows as they do in UNIX, where 4 equals GENERIC_READ, 2 equals GENERIC_WRITE, and 1 equals GENERIC_EXECUTE. This attribute cannot be used to set :full_control. This attribute has no effect if not specified, but when this attribute and rights are both specified, the effects will be cumulative.

owner A string or ID that identifies the group owner by user name, including fully qualified user names such as domain\user or user@domain. If this value is not specified, existing owners will remain unchanged and new owner assignments will use the current user (when necessary).
path

The path to the file.

Microsoft Windows: A path that begins with a forward slash (/) will point to the root of the current working directory of the chef-client process. This path can vary from system to system. Therefore, using a path that begins with a forward slash (/) is not recommended.

provider Optional. Use to specify a provider by using its long name. For example: provider Chef::Provider::Long::Name. See the Providers section below for the list of providers available to this resource.
rights Microsoft Windows only. The permissions for users and groups in a Microsoft Windows environment. For example: rights <permissions>, <principal>, <options> where <permissions> specifies the rights granted to the principal, <principal> is the group or user name, and <options> is a Hash with one (or more) advanced rights options.
source The location of a template file. By default, the chef-client will look for a template file in the /templates directory of a cookbook. When the local attribute is set to true, use this attribute to specify path to a template on the local node. This attribute may also be used to distribute specific files to specific platforms (see the section “File Specificity”, below). Default value: the name of the resource block (see Syntax section above).
variables

|variables passed_to_template|

This attribute can also be used to reference a partial template file by using a Hash. For example:

template "/file/name.txt" do
  variables :partials => {
    "partial_name_1.txt.erb" => "message",
    "partial_name_2.txt.erb" => "message",
    "partial_name_3.txt.erb" => "message"
  },
end

where each of the partial template files can then be combined using normal Ruby template patterns within a template file, such as:

<% @partials.each do |partial, message| %>
  Here is <%= partial %>
<%= render partial, :variables => {:message => message} %>
<% end %>

Warning

For a machine on which SELinux is enabled, the chef-client will create files that correctly match the default policy settings only when the cookbook that defines the action also conforms to the same policy.

Atomic File Updates

Atomic updates are used with file-based resources to help ensure that file updates can be made when updating a binary or if disk space runs out.

Atomic updates are enabled by default. They can be managed globally using the file_atomic_update attribute in the client.rb file. They can be managed on a per-resource basis using the atomic_update attribute that is available with the cookbook_file, file, remote_file, and template resources.

Note

On certain platforms, and after a file has been moved into place, the chef-client may modify file permissions to support features specific to those platforms. On platforms with SELinux enabled, the chef-client will fix up the security contexts after a file has been moved into the correct location by running the restorecon command. On the Microsoft Windows platform, the chef-client will create files so that ACL inheritance works as expected.

Windows File Security

To support Microsoft Windows security, the template, file, remote_file, cookbook_file, directory, and remote_directory resources support the use of inheritance and access control lists (ACLs) within recipes.

Access Control Lists (ACLs)

The rights attribute can be used in a recipe to manage access control lists (ACLs), which allow permissions to be given to multiple users and groups. The syntax for the rights attribute is as follows:

rights permission, principal, option_type => value

where

  • permission is used to specify which rights will be granted to the principal. The possible values are: :read, :write, :full_control, :modify, and :deny. These permissions are cumulative. If :write is specified, then it includes :read. If :full_control is specified, then it includes both :write and :read. If :deny is specified, then the user or group will not have rights to the object. (For those who know the Microsoft Windows API: :read corresponds to GENERIC_READ and GENERIC_EXECUTE; :write corresponds to GENERIC_WRITE, GENERIC_READ, and GENERIC_EXECUTE; :full_control corresponds to GENERIC_ALL, which allows a user to change the owner and other metadata about a file.)

  • principal is used to specify a group or user name. This is identical to what is entered in the login box for Microsoft Windows, such as user_name, domain\user_name, or user_name@fully_qualified_domain_name. The chef-client does not need to know if a principal is a user or a group.

  • option_type is a hash that contains advanced rights options. For example, the rights to a directory that only applies to the first level of children might look something like: rights :write, "domain\group_name", :one_level_deep => true. Possible option types:

    Option Type Description
    :applies_to_children Use to specify how permissions are applied to children. Possible values: true to inherit both child directories and files; false to not inherit any child directories or files; :containers_only to inherit only child directories (and not files); :objects_only to recursively inherit files (and not child directories).
    :applies_to_self Indicates whether a permission is applied to the parent directory. Possible values: true to apply to the parent directory or file and its children; false to not apply only to child directories and files.
    :one_level_deep Indicates the depth to which permissions will be applied. Possible values: true to apply only to the first level of children; false to apply to all children.

The rights attribute can be used as many times as necessary; the chef-client will apply them to the file or directory as required. For example:

resource "x.txt" do
  rights :read, "Everyone"
  rights :write, "domain\group"
  rights :full_control, "group_name_or_user_name"
  rights :full_control, "user_name", :applies_to_children => true
end

or:

rights :read, ["Administrators","Everyone"]
rights :deny, ["Julian", "Lewis"]
rights :full_control, "Users", :applies_to_children => true
rights :write, "Sally", :applies_to_children => :containers_only, :applies_to_self => false, :one_level_deep => true

Some other important things to know when using the rights attribute:

  • Order independence. It doesn’t matter if rights :deny, ["Julian", "Lewis"] is placed before or after rights :read, ["Julian", "Lewis"], both Julian and Lewis will be unable to read the document.
  • Only inherited rights remain. All existing explicit rights on the object are removed and replaced.
  • If rights are not specified, nothing will be changed. The chef-client does not clear out the rights on a file or directory if rights are not specified.
  • Changing inherited rights can be expensive. Microsoft Windows will propagate rights to all children recursively due to inheritance. This is a normal aspect of Microsoft Windows, so consider the frequency with which this type of action is necessary and take steps to control this type of action if performance is the primary consideration.

Inheritance

By default, a file or directory inherits rights from its parent directory. Most of the time this is the preferred behavior, but sometimes it may be necessary to take steps to more specifically control rights. The inherits attribute can be used to specifically tell the chef-client to apply (or not apply) inherited rights from its parent directory.

For example, the following example specifies the rights for a directory:

directory 'C:\mordor' do
  rights :read, 'MORDOR\Minions'
  rights :full_control, 'MORDOR\Sauron'
end

and then the following example specifies how to use inheritance to deny access to the child directory:

directory 'C:\mordor\mount_doom' do
  rights :full_control, 'MORDOR\Sauron'
  inherits false # Sauron is the only person who should have any sort of access
end

If the :deny permission were to be used instead, something could slip through unless all users and groups were denied.

Another example also shows how to specify rights for a directory:

directory 'C:\mordor' do
  rights :read, 'MORDOR\Minions'
  rights :full_control, 'MORDOR\Sauron'
  rights :write, 'SHIRE\Frodo' # Who put that there I didn't put that there
end

but then not use the inherits attribute to deny those rights on a child directory:

directory 'C:\mordor\mount_doom' do
  rights :deny, 'MORDOR\Minions' # Oops, not specific enough
end

Because the inherits attribute is not specified, the chef-client will default it to true, which will ensure that security settings for existing files remain unchanged.

Providers

The following providers are available. Use the short name to call the provider from a recipe:

Long name Short name Notes
Chef::Provider::File::Template template The default provider for all platforms.

Using Templates

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"]

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

Helpers

A helper is a method or a module that can be used to extend a template. There are three approaches:

  • An inline helper method
  • An inline helper module
  • A cookbook library module

Use the helper attribute in a recipe to define an inline helper method. Use the helpers attribute to define an inline helper module or a cookbook library module.

Inline Methods

A template helper method is always defined inline on a per-resource basis. A simple example:

template "/path" do
  helper(:hello_world) { "hello world" }
end

Another way to define an inline helper method is to reference a node object so that repeated calls to one (or more) cookbook attributes can be done efficiently:

template "/path" do
  helper(:app) { node["app"] }
end

An inline helper method can also take arguments:

template "/path" do
  helper(:app_conf) { |setting| node["app"][setting] }
end

Once declared, a template can then use the helper methods to build a file. For example:

Say hello: <%= hello_world %>

Or:

node["app"]["listen_port"] is: <%= app["listen_port"] %>

Or:

node["app"]["log_location"] is: <%= app_conf("log_location") %>

Inline Modules

A template helper module can be defined inline on a per-resource basis. This approach can be useful when a template requires more complex information. For example:

template "/path" do
  helpers do

    def hello_world
      "hello world"
    end

    def app
      node["app"]
    end

    def app_conf(setting)
      node["app"][setting]
    end

  end
end

where the hello_world, app, and app_conf(setting) methods comprise the module that extends a template.

Library Modules

A template helper module can be defined in a library. This is useful when extensions need to be reused across recipes or to make it easier to manage code that would otherwise be defined inline on a per-recipe basis.

template "/path/to/template.erb" do
  helpers(MyHelperModule)
end

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.

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 %>

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.

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.

Examples

The following examples demonstrate various approaches for using resources in recipes. If you want to see examples of how Chef uses resources in recipes, take a closer look at the cookbooks that Chef authors and maintains: https://github.com/opscode-cookbooks.

Configure a file from a template

template "/tmp/config.conf" do
  source "config.conf.erb"
end

Configure a file from a local template

template "/tmp/config.conf" do
  local true
  source "/tmp/config.conf.erb"
end

Configure a file using a variable map

template "/tmp/config.conf" do
  source "config.conf.erb"
  variables(
    :config_var => node["configs"]["config_var"]
  )
end

Use the ``not_if`` condition

The following example shows how to use the not_if condition to create a file based on a template and using the presence of an attribute on the node to specify the condition:

template "/tmp/somefile" do
  mode 00644
  source "somefile.erb"
  not_if { node[:some_value] }
end

The following example shows how to use the not_if condition to create a file based on a template and then Ruby code to specify the condition:

template "/tmp/somefile" do
  mode 00644
  source "somefile.erb"
  not_if do
    File.exists?("/etc/passwd")
  end
end

The following example shows how to use the not_if condition to create a file based on a template and using a Ruby block (with curly braces) to specify the condition:

template "/tmp/somefile" do
  mode 00644
  source "somefile.erb"
  not_if {File.exists?("/etc/passwd")}
end

The following example shows how to use the not_if condition to create a file based on a template and using a string to specify the condition:

template "/tmp/somefile" do
  mode 00644
  source "somefile.erb"
  not_if "test -f /etc/passwd"
end

Use the ``only_if`` condition

The following example shows how to use the only_if condition to create a file based on a template and using the presence of an attribute on the node to specify the condition:

template "/tmp/somefile" do
  mode 00644
  source "somefile.erb"
  only_if { node[:some_value] }
end

The following example shows how to use the only_if condition to create a file based on a template, and then use Ruby to specify a condition:

template "/tmp/somefile" do
  mode 00644
  source "somefile.erb"
  only_if do ! File.exists?("/etc/passwd") end
end

The following example shows how to use the only_if condition to create a file based on a template and using a string to specify the condition:

template "/tmp/somefile" do
  mode 00644
  source "somefile.erb"
  only_if "test -f /etc/passwd"
end

Use a whitespace array (``%w``)

The following example shows how to use a Ruby whitespace array to define a list of configuration tools, and then use that list of tools within the template resource to ensure that all of these configuration tools are using the same RSA key:

%w{openssl.cnf pkitool vars Rakefile}.each do |f|
  template "/etc/openvpn/easy-rsa/#{f}" do
    source "#{f}.erb"
    owner "root"
    group "root"
    mode 0755
  end
end

Use a relative path

template "#{ENV['HOME']}/chef-getting-started.txt" do
  source "chef-getting-started.txt.erb"
  mode 00644
end

Delay notifications

template "/etc/nagios3/configures-nagios.conf" do
  # other parameters
  notifies :run, "execute[test-nagios-config]", :delayed
end

Notify immediately

By default, notifications are :delayed, that is they are queued up as they are triggered, and then executed at the very end of a chef-client run. To run an action immediately, use :immediately:

template "/etc/nagios3/configures-nagios.conf" do
  # other parameters
  notifies :run, "execute[test-nagios-config]", :immediately
end

and then the chef-client would immediately run the following:

execute "test-nagios-config" do
  command "nagios3 --verify-config"
  action :nothing
end

Notify multiple resources

template "/etc/chef/server.rb" do
  source "server.rb.erb"
  owner "root"
  group "root"
  mode "644"
  notifies :restart, "service[chef-solr]", :delayed
  notifies :restart, "service[chef-solr-indexer]", :delayed
  notifies :restart, "service[chef-server]", :delayed
end

Reload a service

template "/tmp/somefile" do
  mode "0644"
  source "somefile.erb"
  notifies :reload, "service[apache]"
end

Restart a service when a template is modified

template "/etc/www/configures-apache.conf" do
  notifies :restart, "service[apache]"
end

Send notifications to multiple resources

To send notifications to multiple resources, just use multiple attributes. Multiple attributes will get sent to the notified resources in the order specified.

template "/etc/netatalk/netatalk.conf" do
  notifies :restart, "service[afpd]", :immediately
  notifies :restart, "service[cnid]", :immediately
end

service "afpd"
service "cnid"

Execute a command using a template

The following example shows how to set up IPv4 packet forwarding using the execute resource to run a command named “forward_ipv4” that uses a template defined by the template resource:

execute "forward_ipv4" do
  command "echo > /proc/.../ipv4/ip_forward"
  action :nothing
end

template "/etc/file_name.conf" do
  source "routing/file_name.conf.erb"
  notifies :run, 'execute[forward_ipv4]', :delayed
end

where the command attribute for the execute resource contains the command that is to be run and the source attribute for the template resource specifies which template to use. The notifies attribute for the template specifies that the execute[forward_ipv4] (which is defined by the execute resource) should be queued up and run at the end of the chef-client run.

Set an IP address using variables and a template

The following example shows how the template resource can be used in a recipe to combine settings stored in an attributes file, variables within a recipe, and a template to set the IP addresses that are used by the Nginx service. The attributes file contains the following:

default['nginx']['dir'] = "/etc/nginx"

The recipe then does the following to:

  • Declare two variables at the beginning of the recipe, one for the remote IP address and the other for the authorized IP address
  • Use the service resource to restart and reload the Nginx service
  • Load a template named “authorized_ip.erb” from the /templates directory that is used to set the IP address values based on the variables specified in the recipe
node.default['nginx']['remote_ip_var'] = "remote_addr"
node.default['nginx']['authorized_ips'] = ["127.0.0.1/32"]

service "nginx" do
  supports :status => true, :restart => true, :reload => true
end

template "authorized_ip" do
  path "#{node['nginx']['dir']}/authorized_ip"
  source "modules/authorized_ip.erb"
  owner "root"
  group "root"
  mode 00644
  variables(
    :remote_ip_var => node['nginx']['remote_ip_var'],
    :authorized_ips => node['nginx']['authorized_ips']
  )

  notifies :reload, resources(:service => "nginx")
end

where the variables attribute tells the template to use the variables set at the beginning of the recipe and the source attribute is used to call a template file located in the cookbook’s /templates directory. The template file looks something like:

geo $<%= @remote_ip_var %> $authorized_ip {
  default no;
  <% @authorized_ips.each do |ip| %>
  <%= "#{ip} yes;" %>
  <% end %>
}

Add a rule to an IP table

The following example shows how to add a rule named “test_rule” to an IP table using the execute resource to run a command using a template that is defined by the template resource:

execute 'test_rule' do
  command "command_to_run
    --option value
    ...
    --option value
    --source #{node[:name_of_node][:ipsec][:local][:subnet]}
    -j test_rule"
  action :nothing
end

template "/etc/file_name.local" do
  source "routing/file_name.local.erb"
  notifies :run, 'execute[test_rule]', :delayed
end

where the command attribute for the execute resource contains the command that is to be run and the source attribute for the template resource specifies which template to use. The notifies attribute for the template specifies that the execute[test_rule] (which is defined by the execute resource) should be queued up and run at the end of the chef-client run.

Apply proxy settings consistently across a Chef organization

The following example shows how a template can be used to apply consistent proxy settings for all nodes of the same type:

template "#{node[:matching_node][:dir]}/sites-available/site_proxy.conf" do
  source "site_proxy.matching_node.conf.erb"
  owner "root"
  group "root"
  mode "0644"
  variables(
    :ssl_certificate =>    "#{node[:matching_node][:dir]}/shared/certificates/site_proxy.crt",
    :ssl_key =>            "#{node[:matching_node][:dir]}/shared/certificates/site_proxy.key",
    :listen_port =>        node[:site][:matching_node_proxy][:listen_port],
    :server_name =>        node[:site][:matching_node_proxy][:server_name],
    :fqdn =>               node[:fqdn],
    :server_options =>     node[:site][:matching_node][:server][:options],
    :proxy_options =>      node[:site][:matching_node][:proxy][:options]
  )
end

where matching_node represents a type of node (like Nginx) and site_proxy represents the type of proxy being used for that type of node (like Nexus).

Get template settings from a local file

The template resource can be used to render a template based on settings contained in a local file on disk or to get the settings from a template in a cookbook. Most of the time, the settings are retrieved from a template in a cookbook. The following example shows how the template resource can be used to retrieve these settings from a local file.

The following example is based on a few assumptions:

  • The environment is a Ruby on Rails application that needs render a file named database.yml
  • Information about the application—the user, their password, the server—is stored in a data bag on the Chef server
  • The application is already deployed to the system and that only requirement in this example is to render the database.yml file

The application source tree looks something like:

myapp/
-> config/
   -> database.yml.erb

Note

There should not be a file named database.yml (without the .erb), as the database.yml file is what will be rendered using the template resource.

The deployment of the app will end up in /srv, so the full path to this template would be something like /srv/myapp/current/config/database.yml.erb.

The content of the template itself may look like this:

<%= @rails_env %>:
   adapter: <%= @adapter %>
   host: <%= @host %>
   database: <%= @database %>
   username: <%= @username %>
   password: <%= @password %>
   encoding: 'utf8'
   reconnect: true

The recipe will be similar to the following:

results = search(:node, "role:myapp_database_master AND environment:#{node.chef_environment}")
db_master = results[0]

template "/srv/myapp/shared/database.yml" do
  source "/srv/myapp/current/config/database.yml.erb"
  local true
  variables(
    :rails_env => node.chef_environment,
    :adapter => db_master['myapp']['db_adapter'],
    :host => db_master['fqdn'],
    :database => "myapp_#{node.chef_environment}",
    :username => "myapp",
    :password => "SUPERSECRET",
  )
end

where:

  • the search method in the Recipe DSL is used to find the first node that is the database master (of which there should only be one)
  • the :adapter attribute may also require an attribute to have been set on a role, which then determines the correct adapter

The template will render similar to the following:

production:
  adapter: mysql
  host: domU-12-31-39-14-F1-C3.compute-1.internal
  database: myapp_production
  username: myapp
  password: SUPERSECRET
  encoding: utf8
  reconnect: true

This example showed how to use the template resource to render a template based on settings contained in a local file. Some other issues that should be considered when using this type of approach include:

  • Should the database.yml file be in a .gitignore file?
  • How do developers run the application locally?
  • How does this work with chef-solo?