It is impossible to begin to learn that which one thinks one already knows.
—Epictetus
In this chapter, you will learn about Puppet variables and data types, expressions, and conditional statements. You will also learn how Puppet manifests can get data about the node using Facter, find out which are the most important standard facts, and see how to create your own external facts. Finally, you will use Puppet's each
function to iterate over arrays and hashes, including Facter data.
A variable in Puppet is simply a way of giving a name to a particular value, which we can then use wherever we would use the literal value (variable_string.pp
):
$php_package = 'php7.0-cli' package { $php_package: ensure => installed, }
The dollar sign ($
) tells Puppet that what follows is a variable name. Variable names must begin with a lowercase letter or an underscore, though the rest of the name can contain uppercase letters or numbers as well.
A variable can contain different types of data—one such type is a String (like php7.0-cli
), but Puppet variables can also contain Number values, or Boolean values (true
or false
). Here are a few examples (variable_simple.pp
):
$my_name = 'Zaphod Beeblebrox' $answer = 42 $scheduled_for_demolition = true
Strings and numbers are straightforward, but Puppet also has a special data type to represent true
or false
values, which we call Boolean values, after the logician George Boole. We have already encountered some Boolean values in Puppet resource attributes (service.pp
):
service { 'sshd': ensure => running, enable => true, }
The only allowed values for Boolean variables are the literal values true
and false
, but Boolean variables can also hold the values of conditional expressions (expressions whose value is true
or false
), which we'll explore later in this chapter.
You might be wondering what type the value running
is in the previous example. It's actually a string, but a special, unquoted kind of string called a bare word. Although it would be exactly the same to Puppet if you used a normal quoted string 'running'
here, it' s considered good style to use bare words for attribute values which can only be one of a small number of words (for example, the ensure
attribute on services can only take the values running
or stopped
). By contrast, true
is not a bare word, but a Boolean value, and it is not interchangeable with the string 'true'
. Always use the unquoted literal values true
or false
for Boolean values.
It's no good being able to store something in a variable if you can't get it out again, and one of the most common ways to use a variable's value is to interpolate it in a string. When you do this, Puppet inserts the current value of the variable into the contents of the string, replacing the name of the variable. String interpolation looks like this (string_interpolation.pp
):
$my_name = 'John' notice("Hello, ${my_name}! It's great to meet you!")
When you apply this manifest, the following output is printed:
Notice: Scope(Class[main]): Hello, John! It's great to meet you!
To interpolate (that is, to insert the value of) a variable in a string, prefix its name with a $
character and surround it with curly braces ({}
). This tells Puppet to replace the variable's name with its value in the string.
A variable can also hold more than one value. An Array is an ordered sequence of values, each of which can be of any type. The following example creates an array of Integer values (variable_array.pp
):
$heights = [193, 120, 181, 164, 172] $first_height = $heights[0]
You can refer to any individual element of an array by giving its index number in square brackets, where the first element is index [0]
, the second is [1]
, and so on. (If you find this confusing, you're not alone, but it may help to think of the index as representing an offset from the beginning of the array. Naturally, then, the offset of the first element is 0.)
You already know that in Puppet resource declarations, the title of the resource is usually a string, such as the path to a file, or the name of a package. You might well ask—what happens if you supply an array of strings as the title of a resource, instead of a single string? Does Puppet create multiple resources, one for each element in the array? Let's try an experiment where we do exactly that with an array of package names, and see what happens (resource_array.pp
):
$dependencies = [ 'php7.0-cgi', 'php7.0-cli', 'php7.0-common', 'php7.0-gd', 'php7.0-json', 'php7.0-mcrypt', 'php7.0-mysql', 'php7.0-soap', ] package { $dependencies: ensure => installed, }
If our intuition is right, applying the previous manifest should give us a package
resource for each package listed in the $dependencies
array, and each one should be installed. Here's what happens when the manifest is applied:
sudo apt-get update sudo puppet apply /vagrant/examples/resource_array.pp Notice: Compiled catalog for localhost in environment production in 0.68 seconds Notice: /Stage[main]/Main/Package[php7.0-cgi]/ensure: created Notice: /Stage[main]/Main/Package[php7.0-cli]/ensure: created Notice: /Stage[main]/Main/Package[php7.0-common]/ensure: created Notice: /Stage[main]/Main/Package[php7.0-gd]/ensure: created Notice: /Stage[main]/Main/Package[php7.0-json]/ensure: created Notice: /Stage[main]/Main/Package[php7.0-mcrypt]/ensure: created Notice: /Stage[main]/Main/Package[php7.0-mysql]/ensure: created Notice: /Stage[main]/Main/Package[php7.0-soap]/ensure: created Notice: Applied catalog in 56.98 seconds
Giving an array of strings as the title of a resource results in Puppet creating multiple resources, all identical except for the title. You can do this not just with packages, but also with files, users, or, in fact, any type of resource. We'll see some even more sophisticated ways of creating resources from data in Chapter 6, Managing data with Hiera.
Why did we run the sudo apt-get update
command before applying the manifest? This is the Ubuntu command to update the system's local package catalogue from the upstream servers. It's always a good idea to run this before installing any package, to make sure you're installing the latest version. In your production Puppet code, of course, you can run this via an exec
resource.
A Hash, also known as a dictionary in some programming languages, is like an array, but instead of just being a sequence of values, each value has a name (variable_hash.pp
):
$heights = { 'john' => 193, 'rabiah' => 120, 'abigail' => 181, 'melina' => 164, 'sumiko' => 172, } notice("John's height is ${heights['john']}cm.")
The name for each value is known as a key. In the example, the keys of this hash are john
, rabiah
, abigail
, melina
, and sumiko
. To look up the value of a given key, you put the key in square brackets after the hash name: $heights['john']
.
Puppet style note
Did you spot the trailing comma on the last hash key-value pair, and the last element of the array in the previous example? Although the comma isn't strictly required, it's good style to add one. The reason is that it's very common to want to add another item to an array or hash, and if your last item already has a trailing comma, you won't have to remember to add one when extending the list.
You might have noticed that a hash looks a lot like the attributes of a resource; it's a one-to-one mapping between names and values. Wouldn't it be convenient if, when declaring resources, we could just specify a hash containing all the attributes and their values? As it happens, you can do just that (hash_attributes.pp
):
$attributes = { 'owner' => 'vagrant', 'group' => 'vagrant', 'mode' => '0644', } file { '/tmp/test': ensure => present, * => $attributes, }
The *
character, cheerfully named the attribute splat operator, tells Puppet to treat the specified hash as a list of attribute-value pairs to apply to the resource. This is exactly equivalent to specifying the same attributes directly, as in the following example:
file { '/tmp/test': ensure => present, owner => 'vagrant', group => 'vagrant', mode => '0644', }
3.17.179.247