Recently I came across an interesting problem. I had to install a kernel from the 3.10 branch on CentOS 6 and there was a need to update grub.conf - change the default kernel plus add a boot option. Both mentioned operations had to be done in Puppet 3.7 (Augeas is of course also available in higher versions of Puppet). Sounds easy, right? In the traditional approach (I saw it in many companies) I would probably create another template, but I was wondering if there is a way to do it in a more elegant and universal way. Of course we can create another template and not think about it, but what if we actually do not know what to expect in grub.conf? Serving grub.conf as a template can have a bunch of other implications - dealing with updates, mixed versions of kernels etc. In other words, another thing we would need to maintain and keep an eye on. Actually, why should we provide another template if we only want to add a single value to, let’s say, sysctl.conf?

To deal with it we can execute some nasty shell command (sed, awk - you name it) or use a more sophisticated interface to configuration files - Augeas. Augeas is actually a library written in C. This library provides us an interface which treats a configuration file as a tree. Additionally, we can dynamically change every single element of this tree. Augeas is not a new solution and provides bindings for most popular programming languages (Python, Ruby). It’s no surprise it’s also available in Puppet by default.

If I want to add some value to sysctl.conf I can do it like this:

augeas { "sysctl":
  context => '/files/etc/sysctl.conf',
  changes => [
    'set kernel.keys.root_maxkeys 1000000',
  ],
}

We can execute it many times. The required entry will be added only once. From what I noticed, this is the simplified way of calling Augeas in Puppet.

For some more sophisticated configuration files there are specialized interfaces. In Puppet we can access them by specifying something called a lens. I did not check how it works under the hood in Puppet, but I suspect Puppet selects the lens automatically if we do not specify any. Below is an example of how we can make changes in grub.conf (a real-world example I use in Puppet):

augeas { 'grub_conf':
  incl    => '/boot/grub/grub.conf',
  lens    => 'grub.lns',
  changes => [
    'set default 0',
    'setm  title[1]/kernel swapaccount 1',
    'rm  title[1]/kernel/quiet',
    'rm  title[1]/kernel/rhgb'
    ],
  require => Package['kernel-lt']
}
Let’s go through it line by line:
  • incl - specifies what configuration file we would like to change
    • lens - specifies the name of the lens we would like to use
    • changes - defines a group of modifications (or a single one) we would like to make
The changes section supports operators like:
  • set - sets the required field to the specified value,
    set default 0 produces default=0 in the configuration file
    • setm - adds a value to lines which match (m stands for multi, I guess)
    • rm - removes a value from lines which match

You will probably ask - “how do I know how the line I want to change is represented in Augeas?”. To see what a given config file looks like when Augeas converts it to a tree, you can use augtool. It should be available in the standard CentOS repo (it’s also available on OSX via Brew). It’s a command line interface for Augeas.

See an example below:
[root@localhost ~]# augtool ls /files/boot/grub/grub.conf
#comment[1] = grub.conf generated by anaconda
#comment[2] = Note that you do not have to rerun grub after making changes to this file
#comment[3] = NOTICE:  You have a /boot partition.  This means that
#comment[4] = all kernel and initrd paths are relative to /boot/, eg.
#comment[5] = root (hd0,0)
#comment[6] = kernel /vmlinuz-version ro root=/dev/mapper/VolGroup-lv_root
#comment[7] = initrd /initrd-[generic-]version.img
#comment[8] = boot=/dev/sda
default = 0
timeout = 5
splashimage = (hd0,0)/grub/splash.xpm.gz
hiddenmenu = (none)
title[1]/ = CentOS (3.10.x86_64)
title[2]/ = CentOS 6 (2.6.32-504.8.1.el6.x86_64)
[root@localhost ~]#

Some folks also figured out that Augeas in Puppet can be integrated as providers to create an even more user friendly interface. You can read more about that here http://augeasproviders.com/

– Robert