Puppet Bolt: taking action based on exit codes

April 13, 2021 

Puppet resources like Package, File or Service are idempotent. In other words, you define the state of the resource and Puppet enforces it. The resources can be used in Bolt plans as well, which frees you from having to do state checks yourself. However, if the thing you're managing is not a Puppet resource you have to check its state manually and use that information to drive login in your plan. Here's a crude but functional PoC for checking if a node's certificate is present on the Puppetmaster and acting accordingly:

plan puppeteers::myplan (
  TargetSpec $targets,
  String     $node,
) {

  # Run the command and store the results in a variable of type ResultSet
  $result = run_command("/opt/puppetlabs/bin/puppetserver ca list --certname ${node}", $targets, { '_catch_errors' => true })

  # Optionally print out the ResultSet
  # out::message($result)

  # Get the exit code from ResultSet
  $exit_code = $result.to_data[0]['value']['exit_code']
  if $exit_code == 0 {
    out::message("Node ${node} is present on the Puppetmaster")

The { '_catch_errors' => true } part is required, otherwise Bolt will choke if the exit status of the command is 1.

The $result variable contains a ResultSet object which contains the exit code. Note how ResultSet is first converted into data before being accessed. If you out::message the ResultSet object it looks ok, but its contents are inaccesible. That's why you convert it to data first.

As a ResultSet is an array, you need to pass an index to it. Each entry in the array represents one target. In this case there's only one target ($node), so we know the correct data is a index 0.

Samuli Seppänen
Samuli Seppänen
Author archive