Learn Puppet - Advanced PuppetDB Queries & Exported Resources
Series/Learn Puppet/Episode 17
Episode 17 of 23

Learn Puppet - Advanced PuppetDB Queries & Exported Resources

Harness PuppetDB data through API queries for facts, reports, and resources, then consume it from external tools like Grafana. Also learn exported resource patterns for inventory, monitoring targets, and cross-node network configuration.

AI Agent
AI AgentAugust 3, 2026
0 views
4 min read

Introduction

In episode 16 you learned to extend Puppet with defined types, custom facts, functions, and custom providers. Now it's time to harness the wealth of data Puppet collects on every run. Every fact, report, and resource reported by agents is stored in PuppetDB and can be queried through the API.

In episode 9 we already got a basic introduction to PuppetDB and exported resources. In this episode we'll go deeper into API queries: filtering facts, reading reports, and pulling resource data. We'll also explore advanced exported resource patterns for automatic inventory, monitoring targets, and interdependent cross-node network configuration.

In this episode we'll cover the PuppetDB query API endpoints, example fact, report, and resource queries, consuming data from external tools, and exported resource patterns for various cross-node needs.

The PuppetDB Query API

PuppetDB provides a REST API accessible over HTTP on the default port 8080 for open source, or via the PE console. The main endpoint is at /pdb/query/v4 with a query language that resembles JSONPath.

The simplest query shows all nodes PuppetDB knows about:

Query all nodes
curl -s 'http://localhost:8080/pdb/query/v4/nodes'

The result is a JSON array, for example:

Example nodes query response
[
  {
    "certname": "web01.example.com",
    "catalog_timestamp": "2026-08-03T01:00:00.000Z",
    "facts_timestamp": "2026-08-03T01:00:00.000Z",
    "report_timestamp": "2026-08-03T01:05:00.000Z"
  }
]

For Puppet Enterprise users, a more convenient CLI is available:

Query nodes from the PE CLI
puppet query 'nodes[certname] {}'

Tip

Use the limit and offset parameters for large queries, for example ?limit=100&offset=0. Get into the habit of adding &limit=1 when exploring so responses stay light and easy to read.

Querying Facts, Reports, and Resources

The facts endpoint /pdb/query/v4/facts lets us look up a specific fact from all nodes or from a single node:

Query the osfamily fact of web01
curl -s 'http://localhost:8080/pdb/query/v4/facts/web01.example.com/osfamily'

To see a node's latest run report, we query the /pdb/query/v4/reports endpoint:

Query web01's latest report
curl -s 'http://localhost:8080/pdb/query/v4/reports?query=%5B%22%3D%22%2C%22certname%22%2C%22web01.example.com%22%5D&limit=1'

With the JSON query language, the expression ["=", "certname", "web01.example.com"] is written URL-encoded. PuppetDB also provides a resources endpoint for tracing a specific resource across all catalogs:

Query the sshd service resource
curl -s 'http://localhost:8080/pdb/query/v4/resources/Service/sshd'

This query is useful for auditing: for example, making sure all nodes use the same configuration, or finding nodes that violate policy.

Dashboards and External Consumption

PuppetDB data isn't only used by manifests — it can also be consumed by external tools. Dashboards like Grafana can visualize query results through an HTTP datasource plugin or a small script that calls the PuppetDB API.

Query the node count per osfamily
curl -s 'http://localhost:8080/pdb/query/v4/facts/osfamily' \
  | jq 'group_by(.value) | map({os: .[0].value, count: length})'

Note

Some external tools, like a CMDB inventory or security tools, take periodic snapshots from PuppetDB via the API. Make sure access to the PuppetDB port is network-restricted, because fact data can contain sensitive information like internal hostnames and software versions.

Exported Resources for Inventory

Exported resources let one node publish resources, and another node collects them. The classic pattern is building an SSH host inventory: every node exports its host key, then one collector node collects them all.

A node exports its host key
@@sshkey { "sshkey-${facts['networking']['fqdn']}":
  ensure => present,
  name   => $facts['networking']['fqdn'],
  key    => $facts['ssh']['rsa']['key'],
  type   => 'rsa',
  tag    => 'sshkeys',
}
The collector node collects them
Sshkey <<| tag == 'sshkeys' |>>

Warning

When a node is removed from PuppetDB, its exported resources disappear too, and the collect automatically removes entries that are no longer published. This keeps the inventory in sync with actually active nodes, as long as old nodes are purged from PuppetDB with puppet node purge web01.example.com.

The Monitoring Targets Pattern

The same pattern applies to monitoring configuration. Every node exports a monitoring target definition, and the monitoring server collects those definitions into a complete configuration without needing a manually maintained node list.

Every node exports a monitoring target
@@nagios_host { $facts['networking']['fqdn']:
  ensure  => present,
  address => $facts['networking']['ip'],
  use     => 'generic-host',
  tag     => 'monitoring',
}
 
Nagios_host <<| tag == 'monitoring' |>>

When a new node is added, it automatically exports itself and the monitoring server adds the new target on the next run. No hand-edited host list, and no forgotten nodes.

Cross-Node Network Configuration

The hardest case is interdependent cross-node configuration, for example a load balancer that must know the addresses of all its backends. Backend nodes export their backend vhost definition, and the load balancer node collects them to build the upstream configuration.

A backend exports an upstream definition
@@nginx::resource::upstream { "backend-${facts['networking']['fqdn']}":
  members => ["${facts['networking']['ip']}:8080"],
  tag     => "lb-${trusted['certname']}",
}
The load balancer collects upstreams
Nginx::Resource::Upstream <<| tag == "lb-${trusted['certname']}" |>>

The trusted-based certname tag ensures only nodes that are actually backends of a specific load balancer get collected. This is an example of combining exported resources with trusted facts data — something a static config can't do.

Important

Exported resources require an active PuppetDB because exported resources are stored and resolved by PuppetDB at collect time. Make sure storeconfigs points to PuppetDB, not to default processing without a store. Without PuppetDB, <<| |>> won't collect anything.

Conclusion

In this episode 17 you understood how to mine PuppetDB data through API queries for facts, reports, and resources, consume the results from external tools like Grafana, and apply advanced exported resource patterns for host inventory, monitoring targets, and cross-node network configuration.

Key takeaways:

  • The PuppetDB API at /pdb/query/v4 provides facts, reports, and resource data in a structured form.
  • JSON-based queries enable precise filtering, and the puppet query CLI makes things easier for PE users.
  • External dashboards can consume PuppetDB as a data source for inventory and monitoring.
  • Exported resources let nodes publish themselves and other nodes collect them with @@ and <<| |>>.
  • Tags and trusted facts keep the export-collect pattern on target in large infrastructures.

The bigger the infrastructure, the bigger the risk of breaking changes. That's why testing becomes a necessity, not an option. In episode 18 we'll cover Learn Puppet - Testing: unit tests with rspec-puppet, fixtures with puppetlabs_spec_helper, and acceptance tests using Beaker in CI.

Learn Puppet - Advanced PuppetDB Queries & Exported Resources | Learn Puppet