Featured resource
2025 Tech Upskilling Playbook
Tech Upskilling Playbook

Build future-ready tech teams and hit key business milestones with seven proven plays from industry leaders.

Check it out
  • Lab
    • Libraries: If you want this lab, consider one of these libraries.
    • Cloud
Google Cloud Platform icon
Labs

Writing Custom Puppet Facts

There are multiple ways we can provide our own facts to our Puppet infrastructure, including plain-text eternal facts files, executable scripts, and via writing Ruby fact plugins. Custom facts are plugins that leverage Ruby to either provide static fact data or evaluate and command as well as provide the output for the value of the fact. These custom facts can be written so they are as simple as providing us a key-value pair or as complicated as some of the structured data sets we see when we query for our `os`-based facts. In this lab, we'll create a custom aggregate fact that provides us with data about our host's web server (should it exist), learn how to create structured facts, and use various coding techniques to ensure our facts work on all systems.

Google Cloud Platform icon
Lab platform
Lab Info
Level
Intermediate
Last updated
Apr 06, 2025
Duration
30m

Contact sales

By filling out this form and clicking submit, you acknowledge our privacy policy.
Table of Contents
  1. Challenge

    Set the Web Server Fact
    1. Move into the nginx module directory:

      cd /etc/puppetlabs/code/environments/production/modules/nginx/
      
    2. Create the plugin library location for Facter:

      sudo mkdir -p lib/facter
      
    3. Create and open a file called web.rb in the plugin location:

      sudo vim lib/facter/web.rb
      
    4. At its most basic, if we wanted to write a single, non-structured fact that output our web server information, we could write something like:

      Facter.add(:web) do
        setcode do
          'Nginx'
        end
      end
      

      Notice how this includes the Facter.add line to set our fact name, and the setcode statement, which provides us our output. Since we just want to supply the text Nginx, that is all we put in our statement block.

    5. However, since we need this to become a structured, aggregate fact, we're going to refactor this so we can add more facts to our code. Let's first define the overall web fact as an aggregate, which means the resolution of our web fact can be read in separate chunks:

      Facter.add(:web, :type => :aggregate) do
      
    6. Next, we want to replace our setcode statement with chunk, which lets us define the different parts of our structured fact:

      Facter.add(:web, :type => :aggregate) do
        chunk(:server) do
      
    7. We now need to update the structure of our output, so it resembles the JSON output we expected when we query for facts. To this, let's create a variable, web, then add our Nginx value as a structured key-value pair:

      Facter.add(:web, :type => :aggregate) do
        chunk(:server) do
          web = {:server => 'Nginx'}
          web
        end
      end
      

      Save and exit.

    8. Let's now test our fact:

      sudo puppet agent -t
      sudo facter -p web
      sudo facter -p web.server
      
  2. Challenge

    Set the Version Fact
    1. Back in the lib/facter/web.rb file, create a second chunk line, this one called version; include a line at the end calling the web variable:

        chunk(:version) do
          web
        end
      
    2. We're going to check our version by using a slightly edited version of the nginx -v command — which means we need nginx for this fact to work. Let's add an if statement checking for nginx:

        chunk(:version) do
          if Facter::Core::Execution.which('nginx') != nil
          end
          web
        end
      
    3. Finally, we want to execute the appropriate command and have the output sent to a structured line mapped to web. Because our command is on the long side, you may want to create a variable for its output:

        chunk(:version) do
          if Facter::Core::Execution.which('nginx') != nil
            version = Facter::Core::Execution.execute('nginx -v 2>&1 | grep -Po [0-9]+\.[0-9]+\.[0-9]+')
            web = {:version => version}
          end
          web
        end
      
    4. If desired, save and test your code thus far.

  3. Challenge

    Set the Fact for the Amount of Running Web Processes

    Mimic the same structures as the previous chunks to create the stanza that provides the amount of running processes:

      chunk(:processes) do
       processes = Facter::Core::Execution.execute('pgrep nginx | wc -l')
       web = {:processes => processes }
       web
      end
    

    The full file should look like:

    Facter.add(:web, :type => :aggregate) do
      chunk(:server) do
       web = {:server => 'Nginx'}
       web
      end
    
      chunk(:version) do
       if Facter::Core::Execution.which('nginx') != nil
         version = Facter::Core::Execution.execute('nginx -v 2>&1 | grep -Po [0-9]+\.[0-9]+\.[0-9]+')
         web = {:version => version}
       end
       web
      end
    
      chunk(:processes) do
       processes = Facter::Core::Execution.execute('pgrep nginx | wc -l')
       web = {:processes => processes }
       web
      end
    end
    
  4. Challenge

    Test the New Facts

    Test that each fact works, as well as the overall web fact. Note that the second server is provided so you can test on a node with Nginx, as well as one without it (remember, our Puppet master does not have Nginx installed):

    sudo puppet agent -t
    sudo facter -p web
    sudo facter -p web.server
    sudo facter -p web.version
    sudo facter -p web.processes
    
About the author

Pluralsight Skills gives leaders confidence they have the skills needed to execute technology strategy. Technology teams can benchmark expertise across roles, speed up release cycles and build reliable, secure products. By leveraging our expert content, skill assessments and one-of-a-kind analytics, keep up with the pace of change, put the right people on the right projects and boost productivity. It's the most effective path to developing tech skills at scale.

Real skill practice before real-world application

Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.

Learn by doing

Engage hands-on with the tools and technologies you’re learning. You pick the skill, we provide the credentials and environment.

Follow your guide

All labs have detailed instructions and objectives, guiding you through the learning process and ensuring you understand every step.

Turn time into mastery

On average, you retain 75% more of your learning if you take time to practice. Hands-on labs set you up for success to make those skills stick.

Get started with Pluralsight