Puppet: System Administration Automated

Puppet Training Schedule
Next Class July 27-29
New York, New York
Discount before July 1st

Transitioning From Cfengine: Puppet and Cfengine integration

For those who are still using Cfengine but would like either to take advantage of Puppet's greater abstractive or modeling capabilities, we have created a Cfengine module that can connect the two tools.

How to Use It

This module works by taking the classes set in Cfengine and using them in Puppet. Cfengine automatically sets quite a few classes for you, and you can set any custom classes you want; you can reuse this class structure to decide what to do within Puppet.

Puppet treats classes somewhat differently from Cfengine; they look like classes in most other languages, in that they are syntactical elements that wrap other Puppet code, like so:

class apache {
    package { apache: ensure => installed }
    service { apache: ensure => running }
}

Puppet classes can be organized in any file structure; I usually put each class in a separate file in a classes subdirectory and load the whole directory at once:

# site.pp
import "classes/*"

Setting Up Cfengine

Currently, the module must be retrieved from subversion or from the online [source:/trunk/ext/module_puppet source viewer].

It must be placed into Cfengine's module directory (which, I believe, still defaults to /var/cfengine/modules. If you have not used modules in Cfengine before, you will have to set up Cfengine to pull this extra directory down in your update.conf file, most likely.

In addition, you'll want to pull all of your Puppet manifests down. This doesn't necessarily need to be done in the update.conf file, but it'd likely make your life easier if it were, since then you don't have to worry about ordering. It's also probably a good idea to follow the same basic structure that Puppet already uses, naming your topmost file site.pp. The location of the files is not terribly important, so we'll use /var/puppet/manifests in the examples.

Once the module is set up, execute it:

control:
    actionsequence = (
        "module_puppet /var/puppet/manifests/site.pp"
    )

It is up to you where this code is in your configuration, and you might need to rename the module to module:puppet; check the Cfengine documentation.

By default, the module will just load classes set in cfengine, but you can add --no-nodes to have it load node configurations if desired (see the rest of the Puppet documentation for more detail) and of course you can set classes in Puppet based on the Cfengine classes..

Setting Up Puppet

Once Cfengine is configured properly, you need to add the appropriate classes to Puppet. Cfengine will be passing Puppet a list of all enabled classes, and Puppet will search for any defined classes named for any of those defined classes. Only classes that are set in Cfengine and exist in Puppet will be applied; classes that are only set in Cfengine or only defined in Puppet will not throw errors, they will just be ignored.

Let's say you're running this module on your mail server; you could set the mailserver class in Cfengine and then create a mailserver class in Puppet:

class mailserver {
    file { "/etc/courier-imap":
        source => "...",
        recurse => true
    }
    package { courier-imap: ensure => installed }
    service { courier-imap:
        ensure => running,
        subscribe => [file["/etc/courier-imap"], package[courier-imap]]
    }
}

If the mailserver class is set in Cfengine, the Puppet module will automatically apply this class, which pulls down the configuration files, installs the package, and starts the service for courier-imap. The subscribe parameter causes Puppet to restart the courier-imap service if the configuration files or the package change (notice how much easier this service restart is than it would be in Cfengine), and it also makes sure that the configuration files are synchronized before the service is started (ordering in Puppet is easily specified using the subscribe, require, notify, and before parameters).

Where to Use Puppet

Puppet was largely developed as a successor to Cfengine, based on years of Cfengine consulting and development; as a result, it overcomes some significant shortcomings in Cfengine, and it makes the most sense to use Puppet in those places where Cfengine is weakest. Specifically, Puppet provides higher-level types than Cfengine, supports high-level abstractions akin to functions, and makes it easy to define your own custom types?.

Generally, it's probably best to start out using Puppet to manage elements that Cfengine cannot manage or is not good at managing, such as users, groups, and packages (I know Cfengine can manage a couple of package types, but Puppet supports more types more flexibly). Also, managing services and their dependencies can get very convoluted in Cfengine but are specified directly in Puppet so they're a bit easier to manage.

If you already have your own custom Cfengine modules for managing other types, it might also make sense to rewrite these as Puppet types since your custom types are treated as first-class types within Puppet's language, rather then being restricted to use Cfengine's shell-script module interface.

If you are using a templating system with Cfengine or are generating your Cfengine configurations somehow, you might be especially happy with this Puppet module, since you can create reusable types with external templates. For an example, see the Puppet vs. Cfengine comparison.

Transitioning

It should be possible to use this module to slowly transition from a pure Cfengine implementation to a pure Puppet implementation. The easiest code to transition will be those types that both tools support, like files, or which Puppet supports as a superset of Cfengine's support, such as services. The hardest code to transition will be editfiles code, since Puppet does not and probably never will provide an analogous feature. Instead, you will need to use something like external templates or create custom Puppet types.

The more code you transition to being within Puppet, however, the easier your configuration should be to maintain and develop. If there is functionality in Cfengine that you cannot find a way to replicate within Puppet, please join the users list or #puppet on irc.freenode.net and ask for help.