Executing shell commands in facts

Puppet gets information about a system from Facter , and the most common way for Facter to get that information is by executing shell commands.

You can then parse and manipulate the output from those commands using standard Ruby code. The Facter API gives you a few ways to execute shell commands:

  • To run a command and use the output verbatim, as your fact’s value, you can pass the command into setcode directly. For example: setcode 'uname --hardware-platform'

  • If your fact is more complicated than that, you can call Facter::Core::Execution.execute('uname --hardware-platform') from within the setcode do ... end block. Whatever the setcode statement returns is used as the fact’s value.

  • Your shell command is also a Ruby string, so you need to escape special characters if you want to pass them through.

Not everything that works in the terminal works in a fact. You can use the pipe (|) and similar operators as you normally would, but Bash-specific syntax like if statements do not work. The best way to handle this limitation is to write your conditional logic in Ruby.

Example

To get the output of uname --hardware-platform to single out a specific type of workstation, you create a custom fact.

  1. Start by giving the fact a name, in this case, hardware_platform.

  2. Create the fact in a file called hardware_platform.rb on the primary Puppet server:

    # hardware_platform.rb
    
    Facter.add('hardware_platform') do
      setcode do
        Facter::Core::Execution.execute('/bin/uname --hardware-platform')
      end
    end

  3. Use the instructions in the Plug-ins in modules docs to copy the new fact to a module and distribute it. During your next Puppet run, the value of the new fact is available to use in your manifests and templates.