Making Standard Resources Overwritable In Your Own Puppet Modules

Want to help support this blog? Try out Oh Dear, the best all-in-one monitoring tool for your entire website, co-founded by me (the guy that wrote this blogpost). Start with a 10-day trial, no strings attached.

We offer uptime monitoring, SSL checks, broken links checking, performance & cronjob monitoring, branded status pages & so much more. Try us out today!

Profile image of Mattias Geniar

Mattias Geniar, January 05, 2015

Follow me on Twitter as @mattiasgeniar

Let’s say you have a module where some “standard” resources are being managed (file/user/package/...). In those resources, you want to make some attributes overwritable, but only as optional arguments. So if the arguments aren’t supplied in your own module, the OS/Puppet default values should be used instead.

It’s hard to explain in words, but an example would make it more clear. Here’s what you actually want to do (even though it’s invalid puppet code).

class mymodule (
  $gid = undef,
  $uid = undef,
)
  user { 'myuser':
    ensure => present,
    uid    => $uid,
  }

  group { 'mygroup':
    ensure => present,
    gid    => $gid,
  }
}

If the $gid or $uid parameters are not supplied in your mymodule module, Puppet should just use the “default” values. So you want to make these arguments optional. There are some default values you could be tempted to use, like nill, undef, … in the parameter list of your module, but they won’t work.

Your Puppet run will most likely end up like this and your catalog compilation will fail.

$ puppet agent -vt 
...
Error: Failed to apply catalog: Parameter gid failed on Group[mygroup]: Invalid GID  at /etc/puppet/modules/mymodule/manifests/init.pp:8

The solution is to reference the already-defined resource and amend the attributes you want to manage to it. That would mean the example above can be extended to look like this (which includes the stdlib module from puppetlabs for input validation).

class mymodule (
  $gid = undef,
  $uid = undef,
)
  include stdlib

  user { 'myuser':
    ensure => present,
  }

  if (is_integer($uid)) {
    # If the supplied UID is an integer, extend the previous resource with the uid
    # Otherwise, don't try to manage the attribute and leave it at the defaults / untouched
    User [ 'myuser' ] {
      uid => $uid,
    }
  }

  group { 'mygroup':
    ensure => present,
  }

  if (is_integer($gid)) {
    # If the supplied GID is an integer, extend the previous resource with the GID
    # Otherwise, don't try to manage the attribute and leave it at the defaults / untouched
    Group [ 'mygroup' ] {
      gid => $gid,
    }
  }
}

This does mean your module code gets large pretty quickly, as each “optional” attribute needs to be checked / validated (but you do that for every parameter already, right?) before it’ll be managed.

I’m actually hoping that I’m missing a more obvious solution to this problem, because with a few “default” resources in your modules, the parameter-list grows very quickly, and the amount of if statements grows with it – each managing a new resource attribute.

You can test each puppet resource parameter at the CLI to test your supplied values.



Want to subscribe to the cron.weekly newsletter?

I write a weekly-ish newsletter on Linux, open source & webdevelopment called cron.weekly.

It features the latest news, guides & tutorials and new open source projects. You can sign up via email below.

No spam. Just some good, practical Linux & open source content.