Pro Puppet (9 page)

Read Pro Puppet Online

Authors: Jeffrey McCune James Turnbull

BOOK: Pro Puppet
2.98Mb size Format: txt, pdf, ePub

Our first step in creating our first agent configuration is defining and extending the
site.pp
file. See an example of this file in
Listing 1-3
.

Listing 1-3.
The
site.pp
File

import 'nodes.pp'
$puppetserver = 'puppet.example.com'

Note
Puppet manifest files are traditionally suffixed with
.pp
. If your manifest file has the .pp suffix, you can drop the suffix when importing files.

The
import
directive tells Puppet to load a file called
nodes.pp
. This directive is used to include any Puppet configuration we want to load. For example, if we specify resources in a file called
resources.pp,
we would need to import it this way:

import 'resources.pp'

When Puppet starts, it will now load the
nodes.pp
file and process the contents. In this case, this file will contain the node definitions we create for each agent we connect. You can also import multiple files like so:

import 'nodes/*'
import 'classes/*'

The
import
statement will load all files with a suffix of
.pp
in the directories
nodes
and
classes
.

The
$puppetserver
statement sets a variable. In Puppet, configuration statements starting with a dollar sign are variables used to specify values that you can use in Puppet configuration.

In
Listing 1-3
, we’ve created a variable that contains the fully qualified domain name of our Puppet master, enclosed in double quotes.

Note
In Puppet manifests, strings with double-quotes are subject to variable interpolation and strings with single quotes are not. If you want to use a variable in a string, you should enclose it in double-quotes, for example: “This is a $variable string”. You can also add braces,
{ }
, to variables in strings to define them more clearly, “This is a ${variable} string”. You can find quoting rules for Puppet at
http://docs.puppetlabs.com/guides/more_language.html#quoting
.

Agent Configuration

Let’s add our first agent definition to the
nodes.pp
file we’ve just asked Puppet to import. In Puppet manifests, agents are defined using
node
statements.

# touch /etc/puppet/manifests/nodes.pp.

You can see the node definition we’re going to add in
Listing 1-4
.

Listing 1-4.
Our Node Configuration

node 'node1.example.com' {
    include sudo
}

For a node definition we specify the node name, enclosed in single quotes, and then specify the configuration that applies to it inside curly braces
{ }
. The client name can be the hostname or the fully qualified domain name of the client. At this stage, you can’t specify nodes with wildcards (e.g.,
*.example.com
) but you can use regular expressions, such as:

node /^www\d+\.example\.com/ {
    include sudo
}

This example will match all nodes from the domain
example.com
with the hostname
www1
,
www12
,
www123
, etc.

Note
We’ll see more of node regular expressions in
Chapter 3
.

Next, we specify an
include
directive in our node definition. The
include
directive specifies a collection of configuration that we want to apply to our host. There are two types of collections we can include in a node:

  • Classes – a basic collection of resources
  • Modules – an advanced, portable collection of resources that can include classes, definitions, and other supporting configuration

You can include multiple collections by using multiple
include
directives or separating each collection with commas.

include sudo
include sshd
include vim, syslog-ng

In addition to including collections of resources, you can also specify individual resources to a node, like so:

node 'node1.example.com' {
    include sudo
    package { 'vim': ensure => present }
}

In this case however, as we’ve seen in
Listing 1-4
, we’re just going to add a single collection of resources: the
sudo
module.

Note
Puppet also has an inheritance model in which you can have one node inherit values from another node. You can read about node inheritance at
http://docs.puppetlabs.com/guides/language_tutorial.html#nodes
; we’ll talk more about it in
Chapter 3
.

Creating our first module

The next step is to create the
sudo
module. A module is a collection of manifests, resources, files, templates, classes, and definitions. A single module would contain everything required to configure a particular application. For example, it could contain all the resources (specified in manifest files), files and associated configuration to configure Apache or the
sudo
command on a host.

Each module needs a specific directory structure and a file called
init.pp
. This structure allows Puppet to automatically load modules. To perform this automatic loading, Puppet checks a series of directories called the module path. The module path is configured with the
modulepath
configuration option in the
[main]
section of the
puppet.conf
file. By default, Puppet looks for modules in the
/etc/puppet/modules
and
/var/lib/puppet/modules
directories, but you can add additional locations if required:

[main]
moduledir = /etc/puppet/modules:/var/lib/puppet/modules:/opt/modules

The automatic loading of modules means, unlike our
nodes.pp
file, modules don’t need to be loaded into Puppet using the
import
directive.

Module Structure

Let’s start by creating a module directory and file structure in
Listing 1-5
. We’re going to create this structure under the directory
/etc/puppet/modules
. We will name the module
sudo
. Modules (and classes) must be normal words containing only letters, numbers, underscores and dashes.

Listing 1-5.
Module Structure

# mkdir –p /etc/puppet/modules/sudo/{files,templates,manifests}
# touch /etc/puppet/modules/sudo/manifests/init.pp

The
manifests
directory will hold our
init.pp
file and any other configuration. The
init.pp
file is the core of your module and every module must have one. The
files
directory will hold any files we wish to serve as part of our module. The
templates
directory will contain any templates that our module might use.

The init.pp file

Now let’s look inside our
sudo
module, starting with the
init.pp
file, which we can see in
Listing 1-6
.

Listing 1-6.
The
sudo
module’s
init.pp
file

class sudo {
    package { sudo:
         ensure => present,
    }
    if $operatingsystem == "Ubuntu" {
         package { "sudo-ldap":
            ensure => present,
            require => Package["sudo"],
        }
    }
    file { "/etc/sudoers":
        owner => "root",
        group => "root",
        mode => 0440,
        source => "puppet://$puppetserver/modules/sudo/etc/sudoers",
        require => Package["sudo"],
    }    
}

Our
sudo
module’s
init.pp
file contains a single class, also called
sudo
. There are three resources in the class, two packages and a file resource.

The first package resource ensures that the
sudo
package is installed,
ensure => present
. The second package resource uses Puppet’s if/else syntax to set a condition on the installation of the
sudo-ldap
package.

Note
Puppet also has two other conditional statements, a case statement and a selector syntax. You can see more details of Puppet’s conditional syntaxes at
http://docs.puppetlabs.com/guides/more_language.html#conditionals
.

Puppet will check the value of the
operatingsystem
fact for each connecting client. If the value of the
$operatingsystem
fact is Ubuntu, then Puppet should install the
sudo-ldap
package.

Note
We discovered Facter and its values earlier in this chapter. Each fact is available as a variable, the fact name prefixed with a $ sign, in your Puppet manifests.

Other books

Vampire Awakening by Eliza Gayle
Teen Frankenstein by Chandler Baker
Bob Dylan by Greil Marcus
Stay!: Keeper's Story by Lois Lowry
Soul of Dragons by Jonathan Moeller
Turn by David Podlipny
The Red Gloves Collection by Karen Kingsbury
The Nightingale Circus by Ioana Visan
Magician Interrupted by S. V. Brown
Ronicky Doone (1921) by Brand, Max