Servers Dance on a String With Puppet

Puppet is a secure configuration management tool for Unix-like operating systems, with features that will undoubtedly mark it for fame. Puppet has been around for nearly two years now, and has claimed a large share of cfengine converts. As mentioned last week, its configuration is more of a specification than a set of instructions, designed to make managing large groups of servers and services more than just tolerable—it can completely streamline an infrastructure.

Puppet runs fully on Solaris, FreeBSD, OpenBSD, Linux and OS X; and partially on others. Puppet itself is written in Ruby, but it understands nuances of each operating system, so you can say things like, “create user phil,” and it will know how. You don’t actually need to copy shadow and passwd files all over the place to make client-specific user accounts appear, as with some other configuration management tools. The part of Puppet that gets “ported” to each operating system is called “providers.” The User provider understands how to create users in each of the above platforms.

That being said, Puppet is widely used to just manage files, too. You could run Puppet on anything with a Ruby interpreter, in theory, as long as you don’t tell it to run anything it doesn’t have specific providers for on that platform.

The Concept
So we know about providers now; that’s a big piece of the puzzle. Backing up a few meters, if we take a look at Puppet from above, we’ll see two things: puppetmasterd, the master server; and puppetd, running on a few client machines. The puppetmaster is the configuration server, where all your configurations are stored, and where all the puppetd processes running on your network will look for their configurations.

When a Puppet client starts, it’ll look for the puppetmaster server, and attempt to contact it, via HTTP over SSL. The client’s SSL certificate will be validated, and if it’s a known client, it will be given a configuration. The puppet (running on a client machine) will parse the configuration it was given, and then begin applying changes. If everything went well, it’ll just sit idle until its next scheduled check-in time. The process repeats, by default, every 30 minutes. If the Puppet client doesn’t have a signed certificate, all it can do is submit a cert for signing to the master. After a quick ‘puppetca –sign host‘ on the master server, the client will be authorized.

The file, /etc/puppet/manifests/site.pp is where everything begins. A manifest, as it’s called, is simply a file that includes Puppet constructs. Within site.pp, you’ll start by saying: import “debian.pp” for example, to imports the debian.pp manifest. Often you’ll define a node (hostname or names of servers) in site.pp, and then specify that the node should include a class. Nodes can also inherit classes; explanations coming soon.

A class in Puppet is basically the same as the concept of a class in object-oriented programming languages. Let’s assume that the imported manifest debian.pp contained a class definition like so:
class debian {}

Of course there would be things within the curly braces, but this is the base case. Now, within a node definition, since the debian.pp manifest was imported in site.pp, we could say “include debian” to include the debian class. The node (host) that includes the class, gets everything applied from the debian class. If the node was defined to inherit the debian class, then the same thing happens. It gets tricky when a class itself inherits another class though: that class can override things (files, etc) from the original.

The Configuration
There are some great configuration examples in the documentation, but there are concepts that require a bit of learning. For example, Puppet has its own language. It’s not something completely alien, thankfully, so anyone who has worked with a variety of configuration files and perhaps one or two scripting languages will be able to understand most of the language easily.

Being a Ruby program, Puppet’s configuration language includes many Ruby constructs. This is a Good Thing indeed.

class debian {
file { "/etc/ntp.conf":
source => "puppet://puppet/debian/etc/ntp.conf",
mode => 644, alias => linux-ntpconf
package { "ntp-server": ensure => latest }
service { "ntp-server":
ensure => true,
subscribe => File[linux-ntpconf]

The above definition of the debian class defines two types: a file, and a service. Get familiar with the type reference in the documentation, it will show you every available option for all types (providers).

The File type can be used to create symlinks, recursive copy directories, or manage a single file. In this case, we’re managing the /etc/ntp.conf file on the client machine. The source identifies where the file can be found, in this case using the built-in file server, which operates much like rsync modules. So puppet://puppet/debian/etc/ means: using the Puppet protocol, and the hostname puppet with file server module debian (starting directory that’s configured in fileserver.conf), look in the etc/ directory. We’ve also created an alias for this file, to avoid typing the whole path again.

In the next line we guarantee that the ntp-server package is installed, and that it’s the latest available. The Service type is used to make sure that the ntp-server service, as it’s called in the Debian init scripts, is running. Also, we subscribe to the file using the alias, so that if the configuration file changes, the service gets restarted.

Both the Service and Package types operate based on some default assumptions. Since we’re in Debian, Puppet knows to use apt to install the package, and also that /etc/init.d/ntp-server is the proper way to enable the service. This information is obtained from the companion program “facter,” another Ruby program that gathers system information. The really neat thing about Puppet is that you can use all the variables that facter defines (find out what they are by running facter by itself) within your Puppet manifests.

That’s just the very surface of Puppet; a few very trivial examples that have hopefully shown a bit of puppet’s power. It’s very easy to configure puppet to manage Web server configurations, local user accounts, and many other aspects of a system. Take a look at the Cookbook section of the documentation pages to get an idea of the amazing things people do with Puppet. It can even manage Solaris Zones or Linux Xen instances.

I’ve personally found that no matter how complex something is, Puppet’s language can easily express the complexity. Puppet sometimes helps to simplify, or at least causes one to rethink, unnecessary complexity.

Add to

Latest Articles

Follow Us On Social Media

Explore More