Installing Puppet on Mac OS X

Puppet

Puppet is an open source (with enterprise version and support available)  client/server tool from Puppet Labs to facilitate the configuration and management of computer systems.

Written in ruby and available on many platforms, it offers a DSL that allows the "programming" of operational tasks across many machines.

The DSL covers abstracting the computer resources in a extensible way, and providing structure like class, modules and graphs that a configuration language can manipulate.

The server is called puppet master. It controls  a puppet agent installed on client machines that are to be managed. In addition of master and agent, there are puppet apply for stand alone use and puppet resource for accessing the Puppet resource abstraction layer.

Its extensibility makes it future proof  and there are providers (implements a resource abstraction in Puppet) for many platforms like Virtual box VMs and Amazon EC2.

The communication between clients and server is secured using SSL certificates.

This post is mainly for me so I can remember how I did install Puppet on Mac OS X and to allow me to repeat it on many mac systems.

The install  basically boils down to running a script I put on Gist (assuming you want to install Puppet 2.7.11 with Facter 1.6.6 on a startup disk called Macintosh HD):

bash -s 1.6.6 2.7.11 /Volumes/Macintosh\ HD < <(curl -s https://raw.github.com/gist/1895594/install_puppet_mac.sh)

The remainder of the post describes the gory details. I'll keep this post updated as I learn more about the idiosyncrasies of Puppet on Mac.

Deployment environment

I've tested these instructions on Mac OS X Lion (10.7.3)  and Mac OS X Snow Leopard (10.6.8).

Downloading necessary files

For Mac OS X, there is a .pkg available for Facter and Puppet downlable from Puppet Lab web site:

http://downloads.puppetlabs.com/mac/

There are several versions available on that site.

For the purpose of this post, we will consider version 1.6.6 and 2.7.11 for Facter and Puppet respectively.

Puppet depends on Facter, so you need both. These are Mac OS X package on the site above.

There is another blog post [1] describing a way to install Puppet from source but the source links didn't work for me when I tried.

Installation steps

Unpack the dmg

hdiutil attach facter-1.6.6.dmg
hdiutil attach puppet-2.7.11.dmg

Install the pkg

sudo installer -package /Volumes/facter-1.6.6/facter-1.6.6.pkg -target /Volumes/Macintosh\ HD
sudo installer -package /Volumes/puppet-2.7.11/puppet-2.7.11.pkg -target /Volumes/Macintosh\ HD

Create the puppet group and user

In other systems, the packaging may include the creation of the necessary puppet user and group.

The packages for Mac OS X don't do that. Although it's possible to create these when starting the puppet master with the --mkusers options, I prefer create then before hand during installation.

 max_gid=$(dscl . -list /Groups gid | awk '{print $2}' | sort -ug | tail -1)
 new_gid=$((max_gid+1))
 dscl . create /Groups/puppet
 dscl . create /Groups/puppet gid $new_gid




 max_uid=$(dscl . -list /Users UniqueID | awk '{print $2}' | sort -ug | tail -1)
 new_uid=$((max_uid+1))
 dscl . create /Users/puppet
 dscl . create /Users/puppet UniqueID $new_uid
 dscl . -create /Users/puppet PrimaryGroupID $new_gid

Create directories

mkdir -p /var/lib/puppet
mkdir -p /etc/puppet/manifests
mkdir -p /etc/puppet/ssl

Change permission on directories

chown -R puppet:puppet  /var/lib/puppet
chown -R puppet:puppet  /etc/puppet

Create puppet.conf

There are several sections, each relevant only to different puppet subcommands except for [main] which is global.

If puppet is running on a client ensure the server property is set to the machine running puppet master instead of local hostname as here.

echo "[main]
pluginsync = false
server = `hostname`

[master]
vardir = /var/lib/puppet
libdir = $vardir/lib
ssldir = /etc/puppet/ssl
certname = `hostname`




[agent]vardir = /var/lib/puppetlibdir = $vardir/libssldir = /etc/puppet/sslcertname = `hostname`




" > /etc/puppet/puppet.conf

Putting it all together

As I needed to install Puppet on more than one mac, I've made a script, inspired by trevmex's tutorial [1], with all the steps together:

bash -s 1.6.6 2.7.11 /Volumes/Macintosh\ HD < <(curl -s https://raw.github.com/gist/1895594/install_puppet_mac.sh)

(Some of the steps uses sudo, so login password will be asked)

In the example above  I've  passed the version of Facter, the version of Puppet and my system disk as parameter to the script.

Create a hello world puppet class

Create the file /etc/puppet/manifests/site.pp with the following content:

import "nodes"

Create the file /etc/puppet/manifests/nodes.pp with the following content:

node default {




  notify {"Hello World":;}




}

Run the example:

puppet apply /etc/puppet/manifests/site.pp

you should see something like:

notice: Hello world




notice: /Stage[main]//Node[default]/Notify[Hello world]/message: defined 'message' as 'Hello world'




notice: Finished catalog run in 0.02 seconds

Setting up puppet in client/server mode

Testing on the same computer

Run the  puppet master

sudo puppet master --verbose --no-daemonize

You should see something like:

notice: Starting Puppet master version 2.7.11

Run the puppet agent in a separate shell by typing:

sudo puppet agent --test --server=`hostname`

You should see something like:

info: Caching catalog for wall-e.home




info: Applying configuration version '1330800282'




notice: Hello world




notice: /Stage[main]//Node[default]/Notify[Hello world]/message: defined 'message' as 'Hello world'




info: Creating state file /var/lib/puppet/state/state.yaml




notice: Finished catalog run in 0.02 seconds

Between computers (or virtual machines)

install Puppet using the shell script above.

If you run the agent as above, you'll get this error:

Exiting; no certificate found and waitforcert is disabled

on the server, ensure puppet master is running, then

on the client machine, ensure puppet.conf has the server property set to the hostname of the server (or use --server in the command below) and do:

sudo puppet agent –waitforcert 60 –test --debug --no-daemonize

then on the server, on the a different shell than the on running puppet master, do:

<span class="kw2">sudo</span> puppetca <span class="re5">--sign</span> <hostname of the client machine>

until the command above is run on the server, the client will output the following message:

notice: Did not receive certificate

Then when the command to issue a certificate is run on the server, the server will output:

notice: Signed certificate request for <client host name>




notice: Removing file Puppet::SSL::CertificateRequest mc-s056627.home at '/etc/puppet/ssl/ca/requests/<client hostname>.pem'

and the client will output:

info: Caching certificate for <client hostname>

Revoking a client's privilege to connect to the Puppet master

the client certificate's name is the lowercase hostname

To revoke a client's certificate and thus deny it's connection attempts, it's a two  steps process.

First on the server, revoke the certificates:

sudo puppetca --revoke <client host name>

Then on the client, remove the certificates:

sudo rm -rf /etc/puppet/ssl

In some circumstances, you will need to use the following command to completely remove the client certificate from the master:

sudo puppet cert clean <client hostname>

Gotchas

Ruby errors:

If you encounter one of the following errors:

/usr/bin/puppet:3:in `require': no such file to load -- puppet/util/command_line (LoadError)        from /usr/bin/puppet:3/usr/sbin/puppetd:3:in `require': no such file to load -- puppet/application/agent (LoadError)        from /usr/sbin/puppetd:3

it's probably because you've got rvm installed.

You can make the problem go away by using system ruby:

rvm use system

I'm not happy about that solution, but I haven't find a better way so far.

Error about plugins when running the puppet agent:

If you see this error in the agent log:

info: Retrieving plugin




err: /File[/var/lib/puppet/lib]: Could not evaluate: Could not retrieve information from environment production source(s) puppet://wall-e.home/plugins

The puppet master log would correspondingly display this:

info: Could not find filesystem info for file 'plugins' in environment production




info: Could not find file_metadata for 'plugins'

ensure you've set pluginsync to false in the puppet.conf: pluginsync = false

Certificates errors:

so far, I solved them by deleting the /etc/puppet/ssl directory on client and master

What if problems occur

  • use --debug and --verbose options to puppet commands

  • use --configprint to dump the value of a config property. E.g: puppet apply --configprint modulepath

  • use the notify keyword in your classes to print custom debug information

  • check the documentation

Links

[1] http://trevmex.com/post/850520511/bootstrapping-puppet-on-mac-os-x

Language guide: http://docs.puppetlabs.com/guides/language_guide.html

Modules and classes: http://docs.puppetlabs.com/learning/modules1.html

Core Types Cheat sheet: http://docs.puppetlabs.com/puppetcoretypes_cheatsheet.pdf