Reducing Coupling between modules
In the past, several of my Puppet modules have been tightly coupled. A perfect example is Apache and Munin. When I install Apache, I want munin graphs set up. As a result my apache class has the following snippet in it:
munin::plugin { "apache_accesses": }
munin::plugin { "apache_processes": }
munin::plugin { "apache_volume": }
This should make sure that these three plugins are installed and that munin-node is restarted to pick them up. The define was implemented like this:
define munin::plugin (
$enable = true,
$plugin_name = false,
) {
include munin::node
file { "/etc/munin/plugins/$name":
ensure => $enable ? {
true => $plugin_name ? {
false => "/usr/share/munin/plugins/$name",
default => "/usr/share/munin/plugins/$plugin_name"
},
default => absent
},
links => manage,
require => Package["munin-node"],
notify => Service["munin-node"],
}
}
(Note: this is a slight simplification of the define). As you can see, the define includes munin::node, as it needs the definition of the munin-node service and package. As a result of this, installing Apache drags in munin-node on your server too. It would be much nicer if the apache class only installed the munin plugins if you also install munin on the server.
It turns out that is is possible, using virtual resources. Virtual resources allow you to define resources in one place, but not make them happen unless you realise them. Using this, we can make the file resource in the munin::plugin virtual and realise it in our munin::node class. Our new munin::plugin looks like:
define munin::plugin (
$enable = true,
$plugin_name = false,
) {
# removed "include munin::node"
# Added @ in front of the resource to declare it as virtual
@file { "/etc/munin/plugins/$name":
ensure => $enable ? {
true => $plugin_name ? {
false => "/usr/share/munin/plugins/$name",
default => "/usr/share/munin/plugins/$plugin_name"
},
default => absent
},
links => manage,
require => Package["munin-node"],
notify => Service["munin-node"],
tag => munin-plugin,
}
}
We add the following line to our munin::node class:
File<| tag == munin-plugin |>
The odd syntax in the munin::node class realises all the virtual resources that match the filter, in this case, any that is tagged munin-plugin. We've had to define this tag ourself, as the auto-generated tags don't seem to work. You'll also notice that we've removed the munin::node include from the munin::plugin define, which means that we no longer install munin-node just by using the plugin define. I've used a similar technique for logcheck, so additional rules are not installed unless I've installed logcheck. I'm sure there are several other places where I can use it to reduce such tight coupling between classes.