Dominic Cleal's Blog

OggCamp 11 highlights
OggCamp 11 is over after a long, but great weekend. My personal highlights had to be:
  • Lorna Jane Mitchell, speaking on open source in your career. A well-prepared and insightful talk about how open source and community-based work she'd done in her spare time had helped her out in business many times. She highlighted the need to blog and how both organising and speaking at community conferences had landed her a variety of jobs and allowed her to move into new areas without previous work experience. Excellent last year and excellent again this time.
  • Gordon Pearce showed his lysdr project, an implementation of a Software Defined Radio (SDR) with easy GUI-based tuning and filtering features. It uses JACK for connecting up audio and can use an inexpensive hardware module for the RF side (there are lots of kits and some prebuilt USB components available).
  • Edd took apart an example shellcode payload, of the sort that would be executed on a compromised host to gain shell access. The talk was an expansion of his blog post and showed off the neat radare2 tool for disassembly of binaries, while demonstrating how self-modifying code was done.
Thanks to all the OggCamp volunteers for putting it on!
Puppet: could not find a default provider for augeas

Augeas is a configuration editing API that Puppet can use to perform targeted modifications to config files. If it's not installed properly when you try to use it, you'll get the following error from Puppet:

Could not find a suitable provider for augeas
Could not find a default provider for augeas

This is Puppet's way of saying that the only provider for the augeas type, which uses the ruby-augeas bindings cannot be loaded and it doesn't have an alternative provider implementation. Every time we help somebody in #puppet fix it, the cause falls into one of these areas:

1. Install ruby-augeas
For Red Hat or Fedora style systems, the package is ruby-augeas and for Debian style systems, it's libaugeas-ruby (or perhaps libaugeas-ruby1.8 for the Ruby 1.8 variant). There's also a rubygem if you prefer.

It's critical that you use your distribution's packages or ones that are known to be compatible with your distribution, or you'll hit problems. The ruby-augeas bindings are built against both Ruby and Augeas C bindings, so if you download a package built against a different binary of Ruby or Augeas to the ones you're running, it probably won't work. This is the most common issue - your packages have to be binary compatible.

Under RHEL or similar, use EPEL for compatible packages. If you've decided to "update" the version of Ruby on your RHEL box to one from a third party, you'll almost certainly have broken the binary compatibility provided by the distro by doing so and will have to build it yourself or find a compatible source.

2. Test with Ruby directly
Try loading the ruby-augeas bindings using Ruby, without Puppet.

$ ruby -raugeas -e "puts"
If you're using rubygems, you need to load the rubygems library first:
$ echo -e "require 'augeas'\nputs" | ruby -rrubygems

If you get the above, but Puppet still can't load the provider then you're probably using a different Ruby installation. Is your Puppet client running with one version of Ruby, while your shell's PATH is loading another?

3. Error loading ruby-augeas Ruby library

If you get something other than the output above, there's an issue loading the library. If you see this:

$ ruby -raugeas -e "puts"
ruby: no such file to load -- augeas (LoadError)
This indicates a failure to load the augeas.rb file (note it says augeas before the LoadError, not _augeas as explained below). The augeas.rb file should be in the directory given by Ruby's sitelibdir:
$ ruby -rrbconfig -e "puts Config::CONFIG['sitelibdir']"

Check that the ruby-augeas package you installed placed an augeas.rb into this directory.

4. Error loading shared library

In all likelihood, you see something like this:

$ ruby -raugeas -e "puts"
/usr/lib/ruby/site_ruby/1.8/augeas.rb:23:in `require': no such file to load -- _augeas (LoadError)
    from /usr/lib/ruby/site_ruby/1.8/augeas.rb:23

Using rubygems will give a similar error - again, the key part is that it cannot load _augeas (with the underscore). This indicates it's trying to load the shared library, named Check that the file exists in Ruby's sitearchdir:
$ ruby -rrbconfig -e "puts Config::CONFIG['sitearchdir']"

Three points when checking whether these files are in the expected place:

  1. Use copy and paste, check whether the files are there with `ls`. You'll get it wrong if you compare paths by eye.
  2. Check the Ruby versions carefully. At the time of writing, some distributions are shipping both Ruby 1.8 and 1.9 so the paths and packages are very similar.
  3. Check the architecture is correct, of both Ruby and ruby-augeas. If Ruby is 32-bit and looking under /usr/lib for a 64-bit shared library stored under /usr/lib64 it won't work.

Again, if something here doesn't match then check the packages. Nine times out ten, they don't match or aren't meant to be compatible with each other. Usually the binary ruby-augeas package doesn't match the Ruby build you're using.

5. Check linking
Occasionally the ruby-augeas library isn't built correctly against Augeas' library. It might be hard to determine this as you might have got the LoadError on as above, despite the .so being in the correct location.

With the path to, check the library dependencies:

$ ldd /usr/lib64/ruby/site_ruby/1.8/x86_64-linux/ =>  (0x00007fff5fbff000) => /usr/lib64/ (0x00007ff4d33eb000) => not found

Any library listed as "not found" is an immediate issue to investigate. The other two to look for are libruby and libaugeas. Check again that the Ruby library it's linked to is part of the Ruby distribution you're using.

The libaugeas library should be in one of your system linker's search directories, or built to be somewhere else. If it isn't in a standard directory then check the Augeas library is installed (augeas-libs on Red Hat, libaugeas0 on Debian). It might also be worth checking standard Augeas tools (augeas on Red Hat, augeas-tools on Debian) are working and also linked correctly.

If it wasn't obvious by now, 98% of the time I find the cause of this error is due to packaging. Not necessarily the packages being at fault, but the wrong combination or versions being used together. Make use of your distro's packaging wherever possible or ensure you understand the third party source for your packages and the level of compatibility they offer.

Puppet Augeas provider news and enhancements

Lately I've been submitting a few tweaks and watching changes to Puppet's Augeas provider closely, so I thought I'd write up a summary of recent modifications and those that might be coming.

#6494: New commands, defvar, defnode, mv and setm
Available from Puppet 2.7.0

Some new commands were added to the provider that are available in newer versions of Augeas and ruby-augeas. These follow exactly the same syntax as augtool uses (so see its help for more info):

  • defvar/defnode create variables to save typing. Needs Augeas 0.5.0 and ruby-augeas 0.3.0 or higher.
  • mv for moving a node and its children around the tree. Needs Augeas 0.3.0 and ruby-augeas 0.2.0 or higher.
  • setm for setting the value of multiple nodes at once (like a loop). Needs Augeas 0.7.2 and ruby-augeas 0.4.0 or higher.

#2728: File diffs and 50% speed increase
Available from Puppet 2.7.3

Mike Knox tackled a long-standing feature request to give file diffs when Augeas resources are applied, in the same way as normal File resoures. When running Puppet with --test or --show_diff, you'll now see a diff printed for the modified file.

Due to the implementation, this allowed Mike to make a great optimisation, halving the time it takes to apply an Augeas resource. The previous implementation followed Puppet's usual pattern of checking if the resource was in sync (i.e. changes had to be applied) before executing those changes. The change now means the provider only makes the change once during the test phase and no longer loads Augeas again when making the change to the live filesystem.

(A bugfix will be included in 2.7.4 for resources that fail to save).

#7854: Augeas version fact
Available from Facter 1.6.1

A new fact will contain the version number of the underlying Augeas library as $augeasversion. This is just the version of the library (from /augeas/version) and not ruby-augeas or the lenses necessarily.

#5606: Error messages shown in Puppet debug mode
Available from Puppet 2.8.0 (Telly)

When Augeas changes cannot be saved, the provider unhelpfully reports Save failed with return code false to say that aug_save failed. This usually indicates the changes made to the tree can't be written back to the file as they don't map to the lens' data structure.

Augeas provides some details about where in the lens the disagreement occurred under /augeas//error, so this information is now printed to the debug log (run puppet agent -t --debug) instead of having to reproduce the error by hand with augtool.

#7285: Optimise file loading using context information
Available from Puppet 2.8.0 (Telly)

Starting up Augeas with all ~90 lenses over 100-200 files normally takes a second or two, which quickly adds up when applying a large catalog containing many Augeas resources. Using the context attribute if it's given, this patch optimises loading to only include the file given by the resource context.

It uses the glob() path function added in Augeas 0.9.0 to find /augeas/load//incl nodes (which contain globs) that match the context, then deletes all other incl nodes. Next it calls aug_load, resulting in a much quicker load time.

Use aug_srun to evaluate commands
In development

Augeas 0.9.0 exposed the command parsing from augtool as a separate API function, aug_srun. Currently the provider parses all commands itself, adding in the context where needed and then calling the appropriate aug_* method from the ruby-augeas API. It simulates exactly what augtool (and aug_srun) would do to try and give fully compatible command processing.

Instead we could use aug_srun for command parsing, making a much smaller Augeas provider. This would also help us get new commands that are added to Augeas as soon as they're available, without users having to wait for updates to Augeas, ruby-augeas and finally Puppet.

It also would help us look at improving the commands available - perhaps there are changes that could be made so it's easier to create fully idempotent Augeas resources from within Puppet (without onlyif clauses).