As an alternative to placing the relationship arrows between the resources, you can just declare the resources and at the end of your manifest include the resource titles with the arrows drawn between them as follows:
Package[‘apache’] ->
File[‘apacheconf’] ~>
Service[‘apache’]
There isn’t a preferred method for defining the resource ordering. However, it is advised that your team decides on a convention that will be easiest for everyone to understand.
You can get creative with the placement of your resources in the manifest, but we
recommend adopting a logical progression when writing your Puppet code. (For instance, if resource B depends on resource A, list resource A before B in the manifest.) This will make it easier for other team members to understand the intentions of your workflow.
Also, in a year’s time, you might not even remember what your thought processes were when you wrote the manifest. As much as is possible, keep things simple.
Note
You may be wondering, “Why not just execute the Puppet code in the order that we write it?”
Even long-time Puppet users have given similar feedback, and Puppet has implemented manifest order analysis of resources (MOAR) starting with Puppet 3.3.0. MOAR will eventually become the default behavior in future releases of open source Puppet and Puppet Enterprise. However, users who prefer the current behavior (a.k.a. title hash) will be able to enable it.
The preceding examples show the quintessential approach to writing Puppet manifests:
package-file-system. You specify which package should be deployed, the related
configuration or content files for that package, and the service state (running, stopped, and so forth) of the package. It’s a great model to follow when you begin writing Puppet code regularly.
Conditional Expressions and Variables
Basic manifests such as the one shown earlier are powerful. However, you may want to make modifications to the way the manifest executes according to the properties of the system that is executing the manifest. Also, if the name of the package ever changes, editing your code can become a bit tedious because the package name change will most likely affect other resources (configuration file path, service state commands, and so forth).
For these and other reasons, Puppet allows the use of variables and conditional
expressions. In addition, a binary called facter is included when Puppet is installed, and it automatically generates a list of variables that describe server characteristics that are referred to as facts (Is this a physical machine or virtual machine? What is the IP address?
What is the operating system? and so on). Facts can be accessed from the command line by running the facter command. You explore individual facts by specifying them when you run the facter command (facter is_virtual, facter ipaddress, facter operatingsystem, and so on). All facts are available at runtime to your Puppet manifest.
All variable labels are prefixed with a $ sign in your manifest file, including the
automatically generated facts ($is_virtual and so forth). Your variables do not need to have a type declared such as string or int. Just like with Ruby, Puppet understands which type of variable you are declaring by the value that you initialize it with.
When using variables in your code with string values, it is necessary to use double
quotation marks instead of single quotation marks. The inclusion of a variable’s data in a string is known as interpolation, as illustrated by the use of the $webserver variable in the following code example:
Click here to view code image
$webserver=‘httpd’
file {‘apacheconf’:
name => “/etc/$webserver/conf/$webserver.conf”, ensure => file,
mode => 600,
source => “/etc/puppet/files/$webserver.conf”, require => Package[‘apache’],
}
If you are concerned with making mistakes with single quotes versus double quotes or other Puppet syntax items, there are helpful integrated development environment (IDE) and text editor plugins such as Geppetto and Sublime Text’s Puppet bundle that support Puppet syntax highlighting. These tools can prove helpful for avoiding mistakes with quotes and other Puppet conventions.
Conditional statements allow you to fully take advantage of the power of puppet variables.
The conditional statements supported in Puppet are if and case. Going back to my Apache deployment example from earlier, the name of the Apache package varies based on the operating system flavor that you deploy. For example, on Red Hat-based systems, the Apache binary is known as httpd. On Debian-based systems, the package is known as apache2. I will be using the operatingsystem fact to determine the appropriate settings to use in my manifest.
Here is an example using an if conditional:
Click here to view code image
if $operatingsystem == ‘centos’ { $webserver= ‘httpd’
$confpath = “/etc/$webserver/conf/$webserver.conf”
}
elsif $operatingsystem == ‘ubuntu’: { $webserver= ‘apache2’
$confpath = “/etc/$webserver/$webserver.conf”
} else {
fail(“Unsupported OS”) }
Here is an example using a case conditional:
Click here to view code image case $operatingsystem { centos: {
$webserver= ‘httpd’
$confpath = “/etc/$webserver/conf/$webserver.conf”
}
ubuntu: {
$webserver= ‘apache2’
$confpath = “/etc/$webserver/$webserver.conf”
}
default: {
fail(“Unsupported OS”) }
}
In the preceding examples, I use the operatingsystem fact to make decisions about the values for the two variables that I declare. If the server that I’m running this script on is neither a Red Hat–based nor a Debian-based operating system, I generate a failure notification for the manifest execution because it is an unexpected environment.
For conditional checks that decide between one or two values, if statements may be preferable. However, if you need to select from a long list of value options, you may want to use case statements instead.
After I add my case statement and variables, the earlier Apache manifest would look something like Listing 4-4.
Listing 4-4 Puppet Manifest Using Conditional Statements to Support Multiple Platforms
Click here to view code image case $operatingsystem { centos: {
$webserver= ‘httpd’
$confpath = “/etc/$webserver/conf/$webserver.conf”
}
ubuntu: {
$webserver= ‘apache2’
$confpath = “/etc/$webserver/$webserver.conf”
}
default: {
fail(“Unsupported OS”) }
}
package { ‘apache’:
name => $webserver, ensure => installed, }
file {‘apacheconf’:
name => $confpath,
ensure => file, mode => 600,
source => “/etc/puppet/files/$webserver.conf”, require => Package[‘apache’],
}
service {‘apache’:
name => $webserver, ensure => running, enable => true,
subscribe => File[‘apacheconf’], }