Chapter 6. Leveraging the Full Toolset of the Language

After our in-depth discussions on both, the manifest structure elements (class and define) and encompassing structure (modules), you are in a great position to write manifests for all of your agents. Make sure that you get Forge modules that will do your work for you. Then, go ahead and add site-specific modules that supply composite classes for the node blocks to be used, or rather, included.

These concepts are quite a bit to take in. It's now time to decelerate a bit, lean back, and tackle simpler code structures and ideas. You are about to learn some techniques that you are not going to need every day. They can make difficult scenarios much easier, though. So, it might be a good idea to come back to this chapter again after you have spent some time in the field. You might find that some of your designs can be simplified with these tools.

Specifically, these are the techniques that will be presented:

  • Templating dynamic configuration files
  • Creating virtual resources
  • Exporting resources to other agents
  • Overriding resource parameters
  • Saving redundancy using resource defaults
  • Avoiding antipatterns

Templating dynamic configuration files

In the introduction, I stated that the techniques that you are now learning are not frequently required. That was true, except for this one topic. Templates are actually a cornerstone of configuration management with Puppet.

Templates are an alternative way to manage configuration files or any files, really. You have synchronized files from the master to an agent that handled some Apache configuration settings. These are not templates, technically. They are merely static files that have been prepared and are ready for carbon copying.

These static files suffice in many situations, but sometimes, you will want the master to manage very specific configuration values for each agent. These values can be quite individual. For example, an Apache server usually requires a MaxClients setting. Appropriate values depend on many aspects, including hardware specifications and characteristics of the web application that is being run. It would be impractical to prepare all possible choices as distinct files in the module.

Learning the template syntax

Templates make short work of such scenarios. If you are familiar with ERB templates already, you can safely skip to the next section. If you know your way around PHP or JSP, you will quickly get the hang of ERB—it's basically the same but with Ruby inside the code tags. The following template will produce Hello,world! three times:

<% ( 1 .. 3 ).each do %>
Hello, world!
<% end %>

This template will also produce lots of empty lines, because the text between the <% and %> tags gets removed from the output but the final line breaks do not. To make the ERB engine do just that, change the closing tag to -%>:

<% ( 1 .. 3 ).each do -%>
Hello, world!
<% end -%>

This example is not very helpful for configuration files, of course. To include dynamic values in the output, enclose Ruby expressions in a <%=tag pair:

<% ( 1 .. 3 ).each do |index| -%>
Hello, world #<%= index %> !
<% end -%>

Now, the iterator value is part of each line of the output. You can also use member variables that are prefixed with @.

These variables are populated with the values from the Puppet manifest variables:

<IfModule mpm_worker_module>
ServerLimit         <%= @apache_server_limit %>
StartServers        <%= @apache_start_servers %>
MaxClients          <%= @apache_max_clients %>
</IfModule>
<% @apache_ports.each do |port| -%>
Listen <%= port %>
NameVirtualHost *:<%= port %>
<% end -%>

Variables that are used in a template must be defined in the same scope or scopes from which the template is used. The next section explains how this works.

In Puppet 3.x, variable values are mostly strings, arrays, or hashes. To write efficient templates, it is helpful to occasionally glance at the methods available for the respective Ruby classes. In Puppet 4, variables have more diverse values.

There are several ways to use Puppet variables in templates:

  • Prefixing the variable with the @ sign: This means that the variable is global, or it was defined in the same class where the template is used. This works with Puppet 2.7, Puppet 3, and Puppet 4.
  • Using the scope.lookupvar('variablewithscopename') function: This allows you to refer to any variable in any class of the module. Please do not look up variables in other modules; it will build an invisible dependency on the other module. The syntax works with Puppet 2, Puppet 3, and Puppet 4.
  • Using scope['variablewithscope']: In Puppet 3, the scope hash can be used directly. The behavior is similar to scope.lookupvar. This will work with Puppet 3 and Puppet 4.

Using templates in practice

Templates have their own place in modules. You can place them freely in the templates/ subtree of the module. The template function locates them using a simple descriptor:

template('cacti/apache/cacti.conf.erb')

This expression evaluates the content of the template found in modules/cacti/templates/apache/cacti.conf.erb. The first path element (without a leading slash) is the module name. The rest of the path gets translated to the templates/ tree in the module. The function is commonly used to generate the value of a file resource's content property:

file { '/etc/apache2/conf.d/cacti.conf': 
  content => template('cacti/apache/cacti.conf.erb'), 
} 

Many templates expect some variables to be defined in their scope. The easiest way to make sure that this happens is to wrap the respective file resource in a parameterized container. Files that are singletons with a well-known name, such as /etc/ssh/sshd_config, should be managed through a parameterized class. Configuration items that can inhabit multiple files, such as /etc/logrotate.d/* or /etc/apache2/conf.d/*, are well suited to be wrapped in defined types:

define logrotate::conf(
  String $pattern,
  Integer $max_days=7,
  Array $options=[]
) {
  file { "/etc/logrotate.d/$name": 
    mode    => '0644', 
    content => template('logrotate/config-snippet.erb') 
  }
}

In the preceding example, the template uses the parameters as @pattern, @max_days, and @options, respectively.

For a quick and dirty string transformation of your data, you can also use the inline_template function in your manifest. This is often found on the right-hand side of a variable assignment:

$comma_seperated_list = inline_template('<%= @my_array * "," %>')

This example assumes that the $my_array Puppet variable holds an array value.

Avoiding performance bottlenecks from templates

When using templates, both through the template and inline_template functions, be aware that each invocation implies a performance penalty for your Puppet master. During the compilation of the catalog, Puppet must initialize the ERB engine for any template it encounters. The ERB evaluation happens in an individual environment that is derived from the respective scope of the template function invocation.

It is, therefore, not even important how complex your templates are. If your manifest requires frequent expansion of a very short template, it generates an enormous overhead for each initialization. Especially in the case of an easy inline_template function, such as the one mentioned previously, it can be worthwhile to invest some more effort in creating a parser function instead, as seen in Chapter 5, Extending Your Puppet Infrastructure with Modules. A function can perform variable value transformation without incurring the cumulative penalty.

On the bright side, using templates is quite economic for the agent, who receives the whole textual file content right inside the catalog. There is no need to make an additional call to the master and retrieve file metadata. On a high-latency network, this can be a noticeable saving.

There is no silver bullet here. Don't let the performance implications deter you from turning specific configuration files into templates. Template-based solutions will often make your module more maintainable, which will usually offset performance implications—hardware is constantly getting cheaper, after all. Just don't be wasteful with frequent (and simple) expansions.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.57.219