Thu, 25 Feb 2010

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.

[puppet] | # Read Comments (2) |

Comments

Well, as far as I found out, the thing you set with "tag => <string>" and the automatically assigned tags (like "sshkey" for any resource of the type sshkey, or "xyz" for any part of a class named "xyz" or "xyz::abc") seem to be completely independent. At least for us, running

puppetd --test --tags munin-plugin

(to use your example) would not create the File resource you mentioned. On the other hand, any of the tags "munin","plugin" or "file" would, if I recall correctly.

I find this a bit disturbing, as we would like to roll out only certain changes based on the tags on each run of puppetd (we don't use it as a daemon for several reasons), but that is only partly possible: It only works on automatically assigned tags, not on manually assigned ones.
Posted by Sven Mueller at Thu Feb 25 16:39:10 2010
Sven,

are you still on 0.24? There were behavioural changes regarding tags in 0.25. You should check that out.


Regards, DavidS
Posted by David Schmitt at Fri Feb 26 14:42:13 2010

Name:


E-mail:


URL:


Comment:


Please enter "fudge" to prove you are a human