Running Puppet

Last Modified: 10/06/2011, Puppet 2.6, Ubuntu 10.10

Brief Overview

Puppet is a configuration management system. You have clients (agents) and a server (puppetmaster). You can run these on the same machine (for testing/trying) or different (in reality), up to you. The communication between the two is HTTP SSL and the server defaults to port 8140. It uses it's own language to declare configuration. It has many of the same elements of ruby, python, PHP that we're all used to, so it's pretty readable. The idea is that you make changes to the configuration and puppet the clients will contact the server and get the latest configuration and implement the changes. The new configuration could could be things like adding packages, running services, creating directories and files, modifying files and/or creating/editing users.


I recommend the packages from Natty (Ubuntu version 11), even if you're on Maverick (10.04). They are the most up-to-date (2.6x) and you'll find the most help on this version of puppet. You also won't have to bother with rubygems, etc..

If you're not using Natty, you can do apt-get pinning or just download the packages manually. I didn't want things "going bump in the night", so I downloaded the packages manually and installed. I also chose to run the client (agent) as a service, some people run it via cron. The details of what I did:

Configuration and Usage

Finalizing the Plumbing

OK, you've got it installed on both sides. You need name resolution for this to work, so at minimum, the client needs to know how to get to the server, so put an entry in your hosts file on the client pointing to the server and restart the client. Now, do the following on both client and server and see that it's running.

sudo tail -f /var/log/syslog

Syslog is the main log file for puppet on both client and server and is your friend. You'll probably get a message about the certificate not being accepted on the server. You need to sign it on the server. Go over to the server and run

sudo puppetca --list

and see if the hostname of your client is there. If so, run:

sudo puppetca --sign (hostname)

Main configuration file: site.pp

This is the main file. You can do all sorts of things from here. Modules and Classes for example. For starters, though, you can put these statements in your site.pp file to get things to happen.

If you want the joe text editor to be available on your system, put this in there.

     package { 'joe':
        ensure => present,

Want to make sure apache is running? Do this:

     package { 'apache2':
             ensure => installed,

     service {
        ensure => running,
        enable => true,
        require => Package['apache2']

Want a directory to be created on the machine?

    file { '/tmp/mydir:
                ensure => directory,
                mode => 777,

You can (and should) push your own files down to your clients as well (taken from the manual):

file { "/etc/sudoers":
    mode => 440,
    owner => root,
    group => root,
    source => "puppet:///modules/module_name/sudoers"

Create a user on the box? (Notice the password hash)

      user { "joe":
           ensure     => present,
           shell      => '/bin/bash',
           home       => '/home/joe',
           managehome => true,
           password => '$6$y./0s6u8$9cftGIJhrot/0lzGNDkW1GzgJJ3tcakzDBSyMxhHyOTfQmOEHUoQiXFU0YhJAIjwS/lc0OVwf/7NPORVw1LY99',

Have a service restart when one of its config files change?

See the "trifecta" in the cheat sheet:

Testing your code before deploying

puppet --parseonly myfile.pp find /etc/puppet -name "*pp" -exec puppet --parseonly '{}' \;

More advanced configuration

The above is the gist of how it all works and is pretty powerful. You can see how this can get unruly, though, when you have 100s of packages, config files and users. Organizing your puppet config into modules and classes and using inheritance gives you the power to have "roles" for your machines that can build upon one another.

There is also the concept of nodes, so you can say things like, "I want all nodes except node3 to have this package."

Putting your code in SCM: You should check this code into a source control management system (SVN, Git, etc). My system is not that big, but deployment flow works like this:

  • Make changes to code, check it into SVN
  • SVN pre-commit hook runs puppet --parseonly on the file to make sure it is valid
  • Puppet master checks out configuration from SVN every 5 minutes
  • Clients connect and get the latest updates

    It's not perfect, but my system isn't that big and is currently internal. There are docs on scaling puppet if you're interested.


    Parameterized Classes

    The gotcha here is that you CAN'T use the include for this if you want to send in a parameter. I hate that. So, you need to do:

    node /^foo-[4-8].bar.local/ inherits default {
         notify {"${hostname} connected" : }
         class { myclass: var1 => "my value" }
         include other_class_sans_parameter

    Rebuilding a Node

    Say you need rebuild a node and want to reinstall puppet. In short, you'll get cert errors unless you do the following

    On the client
  • delete everything in /var/lib/puppet/ssl directory
  • Restart Puppet
  • On the server
  • Delete the client's previous key in /var/lib/puppet/ssl/ca/signed/
  • sudo puppetca --sign <hostname>


  • Make sure the time on the client and server match. SSL will be rejected if these don't match. You see this on VMs alot.
  • sudo tail -f /var/log/syslog
  • Scaling: Apache/Passenger

    I quickly found that WEBrick was not the way to go and that I needed Apache to handle the requests. These two links are key, with a tweak, listed below:
  • Note that the default path on Ubuntu to the puppet SSL dirs is /var/lib/puppet, not /etc/puppet as listed in that file. Also, please remember to enable the SSL options in puppet.conf. If you see "forbidden" errors in your log, that's the issue. BTW, Apache/Passenger is way faster, so it's worth the switch.


  • Puppet Cheat Sheet

    Back to Code