Published on 6 March 2019 by

I work on the team that runs Puppet Enterprise (PE) at Puppet (Inc.). We use PE to enforce the configuration of our infrastructure, and maintain the standards we’ve decided on as a team. But sometimes we need to configure servers that don’t exist within the confines of our production continuous integration (CI) infrastructure, and that’s when we turn to bolt to ensure that those servers are configured in a repeatable fashion.

Here’s a scalable way to automate this workflow using Bolt, Apply, and Plans.

Avoiding excess manual work with an agentless approach

We use PE to manage the physical servers that run Openstack, but the VMs (virtual machines) themselves aren’t centrally managed, since this is a sandboxed environment. In this sandboxed environment, there was a problem I wanted to solve. Our users would report issues with their VMs in the Openstack environment, and I didn’t have access to ssh into the VMs that my internal customers were setting up. Even if I did have access to ssh into their vms, I didn’t have historical data about the experience of being on a VM in the environment.

I solved this problem by building two servers in the environment that communicated with each other, using telegraf to send performance data to influxdb. There was shared code between these two servers, and I didn’t want to configure them manually, particularly in an environment that doesn’t have the SLA of production.

To take this solution even further, I used Bolt to create Plans to help me manage these servers quickly.

How to use Bolt Apply

With the introduction of Bolt Apply, Bolt allows you to manage your agentless infrastructure using the same code and modules that you use to manage your infrastructure managed by PE. The first thing to note is that Bolt is opinionated about how you set up your environment, so that you can take advantage of code you write, as well as modules on the Puppet Forge.

These examples are based on users using a unix-based system. After installing Bolt, change to your ~/.puppetlabs/bolt directory, and create a Puppetfile.

forge ""

mod 'profiles', local: true
mod 'puppetlabs-concat', '5.2.0'
mod 'puppetlabs-stdlib', '5.1.0'
mod 'puppet-telegraf', '2.1.0'

A few things to note:

  • Add any modules that you will be using, in this case, I knew I wanted to use the telegraf module, and the telegraf module was dependent on the concat and stdlib modules.
  • Ensure you add the module you are about to create here with the flag local: true. Bolt will manage your modules from here on out, and if you do not list it as local_true, bolt will delete the code that you wrote, attempting to overwrite it with a module from the forge.

Next, use the command bolt puppetfile install to install all of the modules you listed in your puppetfile, then create a modules directory if one doesn’t exist, and create the directory for your module inside that directory. Bolt supports simpler tasks, which can run in any language you desire, and plans which are more extensible and use the Puppet language, in this case I wanted to use the bolt apply feature which requires puppet plans. I created the puppet plan, telegraf.pp in the directory ~/.puppetlabs/bolt/modules/profiles/plans/telegraf.pp.

plan profiles::telegraf(
  TargetSpec $nodes,
  String[1]  $influxdb_hostname,
  String[1]  $influxdb_password,
) {

  # Install the puppet-agent package if Puppet is not detected.
  # Copy over custom facts from the Bolt modulepath.
  # Run the `facter` command line tool to gather node information.

  # Compile the manifest block into a catalog
  apply($nodes) {

    class { 'telegraf':
      hostname => $facts['networking']['fqdn'],
      logfile  => '/var/log/telegraf/telegraf.log',
      outputs  => {
      'influxdb' => {
          'urls'     => [ "http://${influxdb_hostname}:8086" ],
          'database' => 'telegraf',
          'username' => 'telegraf',
          'password' => $influxdb_password,
      inputs   => {
        'cpu'       => {
          'percpu'   => true,
          'totalcpu' => true,
        'disk'      => {},
        'diskio'    => {},
        'mem'       => {},
        'net'       => {},
        'processes' => {},
        'syslog'    => {
          'server' => 'tcp://:6514',
        'system'    => {},

This is the plan which is used to install telegraf on the nodes. In this plan, I am passing in three variables:


The node variable is populated using the bolt flag --nodes.

Here is an example of how you would apply this bolt plan:

bolt plan run profiles::telegraf --nodes [email protected] --run-as root --tty [email protected]

$nodes.apply_prep is what gets the node ready to run puppet on them, though this is an agentless experience, we need to copy over the code which runs puppet apply onto the hosts running this code.

apply($nodes) { is the line that tells bolt you are about to pass Puppet language code to bolt to apply onto the server. You are running it on the nodes you passed into $nodes. This means you can generate this variable in other ways, if you want to develop a node list programmatically.

Note: If this were a more complex infrastructure, I could have used hiera to configure some of the variables.

Try this agentless approach for yourself or learn more

Bolt is a great way to automate the infrastructure in your organization that is detached from your primary Puppet environment. This allows us to get the benefit of code reuse between teams managing infrastructure, while also keeping our code base smaller, and more purpose built.

Mikker is a site reliability engineer at Puppet.

Here are some handy links

Share via:
Posted in:

Thank you for this very interesting article.

Are the installation steps under "How to use Bolt Apply" done on a central system, may be even a puppetserver?

"Bolt allows you to manage your agentless infrastructure using the same code and modules that you use to manage your infrastructure managed by PE."

I think I understand, that you don't need a puppetserver infrastructure to run Bolt, but on the other hand it would be interesting to know if it would be advisable to use the very same module base (i.e. litteraly the same files on disk) our puppetserver is using?

Are there any other requirements for the box you want to execute the commands on? In your article you say you don't have ssh access to the VMs, but the bolt command takes an user and IP address, so I guess it connects via ssh or is there any other infrastructure in place?


I know there is excessive documentation on Bolt, but it would be great have this information in the context of this article. :)


Hello Lars!

     When I say I don't have ssh access to the VMs I was speaking in general about the platform.  Since I can't login to one of the engineers VMs to determine if there are network latency issues, in this tutorial I created a separate VM that I use as a canary, which I do have SSH access to, and I can use bolt to configure it.

     When running bolt from your local workstation, you wouldn't use the same files on disk as you do for your PE infrastructure, but you would probably use the same modules in your Puppetfile.  If you are working on a team, The PE console is quickly becoming a way for you to run shared tasks(available now) and plans (coming soon), which would use the same file on disk.  If you're running FOSS you could share the modules that you use on the Puppet Master, but Bolt does not have a concept of environments so you would have to replicate environment.conf + puppet.conf in `bolt.yaml` in each environment directory.

The content of this field is kept private and will not be shown publicly.

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.