1NUT configuration management with Augeas
2========================================
3
4Introduction
5------------
6
7Configuration has long been one of the two main NUT weaknesses. This is
8mostly due to the framework nature of NUT, and its many components and
9features, which make NUT configuration a very complex task.
10
11In order to address this point, NUT now provides configuration tools and
12manipulation abstraction, to anybody who want to manipulate NUT configuration,
13through Augeas lenses and modules.
14
15From link:http://augeas.net[Augeas homepage]:
16
17"Augeas is a configuration editing tool. It parses configuration files in their
18native formats and transforms them into a tree. Configuration changes are made
19by manipulating this tree and saving it back into native config files."
20
21In other words, Augeas is the dreamed Registry, with all the advantages
22(such as a uniform interface and tools), and the added bonus of being
23free/libre open source software and letting liberty on configuration file
24format.
25
26Requirements
27------------
28
29To be able to use Augeas with NUT, you will need to install Augeas,
30and also the NUT provided lenses, which describe NUT configuration
31files format.
32
33Augeas
34~~~~~~
35
36Having link:http://augeas.net[Augeas] installed.
37You will need at least version 0.5.1 (prior versions may work too, reports
38are welcome).
39
40As an example, on Debian and derivatives, do the following:
41
42	$ apt-get install augeas-lenses augeas-tools
43
44And optionally:
45
46	$ apt-get install libaugeas0 libaugeas-dev python-augeas
47
48On RedHat and derivatives, you have to install the packages 'augeas' and
49'augeas-libs'.
50
51[[augeas_user]]
52
53NUT lenses and modules for Augeas
54~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
55
56These are the *.aug files in the present directory.
57
58You can either install the files to the right location on your system,
59generally in '/usr/share/augeas/lenses/', or use these from NUT
60source directory ('nut/scripts/augeas'). The latter is to be preferred for
61the time being.
62
63
64Create a test sandbox
65---------------------
66
67NOTE: for now, it's easier to include an existing /etc/nut/ directory.
68
69	$ export AUGEAS_ROOT=./augeas-sandbox
70	$ mkdir $AUGEAS_ROOT
71	$ sudo cp -pr /etc/nut $AUGEAS_ROOT
72	$ sudo chown -R $(id -nu):$(id -ng) $AUGEAS_ROOT
73
74
75Start testing and using
76-----------------------
77
78Augeas provides many tools and
79link:http://augeas.net/download.html[languages bindings] (Python, Perl,
80Java, PHP, Ruby, ...), still with the same simple logic.
81
82This chapter will only illustrate some of these. Refer to the language
83binding's help and link:http://augeas.net/docs/index.html[Augeas documentation]
84for more information.
85
86
87Shell
88~~~~~
89
90Start an augeas shell using:
91
92	$ augtool -b
93
94NOTE: if you have not installed NUT lenses, add '-I/path/to/nut/scripts/augeas'.
95
96From there, you can perform different actions like:
97
98- list existing nut related files:
99
100	augtool> ls /files/etc/nut/
101	nut.conf/ = (none)
102	upsd.users/ = (none)
103	upsmon.conf = (none)
104	ups.conf/ = (none)
105	upsd.conf/ = (none
106+
107or using:
108+
109	augtool> match /files/etc/nut/*
110	/files/etc/nut/nut.conf = (none)
111	/files/etc/nut/upsd.users = (none)
112	/files/etc/nut/upsmon.conf = (none)
113	/files/etc/nut/ups.conf = (none)
114	/files/etc/nut/upsd.conf = (none)
115
116NOTE: if you don't see anything, you may search for error messages by using:
117+
118	augtool> ls /augeas/files/etc/nut/*/errors
119and
120	augtool> get /augeas/files/etc/nut/ups.conf/error/message
121	/augeas/files/etc/nut/ups.conf/error/message = Permission denied
122
123- create a new device entry (in ups.conf), called 'augtest':
124
125	augtool> set /files/etc/nut/ups.conf/augtest/driver dummy-ups
126	augtool> set /files/etc/nut/ups.conf/augtest/port auto
127	augtool> save
128
129- list the devices using the 'usbhid-ups' driver:
130
131	augtool> match /files/etc/nut/ups.conf/*/driver dummy-ups
132
133
134C
135~
136
137A library is available for C programs, along with pkg-config support.
138
139You can get the compilation and link flags using the following code
140in your configure script or Makefile:
141
142	CFLAGS="`pkg-config --silence-errors --cflags augeas`"
143	LDFLAGS="`pkg-config --silence-errors --libs augeas`"
144
145Here is an code sample using this library for NUT configuration:
146
147--------------------------------------------------------------------------------
148augeas *a = aug_init(NULL, NULL, AUG_NONE);
149ret = aug_match(a, "/files/etc/nut/*", &matches_p);
150ret = aug_set(a, "/files/etc/nut/ups.conf/augtest/driver", "dummy-ups");
151ret = aug_set(a, "/files/etc/nut/ups.conf/augtest/port", "auto");
152ret = aug_save(a);
153--------------------------------------------------------------------------------
154
155Python
156~~~~~~
157
158The `augeas` class abstracts access to the configuration files.
159
160  $ python
161  Python 2.5.1 (r251:54863, Apr  8 2008, 01:19:33)
162  [GCC 4.3.0 20080404 (Red Hat 4.3.0-6)] on linux2
163  Type "help", "copyright", "credits" or "license" for more information.
164  >>> import augeas
165  >>> a = augeas.augeas()
166  >>> a.match("/files/etc/nut/*")
167  ['/files/etc/nut/upsd.users', '/files/etc/nut/upsmon.conf', '/files/etc/nut/ups.conf', '/files/etc/nut/upsd.conf']
168  >>> a.set("/files/etc/nut/ups.conf/augtest/driver", "dummy-ups")
169  True
170  >>> a.set("/files/etc/nut/ups.conf/augtest/port", "auto")
171  True
172  >>> a.save()
173  True
174  >>>
175
176  $ grep -A 2 augtest /etc/nut/ups.conf
177  [augtest]
178  driver=dummy-ups
179  port=auto
180
181
182Perl
183~~~~
184
185The Perl binding is available through CPAN and packages.
186
187  use Config::Augeas;
188
189  my $aug = Config::Augeas->new( root => $aug_root ) ;
190
191  my @a = $aug->match("/files/etc/nut/*") ;
192  my $nb = $aug->count_match("/files/etc/nut/*") ;
193
194  $aug->set("/files/etc/nut/ups.conf/augtest/driver", "dummy-ups") ;
195  $aug->set("/files/etc/nut/ups.conf/augtest/port", "auto") ;
196
197  $aug->save ;
198
199
200Test the conformity testing module
201~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
202
203Existing configuration files can be tested for conformity. To do so, use:
204
205	$ augparse -I ./ ./test_nut.aug
206
207
208Complete configuration wizard example
209-------------------------------------
210
211Here is a Python example that generate a complete and usable standalone configuration:
212
213--------------------------------------------------------------------------------
214import augeas
215
216device_name="dev1"
217driver_name="usbhid-ups"
218port_name="auto"
219
220a = augeas.augeas()
221
222# Generate nut.conf
223a.set("/files/etc/nut/nut.conf/MODE", "standalone")
224
225# Generate ups.conf
226# FIXME: chroot, driverpath?
227a.set(("/files/etc/nut/ups.conf/%s/driver" % device_name), driver_name)
228a.set(("/files/etc/nut/ups.conf/%s/port" % device_name), port_name)
229
230# Generate upsd.conf
231a.set("/files/etc/nut/upsd.conf/#comment[1]", "just to touch the file!")
232
233# Generate upsd.users
234user = "admin"
235a.set(("/files/etc/nut/upsd.users/%s/password" % user), "dummypass")
236a.set(("/files/etc/nut/upsd.users/%s/actions/SET" % user), "")
237# FIXME: instcmds lens should be fixed, as per the above rule
238a.set(("/files/etc/nut/upsd.users/%s/instcmds" % user), "ALL")
239
240monuser = "monuser"
241monpasswd = "******"
242a.set(("/files/etc/nut/upsd.users/%s/password" % monuser), monpasswd)
243a.set(("/files/etc/nut/upsd.users/%s/upsmon" % monuser), "primary")
244
245# Generate upsmon.conf
246a.set("/files/etc/nut/upsmon.conf/MONITOR/system/upsname", device_name)
247# Note: we prefer to omit localhost, not to be bound to a specific
248# entry in /etc/hosts, and thus be more generic
249#a.set("/files/etc/nut/upsmon.conf/MONITOR/system/hostname", "localhost")
250a.set("/files/etc/nut/upsmon.conf/MONITOR/powervalue", "1")
251a.set("/files/etc/nut/upsmon.conf/MONITOR/username", monuser)
252a.set("/files/etc/nut/upsmon.conf/MONITOR/password", monpasswd)
253a.set("/files/etc/nut/upsmon.conf/MONITOR/type", "primary")
254
255# FIXME: glitch on the generated content
256a.set("/files/etc/nut/upsmon.conf/SHUTDOWNCMD", "/sbin/shutdown -h +0")
257
258# save config
259a.save()
260a.close()
261--------------------------------------------------------------------------------
262