Integrating Puppet Bolt with PuppetDB

April 24, 2020 

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

...

Samuli Seppänen
Samuli Seppänen
Author archive
menucross-circle