A quick tour
This tutorial gives a brief overview of using Augeas, and augtool in particular. It's highly recommended that you follow along on your own; to do so, first download and install Augeas. Then, create a sandbox so that you can safely modify files without affecting your system. The commands below create the sandbox from /etc on your system, but you might want to copy the files from tests/root in the source tarball — all the examples below were run against those files.
export AUGEAS_ROOT=/tmp/augeas-sandbox mkdir $AUGEAS_ROOT sudo cp -pr /etc $AUGEAS_ROOT sudo chown -R $USER $AUGEAS_ROOT augtool -b
The -b option tells augtool to preserve the original file with an extension of .augsave whenever it makes a change.
In the augtool shell, type help to get a list of commands. The print command is particularly useful to explore what data is present in the tree. The commands to run can either be typed interactively into augtool (with TAB completion on commands and tree paths), or piped in from standard input.
Adding an entry to /etc/hosts
To warm up, let's do something very simple: adding a new entry to /etc/hosts. In the augtool shell, type the following commands:
set /files/etc/hosts/10000/ipaddr 192.168.0.1 set /files/etc/hosts/10000/canonical pigiron.example.com set /files/etc/hosts/10000/alias[1] pigiron set /files/etc/hosts/10000/alias[2] piggy save
The four set commands create four nodes underneath /files/etc/hosts/10000, and assign them the values passed as the second argument. The data parsed from a file with full path FILE in the filesystem is stored in the tree underneath /files/FILE; with that the set commands manipulate an entry in the file /etc/hosts. A second hierarchy underneath /augeas/files/FILE contains metadata about the file, such as an indication of any errors encountered when the file was read.
The set command creates non-existant nodes as needed. There is a second command, ins, to create new nodes in the tree that provides more control over where exactly a new node shows up, in particular where in the list of its siblings it appears. Because files are inherently sequential, the order of sibling nodes in the tree matters.
There is nothing special about calling that host entry 10000: we just chose that since it's safe to assume that such an entry does not exist yet. The schema for /etc/hosts requires that the names of the host entries are positive numbers, though they don't need to be numbered sequentially.
The notation alias[1] and alias[2] tells Augeas to set the value for the first and second child of /files/etc/hosts/10000. Both nodes are called /files/etc/hosts/10000/alias; the new host entry can be listed with
ls /files/etc/hosts/10000
or searched for with
match /files/etc/hosts/*/ipaddr 192.168.0.1
which prints /files/etc/hosts/10000/ipaddr.
Running (cd ${AUGEAS_ROOT} && gendiff . .augsave) in the sandbox confirms that /etc/hosts now has one additional entry at the end:
diff -up ./etc/hosts.augsave ./etc/hosts --- ./etc/hosts.augsave +++ ./etc/hosts @@ -4,3 +4,4 @@ #172.31.122.254 granny.watzmann.net granny puppet #172.31.122.1 galia.watzmann.net galia 172.31.122.14 orange.watzmann.net orange +192.168.0.1 pigiron.example.com pigiron piggy
Changing /etc/grub.conf
Modifying a slightly more complex file, /etc/grub.conf, follows the same lines as modifying /etc/hosts. One of the big advantages of Augeas is that configuration data is manipulated in the same way, regardless of how it is stored in the native config files.
While the above change to /etc/hosts can be easily achieved with standard shell tools (cat comes to mind), and /etc/hosts in general can be manipulated relatively easily with sed, grep, awk, or tools readily available in most scripting languages, manipulating /etc/grub.conf with those tools is quite a bit harder.
We want to change /etc/grub.conf so that grub boots the second boot entry by default, and remove the third boot record completely. The following two commands do that — you should look at the tree before and after the change using print /files/etc/grub.conf:
set /files/etc/grub.conf/default 1 rm /files/etc/grub.conf/title[3] save
The diff between the old and new file confirms that Augeas changed what was intended:
diff -up ./etc/grub.conf.augsave ./etc/grub.conf
--- ./etc/grub.conf.augsave 2008-04-09 16:14:06.000000000 -0700
+++ ./etc/grub.conf 2008-04-15 15:32:09.000000000 -0700
@@ -7,7 +7,7 @@
# kernel /vmlinuz-version ro root=/dev/vg00/lv00
# initrd /initrd-version.img
#boot=/dev/sda
-default=0
+default=1
timeout=5
splashimage=(hd0,0)/grub/splash.xpm.gz
hiddenmenu
@@ -19,11 +19,6 @@ title Fedora (2.6.24.3-50.fc8)
root (hd0,0)
kernel /vmlinuz-2.6.24.3-50.fc8 ro root=/dev/vg00/lv00
initrd /initrd-2.6.24.3-50.fc8.img
-title Fedora (2.6.21.7-3.fc8xen)
- root (hd0,0)
- kernel /xen.gz-2.6.21.7-3.fc8
- module /vmlinuz-2.6.21.7-3.fc8xen ro root=/dev/vg00/lv00
- module /initrd-2.6.21.7-3.fc8xen.img
title Fedora (2.6.24.3-34.fc8)
root (hd0,0)
kernel /vmlinuz-2.6.24.3-34.fc8 ro root=/dev/vg00/lv00
Making sshd accept an additional environment variable
The config file for sshd is deceptively simple, but has some subtle intricacies. One of them are Match blocks at the end of the file, another is the fact that some settings can be repeated in the file, and values are accumulated, and that their values are best viewed as arrays.
To illustrate this, we will add a new environment variable FOO to the AcceptEnv setting in /etc/ssh/sshd_config. The schema that Augeas uses for sshd_config``[1]_ by default maps multiple ``AcceptEnv lines into multiple tree nodes with the name AcceptEnv, similar to how multiple aliases in /etc/hosts are handled. Since each line contains a list of environment variables, the schema splits that list into separate tree nodes numbered starting at one. The following lines in sshd_config
AcceptEnv LANG LC_CTYPE AcceptEnv LC_IDENTIFICATION LC_ALL
are mapped into a tree
AcceptEnv[1]/1 = "LANG" AcceptEnv[1]/2 = "LC_CTYPE" AcceptEnv[2]/1 = "LC_IDENTIFICATION" AcceptEnv[2]/2 = "LC_ALL"
This allows for very fine-grained access to individual value in the sshd_config file, and preserves enough information so that Augeas can decide which entries go on the same line. To see all AcceptEnv entries, run
print /files/etc/ssh/sshd_config/AcceptEnv/*
To add a new variable FOO at the end of the last AcceptEnv line, we perform
set /files/etc/ssh/sshd_config/AcceptEnv[last()]/10000 FOO save
The addition of [last()] to AcceptEnv in the path tells Augeas that we are talking about the last node named AcceptEnv. Augeas requires that for a set the path expression corresponds either to an existing node, or to no node at all (in which case a new node is created). Writing the above command as
set /files/etc/ssh/sshd_config/AcceptEnv/10000 FOO
results in an error when there are multiple AcceptEnv entries in the tree. In that case, Augeas can not figure out under which of them you want to put the entry labelled 10000.
Again, the above commands lead to the expected diff, the addition of FOO to the last AcceptEnv line:
diff -up ./etc/ssh/sshd_config.augsave ./etc/ssh/sshd_config --- ./etc/ssh/sshd_config.augsave +++ ./etc/ssh/sshd_config @@ -93,7 +93,7 @@ UsePAM yes # Accept locale-related environment variables AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT -AcceptEnv LC_IDENTIFICATION LC_ALL +AcceptEnv LC_IDENTIFICATION LC_ALL FOO #AllowTcpForwarding yes #GatewayPorts no #X11Forwarding no
