Puppet Code by Example: Part 2

John Tucker
codeburst
Published in
5 min readNov 16, 2020

--

Exploring variables, facts, and parameters.

This is part of a series of articles starting with Puppet Code by Example: Part 1. The final body of Puppet Code developed through this series is available for download.

Variables

So far we have only been using hard-coded values, e.g., the string Hello World. Here we introduce Puppet variables (which behave more like constants) to help eliminate duplicated hard-coded values.

Variables store values so that those values can be accessed in code later.

After you’ve assigned a variable a value, you cannot reassign it. Variables depend on order of evaluation: you must assign a variable a value before it can be resolved.

— Puppet — Variables

To illustrate a basic use of variables, let’s create a new module by executing the following from the modules folder:

$ pdk new module my_variables

And the executing the following from the modules/my_variables folder:

$ pdk new class local_variables

We update modules/my_variables/manifests/local_variables.pp:

Things to observe:

  • Here we follow Puppet’s variable naming constraints; seems like the convention is to also stick with lower case letters
  • By switching to using double-quotes in defining strings, we can include variables as shown (referred to as interpolation)

So far we have only used locally (to class) scoped variables; let’s change that by first creating a new class by executing the following from the modules/my_variables folder.

$ pdk new class scoped_variables

We update modules/my_variables/manifests/scoped_variables.pp as shown:

Things to observe:

  • Notice that we can reuse the same variable name, $my_content, in a different class
  • (/tmp/scoped_variables_1 resource) Notice that we can reference the variable, $my_content, in a different class, local_variables, by using a fully qualified reference
  • (/tmp/scoped_variables_2 resource) While we need to create it (which we will do shortly), we can reference module variables
  • (/tmp/scoped_variables_3 resource) While we also need to create it (we will also do this shortly), we can reference global variables

Let’s define that module variable, by creating the module’s main class by executing the following from the modules/my_variables folder.

$ pdk new class my_variables

And updating modules/my_variables/manifest/init.pp:

Let’s define the global variable by updating manifest/site.pp:

Facts

So far we have used variables that we have created; here we use variables supplied to us from the agent itself (facts).

Before requesting a catalog for a managed node, or compiling one with puppet apply, Puppet collects system information, called facts, by using the Facter tool. The facts are assigned as values to variables that you can use anywhere in your manifests. Puppet also sets some additional special variables, called built-in variables, which behave a lot like facts.

— Puppet — Facts and Built-in Variables

To see what variables are available from an agent, we can log in to the system running the agent and execute:

$ facter -p
...
os => {
architecture => "amd64",
distro => {
codename => "buster",
description => "Debian GNU/Linux 10 (buster)",
id => "Debian",
release => {
full => "10.6",
major => "10",
minor => "6"
}
},
family => "Debian",
hardware => "x86_64",
name => "Debian",
...
}
...

Please note: This is only a small sample of the output.

To illustrate a basic use of facts, let’s create a new module by executing the following from the modules folder.

$ pdk new module my_facts

And executing the following from the modules/my_facts folder:

$ pdk new class my_class

We update modules/my_facts/manifests/my_class.pp as shown:

Things to observe:

  • Here we use the preferred hash syntax for access facts
  • I was going to show the older syntax to access facts but my editor (VSCode with Puppet extension) complained; basically forcing me to use the preferred syntax

And for completeness, we create a main class for my_facts, include my_class in it, and include it in the site manifest.

Parameterized Classes

Here we explore how to make classes more flexible by passing external data into them using parameters.

Parameters allow a class to request external data. If a class needs to use data other than facts for configuration, use a parameter for that data.

You can use class parameters as normal variables inside the class definition. The values of these variables are set based on user input when the class is declared, rather than with normal assignment statements.

— Puppet — Classes

So far our classes have not accepted parameters and we have declared our classes (used them) in our node definitions using include-like declarations, e.g., include my_module.

Please note: There is a separate, less flexible way to declare our classes, resource-like declarations, that we will not be using for now.

As a side-bar, one subtle but important feature of classes is that they are singletons:

Include-like resource declarations allow you to declare a class multiple times — but no matter how many times you add the class, it is added to the catalog only once. This allows classes or defined types to manage their own dependencies and allows you create overlapping role classes, in which a given node can have more than one role.

— Puppet — Classes

Please note: In object-oriented languages, the concept of a class, template-like, is very different than Puppet’s singleton-like implementation.

Let’s first create a parametrized class by creating a my_parameters module with the classes my_class and the usual main (my_parameters) class.

Please note: In the interest of brevity, I will stop explicitly providing the commands for things that we have done multiple times.

We update modules/my_parameters/manifests/my_class.pp as shown:

Things to observe:

  • This class requires a string parameter $greeting
  • The type-definition, String, is optional (but a good practice)

We then include the class in our node definition as we have done in the past, manifests/site.pp:

Things to observe:

  • We did not supply a value for the $greeting parameter as include-like declarations do not support passing parameters
  • Because one can include the same class multiple time using include-like declarations; it makes sense that they do not support passing parameters (otherwise one could introduce discrepancies)
  • We have a problem as we have not supplied a value for the required $greeting parameter yet

The solution is to use a set of configuration files collectively referred to as Hiera (presumably short for hierarchy) to supply parameters to our classes.

Puppet’s strength is in reusable code. Code that serves many needs must be configurable: put site-specific information in external configuration data files, rather than in the code itself.

Puppet uses Hiera to do two things:
- Store the configuration data in key-value pairs
- Look up what data a particular module needs for a given node during catalog compilation

— Puppet — About Hiera

The default production environment Hiera configuration uses a file, data/common.yaml, to supply parameter values. In this case, we update it to supply a value for the $greeting parameter for the class my_class in the my_parameters module:

Next Steps

We will wrap up this series in the next article in the series, Puppet Code by Example: Part 3.

--

--