Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Mastering Puppet 5

You're reading from   Mastering Puppet 5 Optimize enterprise-grade environment performance with Puppet

Arrow left icon
Product type Paperback
Published in Sep 2018
Publisher Packt
ISBN-13 9781788831864
Length 292 pages
Edition 1st Edition
Tools
Arrow right icon
Authors (2):
Arrow left icon
Jason Southgate Jason Southgate
Author Profile Icon Jason Southgate
Jason Southgate
Ryan Russell-Yates Ryan Russell-Yates
Author Profile Icon Ryan Russell-Yates
Ryan Russell-Yates
Arrow right icon
View More author details
Toc

Table of Contents (14) Chapters Close

Preface 1. Authoring Modules FREE CHAPTER 2. Roles and Profiles 3. Extending Puppet 4. Hiera 5 5. Managing Code 6. Workflow 7. Continuous Integration 8. Extending Puppet with Tasks and Discovery 9. Exported Resources 10. Application Orchestration 11. Scaling Puppet 12. Troubleshooting and Profiling 13. Other Books You May Enjoy

Using good module and class structure

This section contains a set of recommendations surrounding good module and class design. Bear in mind that Puppet development is, in principle, just like any other type of software development, and we've learned over many years in software development, and especially at O&O software, that certain modular and class design principles make our development better. I also feel that part of our journey toward infrastructure as code is making our Puppet code just as well-designed, structured, and tested as any other application code.

Following the class-naming conventions

There's a certain class-naming convention that has developed over time within the Puppet community, and it's really worth taking these into account when structuring your classes:

  • init.pp: init.pp contains the class named the same as the module, and is the main entry point for the module.
  • params.pp: The params.pp pattern (more on this later in the chapter) is an elegant little hack, taking advantage of Puppet's class inheritance behavior. Any of the other classes in the module inherit from the params class, so have their parameters set appropriately.
  • install.pp: The resources related to installing the software should be placed in an install class. The install class must be named <modulename>::install and must be located in the install.pp file.
  • config.pp: The resources related to configuring the installed software should be placed in a config class. The config class must be named <modulename>::config and must be located in the config.pp file.
  • service.pp: The resources related to managing the service for the software should be placed in a service class. The service class must be named <modulename>::service and must be located in the service.pp file.

For software that is configured in a client/server style, see the following:

  • <modulename>::client::install and <modulename>::server::install would be the class names for the install.pp file placed in the client and server directories accordingly
  • <modulename>::client::config and <modulename>::server::install would be the class names for the config.pp file placed in the client and server directories accordingly
  • <modulename>::client::service and <modulename>::server::service would be the class names for the service.pp files placed in the client and server directories accordingly

Having a single point of entry to the module

init.pp should be the single entry point for the module. In this way, someone reviewing the documentation in particular, as well as the code in init.pp, can have a complete overview of the module's behavior.

If you've used encapsulation effectively and used descriptive class names, you can get a very good sense just by looking at init.pp of how the module actually manages the software.

Modules that have configurable parameters should be configurable in a single way and in this single place. The only exception to this would be, for example, a module such as the Apache module, where one or more virtual directories are also configurable.

Ideally, you can use your module with a simple include statement, as follows:

include mymodule

You can also use it with the use of a class declaration, as follows:

class {'mymodule':
myparam => false,
}

The Apache virtual directory style of configuring a number of defined types would be the third way to use your new module:

mymodule::mydefine {‘define1':
myotherparam => false,
}

The anti-pattern to this recommendation would be to have a number of classes other than init.pp and your defined types with parameters expecting to be set.

Using high cohesion and loose coupling principles

As far as possible, Puppet modules should be made up of classes with a single responsibility. In software engineering, we call this high, functional cohesion. Cohesion in software engineering is the degree to which the elements of a certain module belong together. Try to make each class have a single responsibility, and don't arbitrarily mix together unrelated functionalities in your classes.

Using the encapsulation principle

As far as possible, these classes should use encapsulation to hide the implementation details from the user; for example, users of your module don't need to be aware of individual resource names. In software engineering, we call this encapsulation. For example, in a config class, we can use several resources, but the user doesn't need to know all about them. Rather, they just simply know that they should use the config class for the configuration of the software to work correctly.

Having classes contain other classes can be very useful, especially in larger modules where you want to improve code readability. You can move chunks of functionality into separate files, and then use the contain keyword to refer to these separated chunks of functionality.

See https://puppet.com/docs/puppet/5.3/lang_containment.html website for a reminder about the contain keyword.

Providing sensible, well-thought-out parameter defaults

If the vast majority of the people using your module will use the module with a certain parameter set, then of course it makes sense to set that parameter with a default.

Carefully think through how your module is used, and put yourself in the position of a nonexpert user of your own module.

Present the available module parameters in a sensible order, with more often accessed settings before least accessed settings, as opposed to some arbitrary order, such as alphabetical order.

Strongly typing your module variables

In versions of Puppet proper to the new language features which came out in version 4, we would create class parameters with undefined data types, and then, if we were being very nice, we would use the stdlib validate_<datatype> functions to check appropriate values for those variables:

class vhost (
$servername,
$serveraliases,
$port
)
{ ...

Puppet 4 and 5 have an in-built way of defining the data type that a parameterized class accepts. See the following example:

class vhost (
String $servername,
Array $serveraliases,
Integer $port
)
{ ...
You have been reading a chapter from
Mastering Puppet 5
Published in: Sep 2018
Publisher: Packt
ISBN-13: 9781788831864
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image