Puppet is an open source software tool for managing today’s complex business software environments. Instead of setting up dozens or hundreds of servers manually, Puppet automates the configuration of servers and services to ensure your environment always takes the shape you expect.
Unfortunately, when you’re managing dozens or hundreds of servers, keeping all the details of each of those machines straight can be a challenge. What’s more, if you’re in a situation where you need to do one thing on servers configured a certain way (like those running a particular version of Linux) and another on servers configured a different way (like those running Windows), you need some help.
That’s where Facter comes in.
What Is Facter?
Facter is a software tool that collects data about a Puppet node and reports it back. Facter is somewhat similar to the env command in Linux, but it’s much more powerful. It also runs the same on every operating system, meaning that you don’t need to try to parse differences between Windows, Linux, and OS X.
The data that Facter collects about a system is comprehensive and customizable. As a bonus, Facter facts are built into Puppet and available as global variables, meaning you can use Facter facts to customize the way Puppet behaves. You can also run Facter on-demand via the CLI, sync it up to a dashboard, or script Facter to run and create a system information catalog for your entire business architecture.
How Do I Install Facter?
Facter relies on the Ruby programming language and is published as a gem to RubyGems. Installing Facter requires that you first install Ruby. Ruby runs on just about every operating system you might hope to support today. Once you’ve installed Ruby, installing Facter is as simple as running gem install facter. Make yourself a cup of coffee and, by the time you get back, Facter will be ready for you to run on your system.
What Are Custom Facts?
Facter has a built-in set of core facts it ships for nearly every operating system supported. These are helpful for basic systems configuration and reporting, but they’re not the only tool that Facter has in the toolbox.
Facter also supports defining your own custom facts about a system. Custom facts are scripts that you can write to expand the information Facter returns about a system when you run the Facter command.
Setting up custom facts requires a little bit more work than setting up Facter itself. You need to define the custom facts using a domain-specific language in a .rb file. Then, when you run Facter, you need to tell the script to also load your Facter script.
Facter will parse your file and then add any facts you’ve defined to the list of facts it reports about the system you’re evaluating.
Definition of a Fact
You start off defining a fact using the call Facter.add(:fact_name), then wrap the definition of the fact in a do … end block. Much like any other function in Ruby, you can define any arbitrary code inside this function and even call other functions. You’ll want to be careful exactly how you define your facts, though. There are some additional domain-specific functions that you want to understand and use to define your custom facts.
The first custom capability you’ll want to understand is the confine capability. This is an execution guard that determines whether the fact should execute on the current system. Confine statements work kind of like assertions in unit tests. But if they’re false, they don’t throw an error. They simply stop the fact from executing in the current context.
So, for instance, if you want to make sure a fact only runs on Linux systems, you’d write a confine block that looks like this:
confine :kernel do |value|
value == "Linux"
The :kernel symbol in that line has a special meaning. It tells Facter to go retrieve the value of the kernel fact in its current configuration, then pass the value to the block you define. If that value matches “Linux” exactly, the fact will continue to execute. If it doesn’t, execution is aborted.
Whenever you define a fact, you need to include a setcode call. Setcode blocks define what is actually returned to Facter as the “definition” of a fact. The result of your setcode block will be what you see in the list of facts when you run Facter with your custom fact enabled. Setcode will also only run when all of the confine blocks you define for a fact are true.
This guard enables you to verify that you’re in the right environment for defining a specific fact. For instance, if you install a particular utility on all of your Windows servers but not your Linux servers, attempting to retrieve information about that utility on Linux will fail. That will cause your entire Facter script execution to fail, and that system’s information won’t report back.
The setcode command provides two different ways to return values from a fact. The first is to use a do … end block. This is a normal Ruby function. It will allow you to run arbitrary code and return just like you would from a normal Ruby function. You do need to return a single value from your block, but it can be of an arbitrary shape. Integers, strings, and booleans are all fine. So are arrays and hashmaps; Facter knows how to interpret them all and display that information when you run the tool.
The other way to use setcode is with a string. If you use this definition, you don’t pass a block to setcode but rather just the string itself. If you just pass a string, then setcode interprets this as a CLI command to run, and your fact will be the output of that CLI command, whatever it is.
In addition to custom facts, Facter allows you to define external facts as well. External facts are very similar to custom facts, but they allow you to write the code to define the fact in other programming languages like Python or C.
The big value of external facts is that you don’t need to script out entire fact definitions for them. You can write a script or create an executable and drop it into a configured path on your system. Then Facter will look at those facts automatically while it is running. While you still need to write the script that outputs the information you want to import into Facter, you can skip the entire step where you define the fact manually. Facter will handle all of that for you.
External facts don’t have to be executable scripts either. You can load JSON or YAML files into Facter and use values stored in those documents as facts, too. Because facts from Facter are automatically available as global variables when you run Puppet, this can be a useful way to configure the installation or execution of services on your system.
Get Started Today
Facter is a powerful tool that integrates seamlessly with Puppet itself. It’s also totally free! If you’re using Puppet, the only barrier to getting started is installing a single Ruby Gem, and figuring out how you want to use it.
This post was written by Eric Boersma. Eric is a software developer and development manager who's done everything from IT security in pharmaceuticals to writing intelligence software for the U.S. government to building international development teams for non-profits. He loves to talk about the things he's learned along the way, and he enjoys listening to and learning from others as well.