Configuring facts
Facts have properties that you can use to customize how they are evaluated.
Confining facts
One of the more commonly used properties is the confine
statement, which restricts the fact to run only on systems that match another given
fact.
For example:
Facter.add('powerstates') do confine kernel: 'Linux' setcode do Facter::Core::Execution.execute('cat /sys/power/states') end endThis fact uses
sysfs
on Linux to get a list of the power states that are available on
the given system. Because sysfs
is available only on Linux systems, we use the confine
statement to ensure that this fact isn’t needlessly run on systems that
don’t support this type of enumeration.
You can confine structured facts like ['os']['family']
using dotted
notation. For example:
confine 'os.family' => :redhat
You can also use a Ruby block. For example:
confine 'os' do |os| os['family'] == 'RedHat' end
Fact precedence
A single fact can have multiple resolutions, each of which is a different way of
determining the value of the fact. It’s common to have different resolutions for different
operating systems, for example. To add a new resolution to a fact, you add the fact again
with a different setcode
statement.
When a fact has more than one resolution, the first resolution that returns a value other
than nil
sets the fact’s value. The way that Facter decides the issue of resolution precedence is the weight
property. After Facter rules out any resolutions that are
excluded because of confine
statements, the resolution with
the highest weight is evaluated first. If that resolution returns nil
, Facter moves on to the next resolution (by
descending weight) until it gets a value for the fact.
By default, the weight of a resolution is the number of confine
statements it has, so that more specific resolutions take priority over
less specific resolutions. Each external fact has a weight of 10,000. To override the default value, set a weight above 10_000
, because Ruby ignores underscores (_
) in numbers.
The following example code checks the role of a server. The value for role
is set to 10,001 during the PostgreSQL server check, prioritizing the check for that role before the check for the server and desktop role.
# Check to see if this server has been marked as a postgres server Facter.add('role') do has_weight 10_001 setcode do if File.exist? '/etc/postgres_server' 'postgres_server' end end end # Guess if this is a server by the presence of the pg_create binary Facter.add('role') do has_weight 50 setcode do if File.exist? '/usr/sbin/pg_create' 'postgres_server' end end end # If this server doesn't look like a server, it must be a desktop Facter.add('role') do setcode do 'desktop' end end
Execution timeouts
Facter 4 supports timeouts on resolutions. If the timeout is exceeded, Facter prints an error message.
Facter.add('foo', {timeout: 0.2}) do setcode do Facter::Core::Execution.execute("sleep 1") end End
You can also pass a timeout to Facter::Core::Execution#execute
:.
Facter.add('sleep') do setcode do begin Facter::Core::Execution.execute('sleep 10', options = {:timeout => 5}) 'did not timeout!' rescue Facter::Core::Execution::ExecutionFailure Facter.warn("Sleep fact timed out!") end end endWhen Facter runs as standalone, using
Facter.warn
ensures that the message is printed to
STDERR
. When Facter is called as part of a
catalog application, using Facter.warn
prints the message to Puppet’s log. If an exception is not caught, Facter automatically logs it as an error.