Puppet: System Administration Automated

Support

Adding Custom Facts to Facter

Sometimes you need to be able to write conditional expressions based on site-specific data that just isn't available via facter. The solution may be to add a fact to facter.

The Concept

You can add new facts by writing a snippet of ruby code. Puppet will look for custom facts on puppet://$server/facts by default. You will need to run puppetd with --factsync (or add factsync = true to puppetd.conf) to enable the syncing of these files to the local file system and loading them within puppetd.

Facts are synced to a local directory ($vardir/facts, by default) before facter is run, so they will be available the first time. If $factsource is unset, the --factsync option is equivalent to:

 file { $factdir: source => "puppet://puppet/facts", recurse => true }

After the facts are downloaded, they are loaded (or reloaded) in memory.

Note: The approach described above is now deprecated and replaced by the plugin approach described in the Plugins InModules page.

Options

The following command line or config file options are available (default options shown):

  • factpath ($vardir/facts): Where Puppet should look for facts. Multiple directories should be colon-separated, like normal PATH variables. By default, this is set to the same value as factdest, but you can have multiple fact locations (e.g., you could have one or more on NFS).
  • factdest ($vardir/facts): Where Puppet should store facts that it pulls down from the central server.
  • factsource (puppet://$server/facts): From where to retrieve facts. The standard Puppet file type is used for retrieval, so anything that is a valid file source can be used here.
  • factsync (false): Whether facts should be synced with the central server.
  • factsignore (.svn CVS): What files to ignore when pulling down facts.

An Example

I needed to get the output of uname -i to single out a specific type of Sun workstation. No problem:

1. Choose a fact source and configure your file server appropriately:

# in /etc/puppet/fileserver.conf
[facts]
   path /var/lib/puppet/facts

It's highly recommended that these facts be managed via your SCM, like your manifests and other data files.

2. Invent a name, hardware_platform, and create $factsource/hardware_platform.rb on the puppetmaster server:

# hardware_platform.rb

Facter.add("hardware_platform") do
        setcode do
                %x{/bin/uname -i}.chomp
        end
end

Note that the chomp was required :)

3. I changed my SMF manifest (this is a Solaris thing) to add --factsync to puppetd arguments.

4. I can now use the hardware_platform variable in Puppet manifests.

Testing

Of course, we need to test that our code works before adding it to puppet.

Create a directory called facter/ somewhere, and set the environment variable $RUBYLIB to its parent. You can then run facter, and it will import your code:

host:~$ mkdir -p ~/lib/ruby/facter ; export RUBYLIB=~/lib/ruby
host:/tmp$ cp /path/to/hardware_platform.rb $RUBYLIB/facter
host:/tmp$ facter hardware_platform
SUNW,Sun-Blade-1500

You should now see the following when running puppetd:

# puppetd -vt --factsync
info: Retrieving facts
info: Loading fact hardware_platform
...

Alternatively, you can set $FACTERLIB to a directory with your new facts in, and they will be recognised.