I recently had a need to find the OS versions of all 32-bit hosts within an environment. Knowing PuppetDB has a REST API, I set out to query the DB for this information.
There is decent information on how to use the API, but it can be tricky to understand the nuances necessary to construct a proper query as some of it is non-intuitive. I will attempt to describe exactly how my query works here. See "Resources" below for links to the PuppetDB API docs I used.
I used curl as a simple way to query the PuppetDB. The easiest way to construct the query is to do it in a text editor and the run the resulting file as a script. Here is my query command:
curl -s -X GET http://localhost:8080/v2/facts --data-urlencode \
'query=["and",
["=", "name", "operatingsystemrelease"],
["in", "certname",
["extract", "certname",
["select-facts",
["and",
["=", "name", "architecture"],
["=", "value", "i386"]
]
]
]
]
]'
The results of running this query are as follows:
$ ./get_p_ver
[ {
"certname" : "host1.local",
"name" : "operatingsystemrelease",
"value" : "5.3"
}, {
"certname" : "host2.local",
"name" : "operatingsystemrelease",
"value" : "5.3"
}, {
"certname" : "host3.local",
"name" : "operatingsystemrelease",
"value" : "5.3"
} ]
curl -s -X GET http://localhost:8080/v2/facts --data-urlencode
-s
- instruct curl to not return performance data in the output (keeps the output cleaner)-X GET
- instruct curl to send the encoded data as a GET to the URL endpointhttp://localhost:8080/v2/facts
- The URL endpoint for connecting to PuppetDB - Note the 'v2' which indicates we're using version 2 query language (v2 has been deprecated in favor of v3, but the results for this query should be the same regardless)--data-urlencode
- URL encode the data string that follows before passing it on the end of the URL'query=["and",
["=", "name", "operatingsystemrelease"],
["in", "certname",
["extract", "certname",
["select-facts",
["and",
["=", "name", "architecture"],
["=", "value", "i386"]
]
]
]
]
]'
'query=["and",
- access the 'query' method with the following formatted query. Because we're joining a number of components together in the query, we begin with the "and" operator. Similarly to how you query LDAP, the operator precedes the components.["=", "name", "operatingsystemrelease"],
- This is the value that we are attempting to return from the query["in", "certname",
- We're going to find certnames (through the following subquery) which we wish to return the above information from["extract", "certname",
- From the subquery below, we want the "certname" value(s)["select-facts",
- We're looking for "certnames" by querying sepecific fact information in the following subquery["and", ["=", "name", "architecture"], ["=", "value", "i386"] ] ]
- Query hosts where the fact "architecture" has the value "i386" (32-bit)[ {
"certname" : "host1.local",
"name" : "operatingsystemrelease",
"value" : "5.3"
}, {
"certname" : "host2.local",
...
} ]
Note that the output is JSON and can be manipulated as such.
It's also possible to simply query for a single fact directly via the facts API endpoint. The following returns the certname, fact name & fact value for each host in the DB as JSON:
curl -s -X GET http://localhost:8080/v2/facts/architecture
To limit the results to only hosts with the i386 architecture, supply the fact value as an additional component to the URL:
curl -s -X GET http://localhost:8080/v2/facts/architecture/i386
Again, the query syntax is a bit awkward, but if you break it down it's not too bad. There are PuppetDB querying libraries for both Ruby as well as Python (and I'm sure other languages) which could make programmatically querying various information relatively easy.