Debugging rspec-puppet
Usually writing rspec-puppet tests is straightforward. Then you run into some problem that does not make any sense. In my case I ran into a couple of duplicate resource declaration issues when adding rspec tests to our puppetmaster-installer. The error message was not that useful:
$ pdk test unit --tests=spec/classes/puppetboard_spec.rb
--- snip ---
Failures:
1) puppetmaster::puppetboard minimal settings on ubuntu-18.04-x86_64 is expected
to compile into a catalogue without dependency cycles
Failure/Error: it { is_expected.to compile }
error during compilation: Evaluation Error: Error while evaluating a
Resource Statement, Duplicate declaration: Class[Apache] is already
declared; cannot redeclare (file: /home/samuli/opt/puppeteers/puppet-
puppetmaster/spec/fixtures/modules/puppetmaster/manifests/puppetboard.pp,
line: 156) (file: /home/samuli/opt/puppeteers/puppet-puppetmaster
/spec/fixtures/modules/puppetmaster/manifests/puppetboard.pp, line: 156,
column: 3) on node puppet.example.org
--- snip ---
That particular block of code in puppetboard.pp did include a parameterized call to the apache class. But nothing else (afaics) included that class. Also, in Vagrant the same code worked just fine, which made things seem even more bizarre. To add insult to the injury the error message did not tell where else the apache class was included. That would probably have been way too helpful.
Managing Jenkins with Puppet, part 1: Basic installation
It seems every other organization is using Jenkins these days. Jenkins is a continuous integration and continuous delivery server that can be used to automate building, testing, and delivering or deploying software.
Many organizations also use Puppet for their configuration management needs. Puppet is, if not the de facto configuration management solution, at least one of the most mature and field tested ones. It consists of several server components, agents, a declarative programming language, amongst others. Puppet can be used to install, set up and manage large number of all kinds of resources.
Modifying XML files with Puppet's Augeas resource
This article is based on an earlier article written in Finnish.
Here I describe how to make changes to an XML file with Augeas - a useful approach when managing the whole file as a template is out of the question. The configuration file used as an example, web.xml, belong to Pwm, and we intend to set the webapp context parameter.
As discussed before it is important to get an idea of how Augeas sees the file before attempting to modify it with Puppet. First we tell which Augeas lens to use (here: Xml) and which file(s) to associate with the Xml lens. This can be done with in one step:
Using Augeas to manage resources in Puppet
This translated from the original Finnish article that is available here.
The Augeas resource in Puppet allows one to manage parts of a complex configuration file instead of managing the whole file using a template or a static file. For trivial cases stdlib’s file_line resource may be sufficient. While use of templates or static files is in general more reliable and easier than use of Augeas, the latter is quite useful in many cases. As using Puppet Augeas resource directly is quite challenging, a useful practice is to first make the changes manually with “augtool” and only then convert the results into Puppet Augeas resources. We use PostgreSQL’s pg_hba.conf file here as an example.
Allowing changes to a Puppet-managed resource outside of Puppet
When a resource is managed by Puppet it is typically managed fully, or not at all. Exceptions to this rule, such as the “replace” parameter in the File resource, are rare. However, sometimes you end up having to change the properties of a resource outside of Puppet without making Puppet overwrite those changes on the next run. A good example is a set of firewall rules managed with puppetlabs-firewall - you generally want to manage the whole ruleset with Puppet so that you can be sure of the state of the ruleset. For example, if you have libvirt installed, a bunch of virbr0-related rules may appear without your consent. On RedHat-based distros you may also see several rules getting removed by puppetlabs-firewall. Or a fellow sysadmin may have added some random iptables rules for debugging purposes. These are good reasons to have
Getting the interface that matches an IP in Puppet
I was recently in a situation where I needed to figure out which interface name matched a particular, static IPv4 address. On a single or a handful of nodes this could have been hardcoded in Hiera, for example, but there were dozens of nodes. The way I solved this was by creating a custom fact that uses the IPv4 address and loops through the interfaces list to find the matching interface name:
Why modules in Puppetfile should be sorted
This is probably one of the shortest blog postings in the history of this blog. But as this topic does not seem to be covered in more generic articles about avoiding Git merge conflicts (e.g. this, this and this), here it goes.
Adding modules to the Puppetfile is a quite common task. When you or your team has multiple feature branches at the same time many of those branches may add new Puppet modules to the Puppetfile. This is fine, unless the new modules are added to the bottom of the Puppetfile: Git will get confused because it sees that multiple commits have changed the exact same place in the Puppetfile.
Puppet rspec testing: understanding describe and context
In the Puppet module rspec testing with PDK blog post I covered the procedure of creating and running puppet-rspec tests with PDK. This blog post will go more in-depth to that topic, in particular describe and context which you see in all puppet-rspec tests.
When looking at the puppet-rspec test syntax the first time it looks very “rubyesque”. Somebody used to staring at Python code, for example, could call the syntax “odd” or “1337”. Fortunately reading the Ruby rspec documentation helps understand what is going on under the hood and thus making the spec files look less magical. In my case rspec documentation helped understand how contexts work. In the previous blog post a context was created for every supported operating system listed in metadata, and rspec tests were run for each of them by using facts from facterdb.
Testing Puppet feature branches in Foreman
With default settings Foreman does not allow Puppet Agents to specify their own environment when connecting to the Puppetserver. This makes it impossible to use r10k and feature branch workflow like you can with a normal Puppetserver. This behavior can fortunately be reverted easily by modifying Foreman configuration file, /etc/foreman/settings.yaml:
# Allow testing feature branches on nodes
:enc_environment: false
After modifying settings restart the webserver, e.g.
Explicit high-level dependencies in Puppet
I’ve noticed that some people - I won’t reveal their names here to protect them - love using contain and/or ordering arrows in Puppet. A typical use-case is for role classes:
class role::webserver { contain ::packetfilter::endpoint contain ::profile::monit contain ::profile::unixbase contain ::profile::ipa_client contain ::profile::webserver
Class[::packetfilter::endpoint]
-> Class[::profile::monit]
-> Class[::profile::unixbase]
-> Class[::profile::ipa_client]
-> Class[::profile::webserver]
}
The above code nicely ensures that all the classes get applied in the exact order defined above. What happens under the hood is that Puppet generates dependencies between the classes and applies them in order.