Recently I came across an interesting problem. I had to install kernel from branch 3.10 on CentOS6 and there was a need to update grub.conf - change default kernel plus add boot option. Both mentioned operation had to be done in Puppet 3.7 (Augeas are of course also available in the higher version 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 do not think about that but what if we actually do not know what we can expect in grub.conf. Serving grub.conf as a template can have bunch of other implication - dealing with updates, mixed versions of kernels ect. In other words another thing we would need to maintain and keep an eye on. Actually wy we should provide another template if we only want to add single value to lets say sysctl.conf?

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

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

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

We can execute it many times. Required entry will be added only once. From what I noticed this is a simplified way how we can call Augeas in puppet.

For some more sophisticated configuration files there are specialized interfaces. In puppet we can access them by specifying something what is called lens. I did not check how in works under the hood in puppet but I suspect the puppet select lens automatically if we do not specify any. Below is an example how we can make changes in grub.conf (real world example I use in the 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']
}
Lets go through it line by line:
  • inc - specify what configuration file we would like to change
    • lens - specify the name of the lens we would like to use
    • changes - defines group or single modification we would like to make
changes section support operators like:
  • set - sets required field to specified value,
    set default 0 produces default=0 in the configuration file
    • setm - adds value to line which matches to (m stands for multi I guess)
    • rm removes value from line which matches to

You probably will ask - “how do I know how line I desire to change should be presented to augeas”. To see how defined config file looks like when Augeas converts it to tree you can use augtool. It should be available in the standard CentOS repo (it’s also available on the 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 even more user friendly interface. You can read more about that here http://augeasproviders.com/

– Robert