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:
ntp_server
, munin_server
, and so on)ntp.conf
they would be driftfile
, statistics
, server
, restrict
, and so on)install_server
, enable_passenger
, and so on)config_file_source
, package_name
, and so on)service_autorestart
, debug
, ensure
, and so on)db_server
, db_user
, and so on) not directly managed by the module, but needed to configure its applicationThere are also various places where these parameters can be exposed and can act as entry points where to feed our configuration data:
init.pp
filemodulename::server
and modulename::db::mysql
, with their own parameters that can be directly set)modulename::settings
, modulename::globals
)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:
source
argument, since some users may prefer to manage configuration files as isIn the second case, the module should do the following:
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.
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:
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.