Module Development¶
This chapter covers the pieces that turn a basic module into a full-featured one: defined types, type aliases, custom facts, functions, custom types and providers, tasks, and plans.
Module anatomy¶
A basic module has this structure:
modulename/
├── metadata.json
├── manifests/
│ ├── init.pp
│ └── subclass.pp
├── files/
├── templates/
├── README.md
├── lib/
│ └── facter/
├── facts.d/
├── examples/
│ ├── init.pp
│ └── subclass.pp
├── Gemfile
├── Rakefile
└── spec/
├── classes/
│ └── init_spec.rb
└── spec_helper.rb
A more advanced module adds directories for the extensions covered in this chapter:
modulename/
├── types/
├── manifests/
│ ├── init.pp
│ ├── subclass.pp
│ └── resourcetype.pp
├── functions/
├── lib/
│ ├── facter/
│ └── puppet/
│ ├── functions/
│ ├── type/
│ └── provider/
└── spec/
├── acceptance/
│ ├── init_spec.rb
│ └── nodesets/
│ └── default.yml
├── classes/
│ └── init_spec.rb
└── spec_helper.rb
This adds types/ (type aliases), resourcetype.pp (defined resource types),
functions/ (native functions), lib/puppet/ (Ruby functions, custom types,
and providers), and spec/acceptance/ (acceptance tests).
Note
The Puppet language uses the word "type" for several different things — data types, type aliases, defined resource types, and custom resource types. Watch the context.
Type aliases¶
Type aliases create custom data types based on the built-in data types:
Defined resource types¶
Defined resource types are blocks of native Puppet code that work like built-in resources:
# mymodule/manifests/gem.pp
define mymodule::gem (
String $ensure = 'installed',
) {
package { $title:
ensure => $ensure,
provider => 'gem',
}
}
They are also referred to as defined types or just defines. Scaffold a new one with:
Functions¶
Functions take optional arguments and return a result. They are executed at compile time — on the OpenVox server in a typical server/agent configuration. OpenVox supports native (Puppet-language) functions and Ruby functions.
Native functions¶
Native functions are written in the Puppet language and live in a module's
functions/ directory:
# mymodule/functions/first_interface.pp
# Usage:
# mymodule::first_interface($facts['networking']['interfaces'])
function mymodule::first_interface(Hash $ifaces) >> String {
$iface = $ifaces.filter | $i | {
$i[1].dig('bindings', 0, 'address') != undef
}.keys().delete_regex('^lo$|\.[0-9]+$|^docker[0-9]')
$iface[0]
}
Writing functions in the Puppet language
Ruby functions¶
Ruby functions live in lib/puppet/functions/ in your module. They can live in
a module's namespace, but are not required to.
Ruby function overview · Signatures · Implementation
Custom facts¶
Facts are Ruby scripts that add data to the $facts hash. Unlike functions,
facts are executed on the OpenVox agent:
# dnsmasq/lib/facter/dnsmasq_version.rb
Facter.add(:dnsmasq_version) do
setcode do
begin
value = `dnsmasq --version`
if $CHILD_STATUS.exitstatus != 0
nil
else
match = %r{^Dnsmasq version\s+(\S+)\s}.match(value)
match[1]
end
rescue
nil
end
end
end
Custom types and providers¶
Custom types extend the resource types available in OpenVox. Providers are implementations of custom types that allow for portability across platforms. They are included in modules in these locations:
lib/puppet/type/lib/puppet/provider/
Custom types · Provider development
Tasks¶
A task consists of two parts: the script itself, and a JSON file containing metadata about the script (such as the available parameters). Scaffold one with:
This creates tasks/mytask.sh (the script) and tasks/mytask.json (the
metadata):
{
"puppet_task_version": 1,
"supports_noop": false,
"description": "A short description of this task",
"parameters": {
}
}
Tasks can be written in any language available on the agent. They are
namespaced to the module they ship with, so the example above would be called
mymodule::mytask.
Plans¶
Plans are written in the Puppet language but are executed by the bolt
command-line tool (OpenBolt). Plans can include logic, and they can execute
tasks or apply Puppet code to one or more nodes in a sequence defined by the
plan.