Variables and Class Parameters

Prerequisites

  • Welcome
  • Power of Puppet
  • Resources
  • Manifests and Classes
  • Modules

Quest Objectives

  • Learn how variables and parameters can make your modules adaptable.

Getting Started

In this quest you'll get a taste of how variables fit into good module design, and you'll learn how to integrate them into your own Puppet classes and resource declarations.

If you completed the NTP and MySQL quests, you've already seen how parameterized classes can be used to adapt a module to your specific needs. In this quest, you'll see how to include parameters in your own classes.

To explore these two concepts, you'll be writing a module to manage a user account. First, you'll write a simple class using a few variables, then you'll add parameters to your class so that those variables can be set when the class is declared.

When you're ready to get started, type the following command to begin:

quest --start variables

Variables

Beauty is variable, ugliness is constant.

-Douglas Horton

Puppet's variable syntax lets you assign a name to a bit of data, so you can use that variable name later in your manifest to refer to the value assigned to it. In Puppet's syntax, variable names are prefixed with a $ (dollar sign), and a value is assigned with the = operator.

Assigning a short string to a variable, for example, would look like this:

$myvariable = 'look, a string!'

Once you have defined a variable you can use it anywhere in your manifest you would have used the assigned value.

The basics of variables will seem familiar if you know another scripting or programming language. However, there are a few caveats you should be aware of when using variables in Puppet:

  1. Unlike resource declarations, variable assignments are parse-order dependent. This means that you must assign a variable in your manifest before you can use it.

  2. If you try to use a variable that has not been defined, the Puppet parser won't complain. Instead, Puppet will treat the variable as having the special undef value.

  3. You can only assign a variable once within a single scope. Once it's assigned, the value cannot be changed. (If this makes you wonder how accurate the term "variable" is, you're not alone!)

Variable Interpolation

Variable interpolation gives you a way to insert a string stored as a variable into another string. For instance, if you want Puppet to manage the files in the /var/www/html/lvmguide directory you set up in the Power of Puppet quest, you can assign this directory path to a variable:

$doc_root = '/var/root/www/html/lvmguide'

Once the variable is set, you can use the variable interpolation syntax to insert it into a string. The variable name is preceded by a $ and wrapped in curly braces (${var_name}). For example, you might use it in the title of a few file resource declarations:

file { "${doc_root}index.html":
  ...
}
file { "${doc_root}about.html":
  ...
}

Not only is this more concise, but using variables allows you to set the directory once, depending, for instance, on the kind of server you're running, and let that specified directory be applied throughout your class.

Note that a string that includes an interpolated variable must be wrapped in double quotation marks ("..."), rather than the single quotation marks that surround an ordinary string. These double quotation marks tell Puppet to find and parse special syntax within the string, rather than interpreting it literally.

Manage a Web Content with Variables

To better understand how variables work in context, we'll walk you through creating a simple web module to drop some new files into the directory served by the Apache service you set up in the Power of Puppet quest.

Task 1 :

First, you'll need to create the directory structure for your module.

Make sure you're in the modules directory for Puppet's modulepath.

cd /etc/puppetlabs/puppet/environments/production/modules/

Now create an web directory:

mkdir web

...and your manifests and tests directories:

mkdir web/{manifests,tests}

Task 2 :

Now you're ready to create your main manifest, where you'll define the web class.

vim web/manifests/init.pp
class web {

  $doc_root = '/var/www/html/lvmguide'
  
  $english = 'Hello world!'
  $french = 'Bonjour le monde!'

  file { "${doc_root}/hello.html":
    ensure => 'present',
    content => "<em>${english}</em>",
  }
  
  file { "${doc_root}/bonjour.html"}
    ensure => 'present',
    content => "<em>${french}</em>",
  }

}

Note that if you wanted to make a change to the $doc_root directory, you'd only have to do this in one place. While there are more advanced forms of data separation in Puppet, the basic principle is the same: The more distinct your code is from the underlying data, the more resuable it is, and the less difficult it will be to refactor when you have to make changes later.

Task 3 :

Once you've validated your manifest with the puppet parser tool, create a test for your manifest with an include statement for the web class you created.

Task 4 :

Run the test, using the --noop flag for a dry run before triggering your real puppet apply.

From your web browser on your host machine, connect to http://<LVM's IP>/hello.html and http://<LVM's IP>/bonjour.html, and you'll see pages you've set up.

Class Parameters

Freedom is not the absence of obligation or restraint, but the freedom of movement within healthy, chosen parameters.

-Kristin Armstrong

Now that you've created your basic web class and replaced some of the values in your resource declarations with variables, we'll move on to class parameters. Class parameters give you a way to set the variables within a class as it's declared rather than when the class is defined.

When defining a class, include a list of parameters and optional default values between the class name and the opening curly brace. So a parameterized class is defined as below:

class classname ( $parameter = 'default' ) {
  ...
}

Once defined, a parameterized class can be declared with a syntax similar to that of resource declarations, including key value pairs for each parameter you want to set.

class {'classname': 
  parameter => 'value',
}

Say you want to make these pages available not just on the Learning VM, but on each node in your infrastructure, but that you want a few changes on each one. Instead of rewriting the whole class or module with these minor changes, you can use class parameters to customize these values as the class is declared.

Task 5 :

To get started re-writing your web class with parameters, reopen the web/manifests/init.pp manifest. You've already written variables into the resource declarations, so turning it into a parameterized class will be quick. Just add your parameters in a pair of parenthesis following the name of the class:

class web ( $page_name, $message ) {

Now create a third file resource declaration to use the variables set by your parameters:

file { "${doc_root}/${page_name}.html":
  ensure => 'present',
  content => "<em>${message}</em>",
}

Task 6 :

As before, use the test manifest to declare the class. You'll open web/tests/init.pp and replace the simple include statement with the parameterized class declaration syntax to set each of the class parameters:

class {'web': 
  page_name => 'hola',
  message   => 'Hola mundo!',
}

Task 7 :

Now give it a try. Go ahead and do a --noop run, then apply the test.

Your new page should now be available as http://<LVM's IP>/hola.html!

Review

In this quest you've learned how to take your Puppet manifests to the next level by using variables. You learned how to assign a value to a variable and then reference the variable by name whenever you need its content. You also learned how to interpolate variables.

In addition to learning about variables, interpolating variables, and facts, you also gained more hands-on learning with constructing Puppet manifests using Puppet's DSL. We hope you are becoming more familar and confident with using and writing Puppet code as you are progressing.