Chapter 5. Variables, expressions, and facts

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.

Variables, expressions, and facts

Introducing variables

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

Using Booleans

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.

Tip

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.

Interpolating variables in strings

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.

Tip

We sneaked a new Puppet function, notice(), into the previous example. It has no effect on the system, but it prints out the value of its argument. This can be very useful for troubleshooting problems, or finding out what the value of a variable is at a given point in your manifest.

Creating arrays

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

Declaring arrays of resources

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.

Tip

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.

Understanding hashes

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'].

Tip

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.

Setting resource attributes from a hash

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',
}
..................Content has been hidden....................

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