Handson3

From Gridkaschool
Revision as of 14:51, 27 August 2014 by Sternber (talk | contribs) (Splitting the module into parts)

A simplistic "real world example" of a puppet module

Introduction

The main purpose of this tutorial is to try to create a well structured and documented puppet feature.

The "real world example" in this case will be a puppet module called "myapache". It should demonstrate how to install and configure an apache web server in a very simplistic way!

The deployment of the "myapache" web server consists of 3 steps:

  1. Installing the apache package
  2. Configuring the web server
  3. Starting the web server

All the system changes needed to install the apache web server will be defined using puppet and recorded into git. This will allow us not only to document those changes but also to *re-appy* them whenever needed! Git should already have been configured in the previous hands-on session.

Creating a new puppet module in your git working directory

As a first step we should change in our git working directory and create a new puppet module called "myapache"

Use the following command to help you create a new puppet module:

puppet module generate user-myapache

After answering a few questions you should have your new module in place.

This module should as well be pushed upstream into your personal development environment and tested with a puppet agent.


Filling your puppet module with life!

Let's start by editing the following file

./modules/myapache/manifests/init.pp

and change it in order to install the "apache" package.

Hint: Each puppet resource has it's own "man-page"

puppet describe --help
puppet describe --list

In this case you should look more carefully at the "package" resource.

puppet describe package

Solution

After applying and testing your changes, commit them into git and push it upstream. Start a new puppet agent test run. What happens if the puppet agent is called twice?

Protecting your code

One should always make sure that changes are only applied where they should be applied on! This means that if someone else uses your puppet modules, they should not get their systems ruined because your forgot to add a simple check.

The first check should always ensure that your puppet module only runs on a list of supported operating systems, otherwise fail! This check can easily be done using the puppet facts "osfamily" and "operatingsystem".

After applying and testing your changes, don't forget to commit and push!

Solution

Cross-platform support

Of course it is much nicer if instead of just failing we can design our module to run on as many different platforms as possible... Just for fun try to re-write the previous check so that the module now runs on RedHat and on Debian systems. On Debian the "httpd" package name equivalent is "apache2".

After applying and testing your changes, don't forget to commit and push!

Solution

Splitting the module into parts

It is good practice to split your code into a well defined set of manifests, whereas a single manifest should only manage a single task!

For now we should create three new manifests:

./modules/myapache/manifests/params.pp
./modules/myapache/manifests/install.pp
./modules/myapache/manifests/service.pp

The *params.pp* manifest should only include a bunch of variables set to some reasonable "default" values depending on the list of supported operating systems. In this case we have for example the package name (httpd vs. apache2).

The contents from *init.pp* (installing of the apache package) should now be moved into *install.pp*. The apache package name in the *install.pp* manifest should however be set from the variable defined in *params.pp*.

The *service.pp* should start the apache web service. Also here, we should rather define the service name in *params.pp*. (On Debian systems the apache service is also called apache2)

After refactoring the code, the *init.pp* should be only including the classes defined in the other manifests + their dependencies!

After applying and testing your changes, don't forget to commit and push!

As of now you should see a "default" html web page when opening a web browser with the URL from your test machine.

References:

Solution

Configurations

Typically a puppet module does not only install a package but also configures some settings related to that package.

For doing this we will now create a new manifest:

./modules/myapache/manifests/config.pp

This manifest should change/overwrite the "default" web page installed by the apache package. You can find the "default" web page in the following location:

/var/www/error/noindex.html

The first step we need to do is to create a new "default" html web page and save it under:

./modules/myapache/files/default-index.html

The second step we need to do is to use the puppet "file" resource in the *config.pp* manifest and tell it to deploy the new web page in the correct path.

-rw-r--r-- 1 root root 3822 May 14 15:24 /var/www/error/noindex.html

Don't forget to set the correct file permissions!

Hints:

puppet describe file

After applying and testing your changes, don't forget to commit and push!

You should now see _your_ "default" html web page when opening a web browser with the URL from your test machine.

Solution

Puppet templates

How about putting some dynamic information into the default html web page? For example something like:

Welcome!
Some infos about this host:
Hostname: foo@example.com
Number of CPU's:   2
Total memory:   7.73 GB
Free memory:   6.44 GB
Kernel:   Linux
Kernel version:   3.2.0
Operating system:   Ubuntu
OS family:   Debian
IP address:   131.169.171.143
MAC address:   00:1c:c0:b2:fa:d4

This information should be defined in a puppet template under:

./modules/myapache/templates/default-index.html.erb

Note the .erb extension!

The *config.pp* should also be modified to install the template instead of the previously defined static file.

Hints:

facter --help
facter -p

P.S. Yes, this is just an example... You should _not_ use this kind of templates on any production hosts!!

Solution

Parameterized classes

What if we want to change the default port on which the apache web server should listen to?

Well, this can be done by changing the "Listen" parameter in the following configuration file:

/etc/httpd/conf/httpd.conf

However, we don't want to change anything manually on the host! What we want is to add a new parameter "port" to our puppet module and tell it how to make the changes. We also want to keep 80 as the default port.

Examples:

   class{ myapache } # listen to port 80
   class{ myapache : port => 8080 } # listen to port 8080

After changing our class to accept the port parameter, we still need to pass this information into the configuration file /etc/httpd/conf/httpd.conf.

This can be basically be solved in two different ways:

  • One way is to copy /etc/httpd/conf/httpd.conf into our puppet module and make it a template which changes the 'Listen' parameter dynamically.
  • The other way is to use augeas to change the configuration file in-place.

The first way is easier since the augeas syntax tends to be somewhat cumbersome... Feel free to try out both ways and find which one you like best.

Hints:

Solution

Class inheritance

Use inheritance to store the default value from the "port" class parameter in the *params.pp* manifest. The *init.pp* should declare the *myapache* class as follows:

class myapache( $port = $myapache::params::port ) inherits myapache::params {
   ...
}

Hints:

Solution


A full-featured apache puppet module can be downloaded from here [1]