2

Adventures in Puppet: concat module

Posted on Wednesday, 4 August 2010

R.I. Pienaar has a Puppet module on github called "concat". Its premise is very simple, it just concatenates fragments of text together into a particular file.

I'm sure that a more seasoned Puppet veteran would have had this running in no time, but since it introduced some new concepts for me, I thought I'd throw up some notes of how I'm using it. I was particularly interested in an example usage I saw which lists the puppet modules a system is using in its /etc/motd, but because of the way Ubuntu handles constructing the motd, I needed to slightly rework the example. In Ubuntu, the /etc/motd file is constructed dynamically when you log in - this is done by pam_motd which executes the scripts in /etc/update-motd.d/. One of those scripts (99-footer) will simply append the contents of /etc/motd.tail to /etc/motd after everything else - my example will take advantage of this. If you are already using motd.tail, you could just have this puppet system write to a different file and then drop another script into /etc/update-motd.d/ to append the contents of that different file.

This is what I did:


  • git clone http://github.com/ripienaar/puppet-concat.git

  • Move the resulting git branch to /etc/puppet/modules/concat and add it to my top-level site manifest that includes modules

  • Create a class to manage /etc/motd.tail. In my setup this ends up being /etc/puppet/manifests/classes/motd.pp, which is included by my default node, but your setup is probably different. This is what my class looks like:


class motd {
include concat::setup
$motdfile = "/etc/motd.tail"

concat{$motdfile:
owner => root,
group => root,
mode => 644
}

concat::fragment{"motd_header":
target => $motdfile,
content => "\nPuppet modules: ",
order => 10,
}

concat::fragment{"motd_footer":
target => $motdfile,
content => "\n\n",
order => 90,
}
}

# used by other modules to register themselves in the motd
define motd::register($content="", $order=20) {
if $content == "" {
$body = $name
} else {
$body = $content
}

concat::fragment{"motd_fragment_$name":
target => "/etc/motd.tail",
content => "$body ",
order => $order
}
}

So that's quite a mouthful. Let's break it down:

  • We have to include concat::setup so the concat module can...set... up :)

  • We then set a variable pointing at the location of the file we want to manage

  • We then instantiate the concat module for the file we want to manage and set properties like the ownership/mode

  • We then call the concat::fragment function for two specific fragments we want in the output - a header and a footer (although I do this on a single line, so it's the phrase "Puppet modules" and "\n\n" respectively). They're forced to be header/footer by the "order" parameter - by making sure we use a low number for the header and a high number for the footer, we get the layout we expect.

  • Outsite this class we define a function motd::register which other modules will call and the content they supply will be handed to concat::fragment with a default order parameter of 20 (which is higher than the value we used for the header and lower than the footer one).


Finally, in each of my modules I include the line:
motd::register{"someawesomemodule":}

and now when I ssh to a node, I see a line like:
Puppet modules: web ssh 

It's a fairly simple little thing, but quite pleasing and from here out it's almost zero effort - just adding the motd::register calls to each module.

Discussion