Puppet is an automation framework for UNIX and UNIX-like operating systems. It allows sysadmins to automate common tasks in a centralised, efficient, and scalable way.
I’ve recently started looking into Puppet, drawing on my experience managing a large and convoluted Cfengine environment. While Cfengine is an excellent tool and certainly the best choice at the time, Puppet’s more declarative syntax makes for easier to maintain code. While in the Puppet tutorial at LCA this year, I was able to read and understand all of the example recipes without having had any real prior exposure to Puppet or Ruby.
Learning Puppet basics has required a shift in my thinking. I would waste a lot of time over a recipe trying to make Puppet ‘do’ something. Then my perspective would shift with an almost audible thunk and I’d realise where I’d gone wrong. Instead of micromanaging the mechanics of ‘doing’ things, Puppet requires you to define a state you want to acheive. It’s a suble difference, but an important one. I spent a fruitless hour trying to make Puppet create a directory before realising that I needed to tell puppet to maintain the directory.
As an example, here’s a simple class to ship out an authorized_keys file for the root user.
class ssh-keys {
file { "/root/.ssh":
ensure => "directory",
owner => "root",
group => "root",
mode => "600",
}
file { "root/.ssh/authorized_keys":
owner => "root",
group => "root",
mode => "600",
source => "puppet:///ssh-keys/authorized_keys",
}
}
This class ensures that the directory /root/.ssh exists, and has the correct permissions. It then copies out an authorized_keys file from the puppet server, stored in the ssh-keys class definition, and again ensures this file has the correct permissions.
My only real complaint about Puppet so far is that the documentation can occasionally be a little hard to follow. There are plenty of example recipes on the ‘net, but many are extremely complicated and it can be hard to find more simple examples to learn from and build apon. One area in which this was especially true was templating. I had to do quite a bit of digging around before confirming that all facter variables were accessible in templates.
Here as a simple example of using facter variables in templating is a snippet of a class for managing a resolv.conf file.
file { "/etc/resolv.conf":
owner => "root",
group => "root",
mode => "644",
content => template("resolv.erb")
}
This file management block ensures that the file /etc/resolv.conf exists, has the correct permissions, and has the content set out in the template ‘resolv.erb’.
resolv.erb:
search <%= domain %> nameserver xxx.xxx.x.x nameserver xxx.xxx.x.x
Where ‘xxx.xxx.x.x’ are valid nameserver addresses.
This simple template takes the server’s domain from facter, and inserts it in place of the variable “<%= domain %>”. Another very simple template could include:
hosts.erb:
127.0.0.1 localhost.localdmain localhost <%= ipaddress %> <%= fqdn %> <%= hostname %>
Here the template ensures the correct localhost entry, and the ‘real’ ip address and hostname of the server are listed.
Obviously there is far more that can be done with puppet than these simple beginner’s examples here. For more information, and for information on how to set up your puppet environment, see Puppetlabs.com


Pingback: Puppet, PICC, and more updates | Standalone Sysadmin
I’m in the same boat as far as learning Puppet. I did stumble across some excellent modules and documentation at http://www.example42.com/ They are attempting to build an entire example infrastructure. I think it’s much easier to figure out how to use Puppet correctly when you can see the larger picture.