Pro Puppet (48 page)

Read Pro Puppet Online

Authors: Jeffrey McCune James Turnbull

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

In this example, the
gem
command installs executables to
/var/lib/gems/1.8/gems
. The operator adds this file system location to the
PATH
variable, as shown in
Listing 8-36
, to complete the installation of cucumber-puppet.

Listing 8-36.
Adding the gem executable directory to the PATH

# export PATH="/var/lib/gems/1.8/bin:$PATH"
# which cucumber-puppet
/var/lib/gems/1.8/bin/cucumber-puppet

Once the cucumber-puppet command is available, we may proceed with writing a story describing the desired Puppet catalog behavior.

Writing a Story

The behavior of Puppet is described in Cucumber “stories.” Before writing a story describing the catalog behavior and features, the cucumber-puppet testing directory needs to be created. On a testing system, basic example step definitions should be installed using the cucumber-puppet-gen command (see
Listing 8-37
).

Listing 8-37.
Installing basic step defintions with cucumber-puppet-gen

# cd /etc/puppet
#  cucumber-puppet-gen world
Generating with world generator:
     [ADDED]  features/support/world.rb
     [ADDED]  features/steps
     [ADDED]  features/support/hooks.rb

Once the basic steps have been installed, the Example.com operator configures cucumber-puppet by modifying the
hooks.rb
file. Before doing so, he adds and commits the new files to the Git repository as shown in
Listing 8-38
.

Listing 8-38.
Adding cucumber-puppet steps to Git

# cd /etc/puppet
# git add features
# git commit -m 'Add cucumber-puppet generated steps'

Once added to Git, the operator modifies the
hooks.rb
file to configure cucumber-puppet, as shown in
Listing 8-39
.

Listing 8-39.
Changes to hooks.rb to configure cucumber-puppet

# git diff
diff --git a/features/support/hooks.rb b/features/support/hooks.rb
index 77db992..3588300 100644
--- a/features/support/hooks.rb
+++ b/features/support/hooks.rb
@@ -1,7 +1,9 @@
 Before do
   # local configuration
   # @confdir = File.join(File.dirname(__FILE__), '..', '..')
+  @confdir = "/etc/puppet"
   # @manifest = File.join(@confdir, 'manifests', 'site.pp')
+  @manifest = "/etc/puppet/manifests/site.pp"
   # adjust facts like this
   @facts['architecture'] = "i386"
 End

As you can see, the operator added two lines to the
hooks.rb
file. First, the configuration directory for Puppet is set to
/etc/puppet
. This corresponds to the
confdir
configuration setting. Next, the main
site.pp
file is configured using the @manifest variable. This setting should point to the full path of the
site.pp
file,
/etc/puppet/manifests/site.pp
by default.

Once cucumber-puppet is configured, the catalog policy in
Listing 8-40
is used to test and verify the behavior of the catalog. The Example.com operator uses the cucumber-puppet-gen command to generate a template catalog policy file.

Listing 8-40.
The initial web server cucumber-puppet policy.feature file

# cd /etc/puppet/
# cucumber-puppet-gen policy
Generating with policy generator:
     [ADDED]  features/catalog
# git add features/catalog/
# git commit -m 'Add initial catalog policy template'
[master a0c6c3c] Add initial catalog policy template
 1 files changed, 14 insertions(+), 0 deletions(-)
 create mode 100644 features/catalog/policy.feature

With these three commands, the operator generates a new template for the catalog policy, adds the policy to the Git index, and then commits the new file to the repository. The cucumber-puppet policies closely resemble the natural language stories of Cucumber, as shown in
Listing 8-41
.

Listing 8-41.
A template cucumber-puppet policy

# cat /etc/puppet/features/catalog/policy.feature
Feature: General policy for all catalogs
  In order to ensure applicability of a host's catalog
  As a manifest developer
  I want all catalogs to obey some general rules
  Scenario Outline: Compile and verify catalog
    Given a node specified by "features/yaml/.example.com.yaml"
    When I compile its catalog
    Then compilation should succeed
    And all resource dependencies should resolve
    Examples:
      | hostname  |
      | localhost |

There are a few key sections of the policy file. First, the Scenario section is tested for every node listed in the Examples section. Cucumber-puppet substitutes the name listed underneath the
hostname
header into the filename listed in the
Given a node specified by
section. This node cache contains a list of top-level parameters set by
site.pp
, the ENC, and Facter. Using the cached node information stored on the Puppet master allows cucumber-puppet to effectively simulate a catalog request from each Puppet agent.

In order to populate these node definition files, the Example.com operator copies the cached node files from the Puppet Master as shown in
Listing 8-42
. These node files are located in
$yamldir /node/,
where
$yamldir
is a configuration setting on the Master system. Let's see how the operator provides this information to cucumber-puppet.

Listing 8-42.
Copying node YAML files from the Puppet Master into cucumber-puppet

# cd /etc/puppet
# mkdir /etc/puppet/features/yaml
# puppet master --configprint yamldir
/var/lib/puppet/yaml
# cp /var/lib/puppet/yaml/node/{www,mail}.example.com.yaml \
  /etc/puppet/features/yaml/

First, the operator changes to the Puppet configuration directory, then creates the /etc/puppet/features/yaml directory. He then determines where the Puppet Master caches nodes compiled by the Puppet Master using the
--configprint yamldir
option. With this information, he copies the cached node information for the mail and web server into the cucumber-puppet directory structure.

With the node information in place, he modifies the catalog policy slightly to test catalog compilation for the mail and web server, replacing the
localhost
entry in the template. This modification is shown in
Listing 8-43
.

Listing 8-43.
Add www and mail to the cucumber-puppet catalog policy

# git diff
diff --git a/features/catalog/policy.feature b/features/catalog/policy.feature
index c742189..1ea545e 100644
--- a/features/catalog/policy.feature
+++ b/features/catalog/policy.feature
@@ -11,4 +11,5 @@ Feature: General policy for all catalogs
 
     Examples:
       | hostname  |
-      | localhost |
+      | www |
+      | mail |

We can see that the operator replaces the
localhost
entry with two additional entries for
www
and
mail
. These names will be substituted into the file path when cucumber-puppet loads the node information. They also match the two YAML node files copied from the Puppet master yaml directory.

With this information in place, the operator commits the changes using the commands in
Listing 8-44
and is ready to start testing changes to the Puppet manifests.

Listing 8-44.
Committing node information and catalog policy to the git repository

$ git status
#On branch master
# Changes to be committed:
#   (use "git reset HEAD ..." to unstage)
#
#       new file:   features/yaml/mail.example.com.yaml
#       new file:   features/yaml/www.example.com.yaml
#
# Changed but not updated:
#   (use "git add ..." to update what will be committed)
#   (use "git checkout -- ..." to discard changes in working directory)
#
#       modified:   features/catalog/policy.feature
#
# git commit -m 'Add mail and web node YAML, update catalog policy'
[master c71e527] Add mail and web node YAML, update catalog policy
 3 files changed, 141 insertions(+), 1 deletions(-)
 create mode 100644 features/yaml/mail.example.com.yaml
 create mode 100644 features/yaml/www.example.com.yaml
Testing the Basic Catalog Policy

With the YAML node caches copied into place and the catalog policy updated, the operator simply executes cucumber-puppet as shown in
Listing 8-45
, testing his current manifests.

Listing 8-45.
Testing manifests with cucumber-puppet

$ cucumber-puppet features/catalog/policy.feature
Feature: General policy for all catalogs
  In order to ensure applicability of a host's catalog
  As a manifest developer
  I want all catalogs to obey some general rules
  Scenario Outline: Compile and verify catalog
    Given a node specified by "features/yaml/.example.com.yaml"
    When I compile its catalog
    Then compilation should succeed
    And all resource dependencies should resolve
    Examples:
      | hostname |
      | www      |
      | mail     |
2 scenarios (2 passed)
8 steps (8 passed)
0m0.104s

While in the
/etc/puppet
directory, the operator executes cucumber-puppet with the path to the catalog policy file. Cucumber-puppet then tests both the mail and web server and validates that the catalog compilation succeeds. The operator expects as much, but a basic
site.pp
file is being used with an empty node declaration of
node default { }
.

Testing the failure case

To verify that cucumber-puppet will properly report catalog failures, he modifies the site.pp in
Listing 8-46
to contain the following node definitions:

Listing 8-46.
/etc/puppet/manifests/site.pp test failure with cucumber-puppet

# /etc/puppet/manifests/site.pp
node default {
  notify { "unclassified":
    message => "This node is not classified",
  }
}
node www {
  notify { "web":
    message => "This node is the web server.",
  }
}
node mail {
  notify { "mail":
    message => "This node is the mail server.",
  }
  fail("This is a deliberate catalog compilation failure")
}

The operator has reconfigured the site.pp to deliberately fail a catalog compilation when compiling the catalog for the mail server. The web server, however, should still produce a valid catalog. He then verifies these expectations in
Listing 8-47
by re-running the cucumber-puppet command.

Listing 8-47.
Verifying that catalog failures are caught by cucumber-puppet

# cucumber-puppet features/catalog/policy.feature
Feature: General policy for all catalogs
  In order to ensure applicability of a host's catalog
  As a manifest developer
  I want all catalogs to obey some general rules
  Scenario Outline: Compile and verify catalog
    Given a node specified by "features/yaml/.example.com.yaml"
    When I compile its catalog
    Then compilation should succeed
    And all resource dependencies should resolve
    Examples:
      | hostname |
      | www      |
      |This is a deliberate catalog compilation failure at /etc/puppet/manifests/site.pp:17
 on node mail.example.com
 mail     |
      exit (SystemExit)
      features/catalog/policy.feature:8:in `When I compile its catalog'
Failing Scenarios:
cucumber features/catalog/policy.feature:6 # Scenario: Compile and verify catalog
2 scenarios (1 failed, 1 passed)
8 steps (1 failed, 2 skipped, 5 passed)
0m0.132s

The operator uses the fail function to deliberately fail the catalog compilation for the mail server. As expected, cucumber-puppet reports one failed and one successful scenario. The specific error message and line number is returned in the output of cucumber-puppet, allowing the operator to quickly correct the problem.

So far, you've learned how the operator configures cucumber-puppet to test and validate catalog compilation. Next, you'll see how to validate that specific critical resources remain part of the configuration catalog when changes are made to the Puppet modules and manifests.

Validating Specific Resources

In the previous section, you learned how to validate catalog compilation successfully after making changes to the Puppet manifests. In this section, you'll see how the operator adds additional scenarios to ensure specific resources remain defined in the configuration catalog.

Catalog compilation errors will be obvious when they occur; the affected nodes will no longer receive a valid catalog. A resource omitted from the catalog is much more difficult to identify, however, because the affected node will still receive and apply the rest of the Puppet catalog. Cucumber-puppet allows the operator to make changes to conditional logic and verify that key resources are not excluded by the change. Let's see how this works.

Other books

Slow Burn by Heather Graham
Secret Santa by Kathleen Brooks
The Golden Crystal by Nick Thacker
The Altered Case by Peter Turnbull
Game for Marriage by Karen Erickson
Mermaid in Chelsea Creek by Michelle Tea