Configuring facts
Facts have properties that you can use to customize how they are evaluated.
On this page:
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
end
This 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
end
When 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.