Simple Puppet Module – Iterate Through an Array


OK, this is a very simple and quick one.

I was looking for a simple example of how to iterate through an array in a Puppet module. I basically needed an example of a “for loop” inside a Puppet module that I could, as someone who is not exactly fluent in Ruby, could modify to fit my needs.

I settled on the format that you see below.

The “define” code block is basically the work that we want the Puppet module to do. In this case, it’s create a file in /tmp. Think of this line as pretty much just a placeholder for more complex code.

The “class” code block is where we setup our array of items for the module to “loop” through.


# Test Module

define myarray_config {
notify { "Item ${name}": }
file {"/tmp/$name":
ensure => present,
mode => 0777,

class test-module {
$array = [ 'item1', 'item2', 'item3' ]
myarray_config { $array: }


Now add the following code to your site.pp to make this module part of your site manifest.

include test-module

Puppet: Convert a Variable to Lower Case



This is going to be a very simple example of how to convert a variable to all lowercase inside a Puppet module.

If you look, which I am sure that you have already…there seems to be a lot of documentation around how to use the Ruby “downcase” function, but not much of it is easy to read if you are not very familiar with Ruby.

In this example, I create a very simple Puppet module and show how to use the downcase function.

class test-module (
$myname = "TEST",

$myname_downcase = downcase($myname)

file { "/var/tmp/$myname_downcase":
ensure => present,
content => "This is a Test File for $myname_downcase",

In this example I have a Variable called $myname. I am setting $myname to TEST inside the init.pp.

Note however you would probably never do this. More than likely you would do one of the following:

  1. Set $myname so that it is an external environmental variable
  2. Set $myname to NULL and override in Foreman.

The meat in this potato is this line here, where we take the $myname variable and munge it into a new variable called $myname_downcase.

$myname_downcase = downcase($myname)


Running CloudForms and Puppet Together


In this instance we are trying to run Red Hat Cloudforms, also known as Manage IQ, and Puppet together on the same RHEL 6 host.

Our goal here is to push out some configuration to the Cloudforms appliances via Puppet. However we ran into issues as the version of Ruby/Ruby Gems used by Cloudforms is different than the version used by Puppet and they are stepping on each other a bit.

Here is the error we see when attempting to run Puppet


# puppet agent -t

/opt/rh/ruby200/root/usr/share/gems/gems/json-1.8.2/lib/json/ext/ [BUG] Segmentation fault

ruby 1.8.7 (2013-06-27 patchlevel 374) [x86_64-linux]

Aborted (core dumped)


As a workaround we add this code to /usr/bin/puppet.


ENV.delete x

end if $0.match(/\A#{‘/usr/bin’}/)



We add this right below


By no means is this the best way to work around this issue, however it does work and will get you up and running.


How to Add Standalone Puppet Agents to Foreman

This example will walk us through the process of adding a standalone Puppet host to Foreman for the purpose of managing the host through Puppet. In this instance we are going to create a standalone-hostgroup for the server.

Note that the Foreman server must be able listening on ports 8140, and 6163 (according to Puppet documentation). My RHEL7 Foreman host was listening on these ports, but the firewall was blocking any inbound connections. I corrected this with the commands shown below.

First I needed to determine my default firewalld zone.

# firewall-cmd –get-default-zone

Then I ran the commands below to punch a hole in the firewall to allow the required traffic. I also reloaded firewald.

# firewall-cmd –permanent –zone=public –add-port=8140/tcp
# firewall-cmd –permanent –zone=public –add-port=61613/tcp

On the puppet client, install the puppet agent

# yum -y install puppet

Now we add an entry for the puppet server in /etc/puppet/puppet.conf in section [agent], where <PUPPETSERVER-FQDN> is the FQDN of your Foreman Server


Now save the file.

Then on the Puppet client run the following command.

# puppet agent -t waitforcert 60

Log into Foreman WebUI.
Navigate to => “Infrastructure” => “Smart Proxies” => “Certificates”

In the list located the new puppet client and click on sign to accept the key for the new host. The host that I am adding is osd01.lab.localdomain.

NOTE: Once you have accepted the key you need to run the puppet client again (puppet agent -t)  on the client. Otherwise the client will not appear in on the “All hosts” page


Now Lets create a new Host Group to use for this server. Come on, its will be a blast.

Navigate to => “Configure” => “Host groups“. Select the green “New Host Group” button and then add your host group. Here I have added a host group called “Standalone Hosts”. See below.


Now we need to add our new client to this new host group. We do so by navigating to => “Hosts” => “All hosts“. Then select “Edit” to the left of the host.


Click “Submit” an the bottom of the page and you are good to go.

How to Remove Deactivated or Invalid Nodes from Puppet Enterprise via the CLI


Apparently just deleting a Puppet node from the Puppet Enterprise Console does not actually delete the node from the Puppet database, and free up a licenses… or at least in my case it did not. I ran into this issue tonight after removing a few of my test boxes in preparation of building a new node that I wanted to ensure was properly managed via Puppet.

As many of you know when running the free version of Puppet Enterprise you are limited to 10 managed nodes. In my Lab I am actually running only 7 nodes, however over the past few months, I have build several test VMs as part of testing my Centos 6 kickstart and Puppet bootstrap scripts. However even after deleting these nodes manually from the WebUI I noticed that I was not freeing up any licenses.

Below is the process that I had to run to manually remove nodes from my PuppetDB. First lets list all managed VMs and look for nodes that we know do not exist any more.

[root@puppet puppet]# puppet cert list -all

+ “batman.localdomain” (SHA256) 4C:76:04:38:CE:D3:4A:E0:C9:2A:C8:E6:BB:4A:92:0C:6B:39:D9:4B:7C:E4:D1:9D:0F:E2:06:FD:97:CC:72:AF
+ “robin.localdomain” (SHA256) A9:08:E8:09:B6:68:65:81:92:FC:82:93:DB:83:82:D9:A5:A2:EB:6D:DD:6E:C5:F0:45:55:A5:39:47:DB:A1:27

In the example above, I found two test VMs… Batman and Robin, which I know are no longer valid, so lets remove them and free up a couple of licenses.

[root@puppet puppet]# puppet node deactivate robin.localdomain
Submitted ‘deactivate node’ for robin.localdomain with UUID 54267132-1c23-4cf7-96f4-d6f3ff13a684

[root@puppet puppet]# puppet node deactivate batman.localdomain
Submitted ‘deactivate node’ for batman.localdomain with UUID 160d9f7c-734c-4830-8faa-23f331218b90

Once you have set the node to deactivate, lets clean out the certs.. rinse and repeat for each node to delete.

[root@puppet puppet]# puppet node clean batman.localdomain
Notice: Revoked certificate with serial 17
Notice: Removing file Puppet::SSL::Certificate batman.localdomain at ‘/etc/puppetlabs/puppet/ssl/ca/signed/batman.localdomain.pem’

Now when we return to the WebUI we should have two free licenses and can add new managed nodes without issue. Note that according to puppet themselves “that in some cases, the PE license count in the console will not decrease for up to 24 hours, but you can restart the pe-memcached service to update the license count sooner”

Getting Started With Puppet: How to Write Your First Module

1361349665_puppet-logoThis post will walk you through the process of writing your first, albeit, a very simple Puppet module. Nothing fancy here, that can come later once we get the basics down.

Before we get started let’s take a minute to go through a couple of prerequisites.

First, we will assume that you are doing your work some sort of Linux workstation or server. Second, we will assume that you have already installed and configured a Puppet Master and a Puppet Client. In this particular case, I am working on my Fedora 20 desktop. It serves as both my master and client. Last, we are assuming that have a basic site.pp and are able to run the Puppet agent without issue or error.

Now lets get down to the meat and potato. Note we are working with opensource Puppet, not Puppet Enterprise.

First lets change directory to our Puppet module directory.

#cd /etc/puppet/modules/

Now lets create a basic manifest from a template, to do this we need to generate a module. Our very simple module is going to be called harden-cron. Run the command below to generate our bare-bones module

#puppet module generate harden-cron

Now that our module has been generated lets change directories once again. This time we need to change to the manifests directory in our newly created module.

#cd harden-cron/manifests/ && vim init.pp

Now we need to edit our manifest. This is, more or less, our playbook. It defines what “work” puppet needs to do.

Our end goal is to create a manifest that will ensure that /etc/cron.allow exists, is owned by root, and has specific file permissions. We also need to make sure that /etc/cron.deny does not exist. In order to accomplish this we use the simple code shown below. Note that we have defined our class has “harden-cron”. This is the same name that we used when creating our module above.

class harden-cron {

file {"/etc/cron.deny":
ensure => absent,

file {"/etc/cron.allow":
ensure => present,
owner => "root",
group => "root",
mode => "600"

Now we need to test our syntax and make sure that we have not made any errors. Use the command below to accomplish this. No output from the script below means that you do not have any syntax errors.

#puppet parser validate init.pp

Excellent, so now we have a new module, but its not going to do anything for us until we declare it in our site.pp. So lets change directories and do a bit of editing

# cd /etc/puppet/manifests/ && vi site.pp

Continue reading

Puppet: How Not To Generate a Certificate with Your Correct Hostname

954f7381089ac290b4690c5ffd9dd7d3_400x400So, I’ve been hacking away in my homelab as of late, building out a CentOS kickstart server, a Git server, and a puppet server. Right now, I am working on how to roll my puppet agent installs into my kickstart process. I just started on this, so I have yet to nail it down.

So currently, when kicking a VM, I am not yet setting my new CentOS node’s hostname before the install process. Sadly I am setting it manually as I am still building my kickstarts, and they are no where near where I want them to be.

Well, this whole hostname mumbo-jumbo just creates all sorts of issues for puppet… the hostname is one thing initially, then puppet installs as part of the post, and the hostname is set manually to finalize the install. Well this is no good, as you are are not going to be able to add your new node properly until you step in and provide a bit of manual persuasion.

Now while its not hard to find documentation on how to troubleshoot puppet node and master certificate issues — see here and here for example — none of it was written to help troubleshoot the mess that I had created.

Here was my specfic error.

Error: Could not request certificate: The certificate retrieved from the master does not match the agent’s private key.
Certificate fingerprint: BE:B6:B6:5E:AC:B8: ..truncated

And here verbatim, is the output that you get in response to the error above.

To fix this, remove the certificate from both the master and the agent and then start a puppet run, which will automatically regenerate a certficate.

On the master:
  puppet cert clean localhost.localdomain

On the agent:
  rm -f /etc/puppetlabs/puppet/ssl/certs/localhost.localdomain.pem
  puppet agent -t

So we try that and it doesn’t work. The next cert I generate identifies my node as localhost again.

So heres how to fix the issue.

# rm -rf /etc/puppetlabs/puppet/ssl

Now before we generate another certificate for our node, lets test what hostname a new cert would have using the command below.

#puppet agent –verbose –configprint certname

If the command above does not spit out the correct hostname, then you my friend, are in luck. Edit the file below

# vi /etc/puppetlabs/puppet/puppet.conf

Now change the entry below by removing the localhost.localdomain, and replacing that mess with the correct hostname

certname = correcthostname.localdomain

Now kickoff a puppet run on the node

#puppet agent -t

Log into the UI, or ssh into the puppet master, and accept the new node request.

Kick off another puppet run after you have accepted the request to seal the deal and update the new node properly.

Related articles

How to Create a Vagrant Base Box from an Existing One
Some brief notes on Docker