Protecting the production environment
Methuselah
Templates, Functions, Classes
One of the most important operations is managing and manipulating configuration files. Puppet, written in Ruby, makes use of the Ruby template engine [2] to assemble the contents of files dynamically. You call it from within Puppet by the template
function. Puppet already comes with a variety of functions out of the box, but it can also be extended with user-defined functions.
Listing 2 demonstrates yet another important construct, the class. A Puppet class groups multiple resources, to which actions are then applied jointly. A class can be used only once per system or node. If, on the other hand, you need a separate type of resource for the application of multiple resources, you can create a defined resource for this purpose. In both cases, the distinction between the definition and declaration is important. Listing 2 shows a class definition that does nothing on its own. Only a declaration like that in Listing 3 leads to the application of the desired actions.
Listing 3
Class Declaration
class { 'apache': package_name => 'httpd', config_file => '/etc/httpd/httpd.conf', service_name => 'httpd', }
Variables
Classes and defined resources can be parameterized by variables, which always use a $
as a prefix. The =
operator assigns a value to a variable. In a parameter list, the equals sign sets a default. Variables, as shown in the example, contribute to platform independence. Paths and names differ from distribution to distribution. Although the scope of a variable is limited to its class, it is possible to access a variable of another class if necessary (Listing 4, line 15).
Listing 4
Multiple Classes
01 ./apache/manifests/init.pp 02 class apache( 03 String $package_name, 04 ) { 05 class { 'apache::install': } 06 -> class { 'apache::config': } 07 ~> class { 'apache::service': } 08 contain apache::install 09 contain apache::config 10 contain apache::service 11 } 12 13 ./apache/manifests/install.pp 14 class apache::install { 15 $package_name = $apache::package_name 16 17 if $facts['osfamily'] == 'redhat' { 18 package { 'mod_ssl': 19 ensure => installed, 20 } 21 } 22 23 package { $package_name: 24 ensure => installed, 25 } 26 }
In the context of variables, Puppet also provides conditions such as if
-else
and case
to control the flow depending on the value of a variable. For example, on a Red Hat system, for HTTPS on the Apache web server, you also need the RPM package mod_ssl
(Listing 4, lines 17-21), which other distributions do not require.
Since Puppet 4, you can and should typecast parameters to eliminate the need for validations and to standardize error messages. Two of the types used in Listing 2 for $config_file
and $ensure
are not included in Puppet, but have to be loaded by the standard library (stdlib
) as a module to extend the language scope.
Modules
In addition to data types, modules also include functions, classes, defined resources, templates, and much more, all of which must be located in certain subdirectories of the module directory [3] so that Puppet always finds them (autoloading).
Put simply, a module is a summary of all the resources needed to configure a piece of software. Puppet Forge [4] serves as a community portal for modules. In addition to many modules from hobbyists, a large number of professionally maintained modules can be found here, some from Puppet itself (e.g., for Apache) or from the Vox Pupuli project [5].
Each module has its own namespace, which always corresponds to its name. Class or defined resource names start with the module name; the same applies to data types (see Listing 2). Listing 4 shows the approach to further subdivide a class in a module by dividing the tasks into installation, configuration, and service.
The arrows between the class declarations are an alternative notation for setting the order, wherein ->
corresponds to a before
and ~>
to a notify
. Therefore, each resource of one class is processed before those of the other. The opposite case also exists. Any resource that needs to trigger a service restart when a change is made goes into the apache::config
class, and only the resource affecting the service goes after apache::install
. Now you only have to consider the dependencies of resources within the respective class.
The contain
statement lets you declare classes whose resources also belong to the parent class, unlike include
, and is the only way to make sense of a dependency definition (e.g., for the apache
class) [6]. Idempotency allows a declaration with class
and then another with include
or contain
, but not vice versa.
As you will see later, these modules are a major strength of Puppet. First, however, look at how Puppet communicates with the systems to be configured in the first place and decides which resources belong to which host with which parameters.
Buy this article as PDF
(incl. VAT)