graham gilbert

Mac administration and assorted nerdity

Facter 101

| Comments

Facter is what gives Puppet it’s brains. It collects information about the computer it is run on and then passes it to the Puppet Master for use in manifests and can optionally be stored. I know, it doesn’t sound like the most earth shattering revelation of all time, but stop for a moment. Every time your current scripts need to taget a specific OS version or a machine with a certain bit of hardware, you need to code it directly into the script. If the method of extracting that information changes, you need to modify every single script that uses that method. With Facter, you’re editing one file, which is always up to date on the client. Anyway, that’s enough waffle from me. Let’s get started.

Requirements

  • VirtualBox
  • Vagrant
  • Either a Mac running 10.8 that you don’t mind wiping, or a Virtual Machine running in VMWare Fusion or similar.
  • Git (Install the Command Line Tools from within Xcode’s preferences if you don’t have it).

Setup

We need a Puppet Master – fortunately there’s one pre-built that has everything we need. Make sure you’ve installed everything in the requirements, and then open up your trusty Terminal:

1
2
3
4
$ mkdir ~/src
$ git clone https://github.com/grahamgilbert/vagrant-puppetmaster.git facter-101
$ cd facter-101
$ vagrant up

This will pull down the needed bits to get your own Puppet Master running and then vagrant up will start things going. If you get errors about Postgres, just issue a vagrant reload

Now for your test Mac: I’ve made a script to automate the process. If you don’t have a DNS entry for your Puppet Master, and you’re using the Vagrant setup described above, run this in your terminal:

1
$ curl -o /tmp/install_puppet.py https://raw.github.com/grahamgilbert/macscripts/master/Puppet-Install/install_puppet.py; sudo python /tmp/install_puppet.py --appendhosts

If you are using a different setup, please refer to the script’s readme for more information

Learn some Facts

On your client machine, run this in a Terminal

1
$ sudo facter

Your test Mac will churn away for a minute and then spit out a ton of information – you’ll see everything from the uptime of the machine to the amount of RAM. Still not overly useful sitting on that one machine. We need this information somewhere central to make use of it.

We need to make one small change to ~/src/facter-101/puppet/manifests/site.pp to get the puppet run working:

1
2
# comment out the next line by putting a hash in front of it
# import "classes/*"

This is to stop Puppet complaining that there’s nothing to import – which there isn’t yet.

Assuming your Puppet Master is running, this is on your test Mac:

1
sudo puppet agent -t

You’ll see a load of files being synced to your test Mac – these are custom Facts, plugins and assorted other goodies being pulled from the server. We’ll get to using custom Facts in a moment. If you load up http://192.168.33.10:3000 in your browser of choice, you’ll see your client having checked into Puppet. Click on it’s hostname and you’ll be presented with a list of all of the available Facts for that machine.

That’s all very nice, but what can we use it for?

The Plan

We’re going to install some extra facts from the Puppet Forge onto our Master, and then write some code to target a specific set of machines. In our fictional world, every Mac with 4GB or more of RAM will be designated a “design” Mac. We’ll install Firefox on those (that’s a design app, right?).

First we’ll install the extra Facts onto our Master from the Forge.

1
2
3
4
5
6
7
8
$ cd ~/src/facter-101
$ vagrant ssh
# You're on the Puppet Master now
$ sudo puppet module install grahamgilbert/mac_facts
# Get out of the Puppet Master
$ exit
# Restart the Puppet Master to pick up the new module
$ vagrant reload

Now we’ll write a class that will:

  • Test that the client machine is a Mac
  • Test that the client machine also has more than 4GB RAM
  • If both conditions are satisfied, will install Firefox.

Create your ~/src/facter-101/puppet/manifests/classes/design.ppand make it look like the following.

~/src/facter-101/puppet/manifests/classes/design.pp
1
2
3
4
5
6
7
8
9
class design {
  if $::operatingsystem == "Darwin" and $::mac_memory_in_gb >= 4{
      package { 'Firefox':
          ensure => installed,
          provider => appdmg,
          source => "http://ftp.mozilla.org/pub/mozilla.org/firefox/releases/19.0.2/mac/en-US/Firefox%2019.0.2.dmg",
      }
  }
}

Puppet has a default node – all machines checking into the Master get anything that’s declared in this node by default. Open up ~/src/facter-101/puppet/manifests/site.pp and make it look like:

~/src/facter-101/puppet/manifests/site.pp
1
2
3
4
5
import "classes/*"

node default {
  include design
}

We’ve added some classes, so the Puppet Master process needs to be restarted – rebooting the whole VM is probably quicker.

1
$ vagrant reload

On your Test Mac, perform a Puppet run.

1
$ sudo puppet agent -t

Depending on how much memory is in your test Mac, this might or might not do anything. Play with the $::mac_memory_in_gb value, starting high and then bringing it down to the amount of RAM in your test Mac – or if you are running your test Mac in a VM, you could also adjust the amount of memory assigned to it.

So that’s Facter – you’re not limited to using this with the default node, this technique can be used anywhere you write Puppet code. Try changing your design.pp file to look like the following – we’re using Facter Facts directly within our manifest to write data to the test Mac.

~/src/facter-101/puppet/manifests/classes/design.pp
1
2
3
4
5
6
7
8
9
10
11
12
13
class design {
  if $::operatingsystem == "Darwin" and $::mac_memory_in_gb >= 4{
      package { 'Firefox':
          ensure => installed,
          provider => appdmg,
          source => "http://ftp.mozilla.org/pub/mozilla.org/firefox/releases/19.0.2/mac/en-US/Firefox%2019.0.2.dmg",
      }
  }
  
  file { '/tmp/mac_ver':
      content => "This Mac is running ${::sp_os_version}",
  }
}

Which gives us

1
2
$ less /tmp/mac_ver
This Mac is running OS X 10.8.3 (12D78)

This is a very simple example of how you can use Facter to configure your machines. Facter can be used anywhere you’d set a variable manually – the Puppet documentation on Conditional Statements is an excellent next step with dynamically assigning configuration to your machines.

Comments