The parameters dilemma

In modules, we typically set up applications: most of the time this is done by installing packages, configuring files and managing services.

We can write a module that makes exactly what we need for our working scenario or we can try to design it having in mind that people with different needs and infrastructures may use it.

These people might be us in the future, when we'll have to manage a Puppet setup for another project or cope with different kinds of servers, or manage unexpected or nonstandard requirements, and we might regret not having written our code in an abstract enough and reusable way.

Basically, parameters, being our API to the module's functionality, are needed for exactly this: to let modules behave in different ways and do different things according to the values provided by users.

Hypothetically, we could enforce inside our code exactly what we need and therefore do this without the need of having any parameter. Maybe our code could be simpler to use and read at the beginning, but this would be a technical debt we will have to pay, sooner or later.

So we need parameters, and we need them to allow users' customization of what the module does, in order to adapt it to different use cases.

Still it is not so obvious to define what parameters to use and where to place them, let's review some possible cases.

There might be different kinds of parameters, which can be as follows:

  • Manage variables that provide the main configuration settings for an application (ntp_server, munin_server, and so on)
  • Manage most or all configuration settings for an application (for a sample ntp.conf they would be driftfile, statistics, server, restrict, and so on)
  • Manage triggers that define which components of the module should be used (install_server, enable_passenger, and so on)
  • Manage the attributes of the resources declared inside a class or define (config_file_source, package_name, and so on)
  • Manage the behavior of the module or some of its components (service_autorestart, debug, ensure, and so on)
  • Manage external parameters related to applications, references or classes (db_server, db_user, and so on) not directly managed by the module, but needed to configure its application

There are also various places where these parameters can be exposed and can act as entry points where to feed our configuration data:

  • The main module's class, defined in the init.pp file
  • Single sub classes which may act as single responsibility points for specific features (class names like modulename::server and modulename::db::mysql, with their own parameters that can be directly set)
  • Configuration classes, used as entry points for various settings, to override modules' defaults (modulename::settings, modulename::globals)
  • Normal defines provided by the module

There is not an established and common structure or agreement regarding the kind of parameters and where to expose them.

They depend upon several factors, but the main design decision that the module's author has to make, which heavily affects the kind of parameters to expose, is how configurations are provided: are they file-based or setting-based?

File-based configurations expect the module to manage the application configuration via files, generally provided as ERB templates whose content is derived from the parameters exposed by the classes or defines that use it.

Setting-based configurations have a more granular approach: the application configuration files are managed as single configuration entries, typically single lines, which compose the final file.

In the first case, where files are managed as a whole, the module's classes should:

  • Expose parameters that define at least the application's main settings and, optionally, most or all the other settings, as long as they are managed in the default template
  • Allow users to provide a custom template that overrides the module's default one, and can be used to manage custom settings which are not manageable via parameters
  • Allow users to provide configurations as plain static files, to serve via the source argument, since some users may prefer to manage configuration files as is

In the second case, the module should do the following:

  • Provide native or defined types that allow manipulation of single lines inside a configuration file
  • Eventually provide classes (either a single main class or many subclasses) that expose as parameters all the possible configuration settings for the managed application (they might be many and hard to keep updated)

Note

I don't have a clear answer on what would be the preferred approach; I suppose it depends on the kind of managed application, the user's preference, and the complexity and structure of the configuration files.

The good news is that a module's author can accommodate both the approaches and leave the choice to the user.

Naming standards

The modules ecosystem has grown erratically, with many people redoing modules for the same application, either forking existing ones or developing them from scratch.

In this case, quantity is not a plus: there's really no advantage for Puppet users to have dozens of different modules for a single application, written with different layouts, parameters names, entry points, OS coverage, and features sets.

Even worse, when we use modules that have dependencies on other modules (as described in Modulefile), we may quickly end up having conflicts that may prevent us from installing a module with the puppet module tool and force us to fork and fix, just for our case.

Module interoperability is a wider issue which has not yet been solved, but there is something that can be done if there is the common will: an attempt to standardize naming conventions for modules' class and parameters names.

The various benefits are as follows:

  • Saner and simpler user experience
  • Easier module interoperability
  • Suggested reusability patterns
  • Predictability in usage and development.

It's common sense that such an effort should be driven by Puppet Labs, but for the moment, it remains a community effort, under the label stdmod: https://github.com/stdmod.

The naming conventions defined there embrace some standard de facto naming and try to define general rules for parameters and class names. For the ones that affect the resource arguments, the pattern is [prefix_]resource_attribute, so these may be some parameters names:

config_file_path, config_file_content, package_name, init_config_file_path, client_package_name

Many other names are defined; the basic principle is that a stdmod compliant module is not expected to have them all, but if it exposes parameters that have the same functions, it should call them as defined by the standard.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset