Conditionals, Case statements, Selectors, Relationships and Ordering, ERB Templates

Conditionals

Vagrant VM will by default have NAT Interface, we can create an extra bridge interface. The benefit of bridge interface: Our VM will get IP from Router/Gateway/DHCP/Wifi router of our network. So our VM will be able to talk to any instance in network and vice versa.
Puppet supports “if” and “unless” statements, case statements, and selectors.
“If” Statements
Syntax:
if $osfamily == 'redhat'{
package {'httpd':
ensure =>'present',
}
elsif $osfamily == 'debian'{
Package {'apache2':
ensure =>'present',
}
else {
notify { 'No Package Found':
}
The general form of an “if” statement is:
• The if keyword
• A condition
• A pair of curly braces containing any Puppet code
• Optionally: the elseif keyword, another condition, and a pair of curly braces containing Puppet code
• Optionally: the else keyword and a pair of curly braces containing Puppet code

Case Statements

Like “if” statements, case statements choose one of several blocks of arbitrary Puppet code to execute. They take a control expression and a list of cases and code blocks and will execute the first block whose case value matches the control expression.
Syntax
case $operatingsystem {
'Solaris': { include role::solaris } # apply the solaris class
'RedHat', 'CentOS': { include role::redhat } # apply the redhat class
/^(Debian|Ubuntu)$/:{ include role::debian } # apply the debian class
default: { include role::generic } # apply the generic class
}
The general form of a case statement is:
• The case keyword
• A control expression (see below)
• An opening curly brace
• Any number of possible matches, which consist of:
• A case (see below) or comma-separated list of cases
• A colon
• A pair of curly braces containing any arbitrary Puppet code
• A closing curly brace

Selectors

Selector statements are similar to case statements, but return a value instead of executing a code block. Selectors are useful when the user wishes to specify a resource attribute and variables which are different from the default values based on the facts or other variables.
Syntax
Selectors resemble a cross between a case statement and the ternary operator found in other languages.

$rootgroup = $osfamily ? {
'Solaris'=>'wheel',
/(Darwin|FreeBSD)/ =>'wheel',
default =>'root',
}
file { '/etc/passwd':
ensure =>file,
owner =>'root',
group =>$rootgroup,
}
In the example above, the value of $rootgroup is determined using the value of $osfamily. The general form of a selector is:
• A control variable
• The ? (question mark) keyword
• An opening curly brace
• Any number of possible matches, each of which consists of:
• A case
• The => (fat comma) keyword
• A value
• A trailing comma
• A closing curly brace

Relationships and ordering
By default, Puppet applies resources in the order they’re declared in their manifest. However, if a group of resources must always be managed in a specific order, you should explicitly declare such relationships with relationship meta parameters.
Syntax: Relationship meta parameters
package { 'OpenSSH-server':
ensure =>present,
before =>File['/etc/ssh/sshd_config'],
}
Puppet uses four meta parameters to establish relationships, and you can set each of them as an attribute in any resource. The value of any relationship meta parameter should be a resource reference pointing to one or more target resources.
•before — Applies a resource before the target resource.
•require— Applies a resource after the target resource.
•notify — Applies a resource before the target resource.
The target resource refreshes if the notifying resource changes.
•subscribe — Applies a resource after the target resource. The subscribing resource refreshes if the target resource changes.
If two resources need to happen in order, you can either put a before attribute in the prior one or a required attribute in the subsequent one; either approach creates the same relationship. The same is true of notifying and subscribe.
The two examples below create the same ordering relationship:
package { 'openssh-server': ensure =>present,
before =>File['/etc/ssh/sshd_config'],
}
file { '/etc/ssh/sshd_config':
ensure =>file,
mode =>'0600',
source =>'puppet:///modules/sshd/sshd_config',
require =>Package['openssh-server'],
}
The two examples below create the same notifying relationship:
file { '/etc/ssh/sshd_config':
ensure =>file,
mode =>'0600',
source =>'puppet:///modules/sshd/sshd_config',
notify =>Service['sshd'],
}
service { 'sshd':
ensure =>running,
enable =>true,
subscribe =>File['/etc/ssh/sshd_config'],
}
Since an array of resource references can contain resources of differing types, these two examples also create the same ordering relationship:
service { 'sshd':
ensure =>running,
require =>[
Package['openssh-server'],
File['/etc/ssh/sshd_config'],
],
}
package { 'openssh-server':
ensure =>present,
before =>Service['sshd'],
}
file { '/etc/ssh/sshd_config':
ensure =>file,
mode =>'0600',
source =>'puppet:///modules/sshd/sshd_config',
before =>Service['sshd'],
}

ERB Templates

First, let’s adjust the file declaration from the previous section. We’ll remove the source attribute and replace it with a content attribute.
file { '/etc/puppet/puppet.conf':
ensure =>ensure,
owner =>'root',
group =>'wheel',
mode =>'0644',
content =>template('puppet:///puppet/puppet.conf.erb'),
}
The template() function takes a single argument: the URI of the ERB template. The format of that URI is always puppet:///modulename/filename. The file should be placed in the templates directory of the module. ERB templates should end with the .erb extension to indicate that the file contains tags for the ERB template processor.
Let’s create the ERB template file.
$ cd sample_module/templates
$ vi templates/puppet.conf.erb
The contents of the file should look like this:
# Generated by Puppet ERB template processor

[main]
log_level = <%= @loglevel %>
# This is used by "puppet agent"
[agent]
log_level = <%= @agent_loglevel %>
server = <%= @server -%>.example.net
# This is used for "puppet apply"
[user]
log_level = <%= @apply_loglevel %>
Each instance of <%=@variable %> is replaced with the value of the Puppet variable named after the @sign. The variables named with the @ sign must exist in the same scope (within the module class) as the template declaration. There are many other things you can do within an ERB template. You can lookup variables from another class using the scope. lookupvar() function, or use scope[] as if it was a Hash.
You can call Puppet functions using scope.function_puppet_function(). For example, you could call the Hiera function to lookup Hiera values within templates (although this practice is strongly discouraged). This would be done by using scope.function_hiera() to call the same heira() function we used when introducing Hiera. server = <%= scope.function_hiera( ['puppet::server'] ) -%>
Best Practice: Avoid placing direct Hiera calls within the template, as it divides the source of data for the template between the manifest file and hiera, ensuring confusion. Instead, source the Hiera variables within the manifest so that all variables are within scope.
As ERB templates were intended for inline Ruby development, you can put any Ruby statement within <% ... %> tags without the equals sign. Here’s an example that would limit duplicate assignment of log levels which don’t differ.
[user]
<% if @apply_loglevel != @loglevel -%>
log_level = <%= @apply_loglevel %>
<% end -%>
By wrapping this line of the template within the Ruby block, it will skip outputting the configuration line if the log level matches the main log level, thus simplifying the configuration file.
Go ahead and test this change right now with puppet apply. You will see the content of the puppet configuration file get updated.

Iterating over Values

Here’s an example where we use the Ruby each () function to iterate through an array of tags which should be used to limit which resources are applied to the node, as we discussed in Part I. This example uses the dash creatively to suppress linefeeds and output multiple Puppet servers on a single line:
Each instance of <%=@variable %> is replaced with the value of the Puppet variable named after the @sign. The variables named with the @ sign must exist in the same scope (within the module class) as the template declaration. There are many other things you can do within an ERB template. You can lookup variables from another class using the scope.lookupvar() function, or use scope[] as if it was a Hash.
You can call Puppet functions using scope.function_puppet_function(). For example, you could call the Hiera function to lookup Hiera values within templates (although this practice is strongly discouraged). This would be done by using scope.function_hiera() to call the same heira() function we used when introducing Hiera. server = <%= scope.function_hiera( ['puppet::server'] ) -%>
Best Practice: Avoid placing direct Hiera calls within the template, as it divides the source of data for the template between the manifest file and hiera, ensuring confusion. Instead, source the Hiera variables within the manifest so that all variables are within scope.
As ERB templates were intended for inline Ruby development, you can put any Ruby statement within <% ... %> tags without the equals sign. Here’s an example that would limit duplicate assignment of log levels which don’t differ.
[user]
<% if @apply_loglevel != @loglevel -%>
log_level = <%= @apply_loglevel %>
<% end -%>
By wrapping this line of the template within the Ruby block, it will skip outputting the configuration line if the log level matches the main log level, thus simplifying the configuration file.
Go ahead and test this change right now with puppet apply. You will see the contents of the puppet configuration file get updated.
Iterating over Values
Here’s an example where we use the Ruby each () function to iterate through an array of tags which should be used to limit which resources are applied to the node, as we discussed in Part I. This example uses the dash creatively to suppress linefeeds and output multiple Puppet servers on a single line:
[agent]
tags = <% @taglist.each do |tagname| -%>
<%= tagname + ','-%>
<% end -%>
You’ll note that we don’t put an @ sign before the variable name. That is because we are not referencing a variable in the Puppet module class, but instead from the local loop shown in this example.
For more information about Visualpath, visit www.visualpath.in and follow the company on Facebook and Twitter.
For DevOps training contact us at +91 9704455959 / info@visualpath.in

Comments