Module design practices
Consistent module design practices makes module contributions easier.
Spacing, indentation, and whitespace
Module manifests should follow best practices for spacing, indentation, and whitespace.
Manifests:
- Must use two-space soft tabs.
- Must not use literal tab characters.
- Must not contain trailing whitespace.
- Must include trailing commas after all resource attributes and parameter definitions.
- Must end the last line with a new line.
- Must use one space between the resource type and opening brace, one space between the
opening brace and the title, and no spaces between the title and
colon.
Good:
file { '/tmp/sample':
Bad: Space between title and colon:file { '/tmp/sample' :
Bad: No spaces:file{'/tmp/sample':
Bad: Too many spaces:file { '/tmp/sample':
-
Should not exceed a 140-character line width, except where such a limit would be impractical.
-
Should leave one empty line between resources, except when using dependency chains.
-
May align hash rockets (
=>
) within blocks of attributes, one space after the longest resource key, arranging hashes for maximum readability first.
Arrays and hashes
To increase readability of arrays and hashes, it is almost always beneficial to break up the elements on separate lines.
Use a single line only if that results in overall better readability of the construct where it appears, such as when it is very short. When breaking arrays and hashes, they should have:
Each element on its own line.
Each new element line indented one level.
First and last lines used only for the syntax of that data type.
Good: Array with multiple elements on multiple lines:
service { 'sshd': require => [ Package['openssh-server'], File['/etc/ssh/sshd_config'], ], }Good: Hash with multiple elements on multiple lines:
$myhash = { key => 'some value', other_key => 'some other value', }Bad: Array with multiple elements on same line:
service { 'sshd': require => [ Package['openssh-server'], File['/etc/ssh/sshd_config'], ], }Bad: Hash with multiple elements on same line:
$myhash = { key => 'some value', other_key => 'some other value', }Bad: Array with multiple elements on different lines, but syntax and element share a line:
service { 'sshd': require => [ Package['openssh-server'], File['/etc/ssh/sshd_config'], ], }Bad: Hash with multiple elements on different lines, but syntax and element share a line:
$myhash = { key => 'some value', other_key => 'some other value', }Bad: Array with an indention of elements past two spaces:
service { 'sshd': require => [ Package['openssh-server'], File['/etc/ssh/sshd_config'], ], }
Quoting
As long you are consistent, strings may be enclosed in single or double quotes, depending on your preference.
Regardless of your preferred quoting style, all variables MUST be enclosed in braces when interpolated in a string.
For example:
Good:
"/etc/${file}.conf"
"${facts['operatingsystem']} is not supported by ${module_name}"
Bad:
"/etc/$file.conf"
Option 1: Prefer single quotes
Modules that adopt this string quoting style MUST enclose all strings in single quotes, except as listed below.
For example:
Good:
owner => 'root'Bad:
owner => "root"
A string MUST be enclosed in double quotes if it:
-
Contains variable interpolations.
-
Good:
"/etc/${file}.conf"
-
Bad:
'/etc/${file}.conf'
-
-
Contains escaped characters not supported by single-quoted strings.
-
Good:
content => "nameserver 8.8.8.8\n"
-
Bad:
content => 'nameserver 8.8.8.8\n'
-
A string SHOULD be enclosed in double quotes if it:
-
Contains single quotes.
-
Good:
warning("Class['apache'] parameter purge_vdir is deprecated in favor of purge_configs")
-
Bad:
warning('Class[\'apache\'] parameter purge_vdir is deprecated in favor of purge_configs')
-
Option 2: Prefer double quotes
Modules that adopt this string quoting style MUST enclose all strings in double quotes, except as listed below.
For example:
Good:
owner => "root"
Bad:
owner => 'root'
A string SHOULD be enclosed in single quotes if it does not contain variable interpolations AND it:
-
Contains double quotes.
-
Good:
warning('Class["apache"] parameter purge_vdir is deprecated in favor of purge_configs')
-
Bad:
warning("Class[\"apache\"] parameter purge_vdir is deprecated in favor of purge_configs")
-
-
Contains literal backslash characters that are not intended to be part of an escape sequence.
-
Good:
path => 'c:\windows\system32'
-
Bad:
path => "c:\\windows\\system32"
-
If a string is a value from an enumerable set of options, such as present
and absent
, it SHOULD NOT be enclosed in
quotes at all.
For example:
Good:
ensure => presentBad:
ensure => "present"
Escape characters
Use backslash (\
) as an escape character.
For both single- and double-quoted strings, escape the backslash to remove this special
meaning: \\
This means that for every backslash
you want to include in the resulting string, use two backslashes. As an example, to include
two literal backslashes in the string, you would use four backslashes in total.
Do not rely on unrecognized escaped characters as a method for including the backslash and the character following it.
Unicode character escapes using fewer than 4 hex digits, as in \u040
, results in a backslash followed by the string u040
. (This also causes a warning for the unrecognized escape.) To use a number
of hex digits not equal to 4, use the longer u{digits}
format.
Comments
Comments must be hash comments (# This is a comment
).
Comments should explain the why, not the how, of your code.
Do not use /* */
comments in Puppet code.
Good:
# Configures NTP file { '/etc/ntp.conf': ... }Bad:
/* Creates file /etc/ntp.conf */ file { '/etc/ntp.conf': ... }
Functions
Avoid the inline_template()
and inline_epp()
functions for templates of more than one line,
because these functions don’t permit template validation. Instead, use the template()
and epp()
functions to read a template from the module. This method allows for
syntax validation.
You should avoid using calls to Hiera functions in modules meant for public consumption, because not all users have implemented Hiera. Instead, we recommend using parameters that can be overridden with Hiera.
Improving readability when chaining functions
In most cases, especially if blocks are short, we recommend keeping functions on the same line. If you have a particularly long chain of operations or block that you find difficult to read, you can break it up on multiples lines to improve readability. As long as your formatting is consistent throughout the chain, it is up to your own judgment.
For example, this:
$foodgroups.fruit.vegetablesIs better than this:
$foodgroups .fruit .vegetablesBut, this:
$foods = { "avocado" => "fruit", "eggplant" => "vegetable", "strawberry" => "fruit", "raspberry" => "fruit", } $berries = $foods.filter |$name, $kind| { # Choose only fruits $kind == "fruit" }.map |$name, $kind| { # Return array of capitalized fruits String($name, "%c") }.filter |$fruit| { # Only keep fruits named "berry" $fruit =~ /berry$/ }Is better than this:
$foods = { "avocado" => "fruit", "eggplant" => "vegetable", "strawberry" => "fruit", "raspberry" => "fruit", } $berries = $foods.filter |$name, $kind| { $kind == "fruit" }.map |$name, $kind| { String($name, "%c") }.filter |$fruit| { $fruit =~ /berry$/ }
Related information