Your browser doesn't support the features required by impress.js, so you are presented with a simplified version of this presentation.

For the best experience please use the latest Chrome, Safari or Firefox browser.

Are you tired of ugly
sed and awk one liners?
or of using tons of
  different parsing libraries
    or common::line tricks?
Become a configuration
   surgeon with

Augeas

You have heard that files are made from trees...
Here configuration files are turned into a tree structure...
/etc/hosts -> /files/etc/hosts
... and their parameters into branches and leaves:
$ augtool print /files/etc/hosts
 /files/etc/hosts
 /files/etc/hosts/1
 /files/etc/hosts/1/ipaddr = "127.0.0.1"
 /files/etc/hosts/1/canonical = "localhost"
      
Augeas provides many stock parsers, called lenses:
Access		Cron		Host_Conf
Aliases		Crypttab	Hostname
Anacron		debctrl		Hosts_Access
Approx		Desktop		IniFile
AptConf		Dhcpd		Inputrc
Automaster	Dpkg		Iptables
Automounter	Exports		Kdump
BackupPCHosts	FAI_DiskConfig	Keepalived
cgconfig	Fonts		Keepalived
cgrules		Fuse		Login_defs
Channels	Grub		Mke2fs
...
       
... as well as generic lenses available to build new parsers:
Build		Sep			Simplelines
IniFile		Shellvars		Simplevars
Rx		Shellvars_list		Util
       
augtool lets you inspect the tree:
$ augtool
augtool> ls /
 augeas/ = (none)
 files/ = (none)

augtool> print /files/etc/passwd/root/
 /files/etc/passwd/root
 /files/etc/passwd/root/password = "x"
 /files/etc/passwd/root/uid = "0"
 /files/etc/passwd/root/gid = "0"
 /files/etc/passwd/root/name = "root"
 /files/etc/passwd/root/home = "/root"
 /files/etc/passwd/root/shell = "/bin/bash"
      
The tree can be queried using XPath:
augtool> print /files/etc/passwd/*[uid='0'][1]
 /files/etc/passwd/root
 /files/etc/passwd/root/password = "x"
 /files/etc/passwd/root/uid = "0"
 /files/etc/passwd/root/gid = "0"
 /files/etc/passwd/root/name = "root"
 /files/etc/passwd/root/home = "/root"
 /files/etc/passwd/root/shell = "/bin/bash"
      
But also modified:
$ getent passwd root
root:x:0:0:root:/root:/bin/bash

$ augtool
augtool> set /files/etc/passwd/*[uid='0']/shell /bin/sh
augtool> match /files/etc/passwd/*[uid='0']/shell
 /files/etc/passwd/root/shell = "/bin/sh"
augtool> save
Saved 1 file(s)
augtool> exit

$ getent passwd root
root:x:0:0:root:/root:/bin/sh
      
Puppet has a native provider:
augeas{ "export foo" : 
    context => "/files/etc/exports",
    changes => [
        "set dir[. = '/foo'] /foo",
        "set dir[. = '/foo']/client weeble",
        "set dir[. = '/foo']/client/option[1] ro",
        "set dir[. = '/foo']/client/option[2] all_squash",
    ],
} 
      
It is better to wrap things up:
define kmod::generic(
  $type, $module, $ensure=present,
  $command='', $file='/etc/modprobe.d/modprobe.conf'
) {
  augeas {"${type} module ${module}":
    context => "/files${file}",
    changes => [
      "set ${type}[. = '${module}'] ${module}",
      "set ${type}[. = '${module}']/command '${command}'",
    ],
  }
}
      
mcollective also has an agent:
$ mco augeas match /files/etc/passwd/rpinson/shell

 * [ ======================================> ] 196 / 196

...
wrk1                                    
saja-map-dev                            
    /files/etc/passwd/rpinson/shell = /bin/bash
wrk3                                    
wrk4                                    
    /files/etc/passwd/rpinson/shell = /bin/bash
...
    
Bindings include Perl, Python, Java, PHP, Haskell, Ruby...
require 'augeas'
aug = Augeas.open
if aug.match('/augeas/load/'+lens).length > 0
  aug.set('/augeas/load/'+lens+'/incl[last()+1]', path)
else
  aug.set('/augeas/load/'+lens+'/lens', lens+'.lns')
end
    
From the mcollective agent
You can use them with facter:
Facter.add(:augeasversion) do setcode do
    begin
      require 'augeas'
      aug = Augeas::open('/', nil, Augeas::NO_MODL_AUTOLOAD)
      ver = aug.get('/augeas/version')
      aug.close
      ver
    rescue Exception
      Facter.debug('ruby-augeas not available')
    end
  end
end
    
From the augeasversion fact
Or to write native types:
  def ip
    aug = nil
    path = "/files#{self.class.file(resource)}"
    begin
      aug = self.class.augopen(resource)
      aug.get("#{path}/*[canonical =
         '#{resource[:name]}']/ipaddr")
    ensure
      aug.close if aug
    end
  end
    
See https://github.com/domcleal/augeasproviders
Augeas reports its errors in /augeas:
augtool> print /augeas//error
/augeas/files/etc/mke2fs.conf/error = "parse_failed"
/augeas/files/etc/mke2fs.conf/error/pos = "82"
/augeas/files/etc/mke2fs.conf/error/line = "3"
/augeas/files/etc/mke2fs.conf/error/char = "0"
/augeas/files/etc/mke2fs.conf/error/lens = \
   "/usr/share/augeas/lenses/dist/mke2fs.aug:132.10-.49:"
/augeas/files/etc/mke2fs.conf/error/message = \
   "Get did not match entire input"
    
Other projects using Augeas:

  • libvirt
  • Nut
  • guestfs
  • ZYpp
  • Augeas-validator
  • Future projects:

  • better integration in Mcollective 2.0
  • content validation in Puppet
  • ...
  • your idea/project here...
  • questions ?
    freenode: #augeas

    Use a spacebar or arrow keys to navigate