In the Puppet Bolt with a Puppet control repository blog post we showed how to integrate Puppet Bolt with an existing control repository. We used a static inventory file, which is ok for testing or when you have a few target nodes. However, if you have a Puppetserver running and are not using Bolt to manage the configurations of your nodes, then the chances are that you have a fairly large node population and maintaining a static inventory would be both tedious and error-prone. One option among many is to use the PuppetDB plugin to generate a dynamic inventory and that is what we describe here.
The first step is to configure the Bolt controller and PuppetDB so that they can work communicate. This is covered pretty thoroughly in the official documentation, but we'll go through it here as well.
First, the Bolt controller needs TLS certificates and keys to connect to PuppetDB. If the Bolt controller is joined to the same Puppet environment as the PuppetDB server then its own Puppet keys can be reused. If not, keys have to generated for it on the Puppetserver with
$ puppetserver ca generate --certname <certname>
Once the keys are available they can be copied from the Puppetserver or the node itself to a directory on the Bolt controller. Here we've used the following locations:
- ~/.puppetlabs/etc/bolt/myenv/ssl/certs/ca.pem
- ~/.puppetlabs/etc/bolt/myenv/ssl/certs/cert.pem
- ~/.puppetlabs/etc/bolt/myenv/ssl/private_keys/key.pem
The keys are in the "myenv" subdirectory so that you can easily use Bolt for multiple control repositories and PuppetDB instances.
Connectivity should now be tested with "telnet puppet.example.org 8081" (or similar) to make sure basic connectivity to PuppetDB is ok. If it is not, make sure that there are no firewalls blocking access to PuppetDB and that PuppetDB is actually listening on the interfaces you think it is. Finally, test the keys with curl to make sure PuppetDB accepts them.
Once PuppetDB queries work add a puppetdb configuration section to bolt.yaml:
puppetdb:
server_urls:
- 'https://puppet.example.org:8081'
cacert: '~/.puppetlabs/etc/bolt/myenv/ssl/certs/ca.pem'
cert: '~/.puppetlabs/etc/bolt/myenv/ssl/certs/cert.pem'
key: '~/.puppetlabs/etc/bolt/myenv/ssl/private_keys/key.pem'
The final step is to create the inventory file:
groups:
- name: servers
targets:
- _plugin: puppetdb
query: "inventory[certname] { facts.fqdn = 'server.example.org' }"
The above group has only one target node, but that is just for display purposes. Now you can test the inventory:
$ bolt group show
all
servers
2 groups
To list the nodes in a group:
$ bolt inventory show --target servers
server.example.org
1 targets
This is a very simplistic and rather useless inventory, but you can make it a lot fancier by simply adding more groups with PQL queries. For example, if you have production and staging web servers which can be distinguished by their hostnames you can do something like this:
- name: www-staging
targets:
- _plugin: puppetdb
query: "inventory[certname] { facts.fqdn ~ 'www\\d-staging.example.org' }"
- name: www-production
targets:
- _plugin: puppetdb
query: "inventory[certname] { facts.fqdn ~ 'www\\d-production.example.org' }"
You can also require multiple facts to resolve to certain values. For example to target all Linux nodes that are in the staging deployment you could
query: "inventory[certname] { facts.kernel = 'linux' and facts.deployment = 'staging' }"
This of course depends on the presence of the "deployment" fact which is most likely to be added during provisioning (e.g. with terraform-aws_instance_wrapper).
When doing more advanced PQL stuff these are excellent resources:
- https://puppet.com/docs/puppetdb/latest/api/query/tutorial-pql.html
- https://puppet.com/docs/puppetdb/latest/api/query/v4/pql.html
- https://puppet.com/docs/puppetdb/latest/api/query/v4/entities.html
- https://www.postgresql.org/docs/9.6/functions-matching.html#POSIX-SYNTAX-DETAILS
...