External facts

External facts provide a way to use arbitrary executables or scripts as facts, or set facts statically with structured data. With this information, you can write a custom fact in Perl, C, or a one-line text file.

Executable facts on Unix

Executable facts on Unix work by dropping an executable file into the standard external fact path. A shebang (#!) is always required for executable facts on Unix. If the shebang is missing, the execution of the fact fails.

An example external fact written in Python:
#!/usr/bin/env python
data = {"key1" : "value1", "key2" : "value2" }

for k in data:
    print "%s=%s" % (k,data[k])
You must ensure that the script has its execute bit set:
chmod +x /etc/facter/facts.d/my_fact_script.py

For Facter to parse the output, the script should return key-value pairs, JSON, or YAML.

Custom executable external facts can return data in YAML or JSON format, and Facter parses it into a structured fact. If the returned value is not YAML, Facter falls back to parsing it as a key-value pair.

By using the key-value pairs on STDOUT format, a single script can return multiple facts:

key1=value1
key2=value2
key3=value3

Executable facts on Windows

Executable facts on Windows work by dropping an executable file into the external fact path. The external facts interface expects Windows scripts to end with a known extension. Line endings can be either LF or CRLF. The following extensions are supported:
  • .com and .exe: binary executables

  • .bat and .cmd: batch scripts

  • .ps1: PowerShell scripts

The script should return key-value pairs, JSON, or YAML.

Custom executable external facts can return data in YAML or JSON format, and Facter parses it into a structured fact. If the returned value is not YAML, Facter falls back to parsing it as a key-value pair.

By using the key-value pairs on STDOUT format, a single script can return multiple facts:

key1=value1
key2=value2
key3=value3
Using this format, a single script can return multiple facts in one return.

For batch scripts, the file encoding for the .bat or .cmd files must be ANSI or UTF8 without BOM.

Here is a sample batch script which outputs facts using the required format:
@echo off
echo key1=val1
echo key2=val2
echo key3=val3
REM Invalid - echo 'key4=val4'
REM Invalid - echo "key5=val5"

For PowerShell scripts, the encoding used with .ps1 files is flexible. PowerShell determines the encoding of the file at run time.

Here is a sample PowerShell script which outputs facts using the required format:
Write-Host "key1=val1"
Write-Host 'key2=val2'
Write-Host key3=val3
Save and execute this PowerShell script on the command line.

Executable fact locations

Distribute external executable facts with pluginsync. To add external executable facts to your Puppet modules, place them in <MODULEPATH>/<MODULE>/facts.d/.

If you’re not using pluginsync, then external facts must go in a standard directory. The location of this directory varies depending on your operating system, whether your deployment uses Puppet Enterprise or open source releases, and whether you are running as root or Administrator. When calling Facter from the command line, you can specify the external facts directory with the --external-dir option.

Note: These directories don’t necessarily exist by default; you might need to create them. If you create the directory, make sure to restrict access so that only administrators can write to the directory.
In a module (recommended):
<MODULEPATH>/<MODULE>/facts.d/
On Unix, Linux, or Mac OS X, there are three directories:
/opt/puppetlabs/facter/facts.d/
/etc/puppetlabs/facter/facts.d/
/etc/facter/facts.d/
On Windows:
C:\ProgramData\PuppetLabs\facter\facts.d\
When running as a non-root or non-Administrator user:
<HOME DIRECTORY>/.facter/facts.d/
Note: You can use custom facts as a non-root user only if you have first configured non-root user access and previously run Puppet agent as that same user.

Structured data facts

Facter can parse structured data files stored in the external facts directory and set facts based on their contents.

Structured data files must use one of the supported data types and must have the correct file extension. Facter supports the following extensions and data types:
  • .yaml: YAML data, in the following format:
    ---
    key1: val1
    key2: val2
    key3: val3
  • .json: JSON data, in the following format:
    { "key1": "val1", "key2": "val2", "key3": "val3" }
  • .txt: Key-value pairs, of the String data type, in the following format:
    key1=value1
    key2=value2
    key3=value3 
As with executable facts, structured data files can set multiple facts at one time.
{
  "datacenter":
  {
    "location": "bfs",
    "workload": "Web Development Pipeline",
    "contact": "Blackbird"
  },
  "provision":
  {
    "birth": "2017-01-01 14:23:34",
    "user": "alex"
  }
}

You can also compose multiple external facts in a structured fact using the dot notation. For example:

my_org.my_group.my_fact1 = fact1_value
my_org.my_group.my_fact2 = fact2_value

Structured data facts on Windows

All of the above types are supported on Windows with the following notes:

  • The line endings can be either LF or CRLF.

  • The file encoding must be either ANSI or UTF8 without BOM.

Troubleshooting

If your external fact is not appearing in Facter’s output, running Facter in debug mode can reveal why and tell you which file is causing the problem:
# puppet facts --debug
One possible cause is a fact that returns invalid characters. For example if you used a hyphen instead of an equals sign in your script test.sh:
#!/bin/bash

echo "key1-value1"
Running puppet facts --debug yields the following message:
...
Debug: Facter: resolving facts from executable file "/tmp/test.sh".
Debug: Facter: executing command: /tmp/test.sh
Debug: Facter: key1-value1
Debug: Facter: ignoring line in output: key1-value1
Debug: Facter: process exited with status code 0.
Debug: Facter: completed resolving facts from executable file "/tmp/test.sh".
...

If you find that an external fact does not match what you have configured in your facts.d directory, make sure you have not defined the same fact using the external facts capabilities found in the stdlib module.

Drawbacks

While external facts provide a mostly-equal way to create variables for Puppet, they have a few drawbacks:
  • An external fact cannot internally reference another fact. However, due to parse order, you can reference an external fact from a Ruby fact.

  • External executable facts are forked instead of executed within the same process.