Puppet is an open source configuration management tool written in Ruby. It allows a systems administrator to define how a system should be configured using Puppet's declarative language. Each Puppet client pulls its catalog at a regular interval and figures out how to make the catalog definitions true for the local operating system.
The Puppet Introduction uses the following diagram to show how Puppet works.
Currently Puppet is most useful when you have lots of nodes with similar setups. Unfortunately Puppet's declarative language is a bit weak when it comes to inheritance and users familiar with true object oriented systems will soon become frustrated (at least I did). I'm assuming this issue will be addressed in the future, but for now I'm going to tell you how I setup a 100+ node system while adhering to DRY principles.
A quick note, I'm assuming you already know how to use Puppet.
First lets start with the Puppetmaster configuration layout:
puppet/ - fileserver.conf - manifests/ - classes/ - initialize.pp - nodes/ - net/ - example/ - web01.pp # web01.example.net - site.pp - templates.pp - modules/ # application specific modules - httpd/ - files/ # static assets (ex: default HTML file) - manifests/ # application configuration logic - templates/ # dynamic configuration files (ex: httpd.conf)
The layout was adapted from recommendations in Pulling Strings with Puppet by James Turnbull.
When I was initially designing my Puppet setup the common practice was to define and initialize the various Puppet types and classes throughout the inheritance tree. So if you had a generic resolv.conf configuration you would include it at the top of the inheritance tree. This worked great until I needed to change one attribute of a class further down. I initially tackled this problem by hacking in if/case statements, but eventually it became unmanageable.
After a couple of rewrites I came up with the idea of wrapping the internals of each class in a conditional statement and initializing all classes at the end of each node.
The key components of my setup were:
This lets you both arbitrarily redefine or extend class attributes (including the on/off state) throughout the inheritance tree.
I've created a simple example to show how this setup works. The main files are listed below (you'll want to go through each in order):
Also note that I designed this setup about 8 months ago and I haven't kept as up-to-date on recent developments as I should. If there is a better way to do this please let me know.