Configuration has long been one of the two main NUT weaknesses. This is mostly due to the framework nature of NUT, and its many components and features, which make NUT configuration a very complex task.
In order to address this point, NUT now provides configuration tools and manipulation abstraction, to anybody who want to manipulate NUT configuration, through Augeas lenses and modules.
From Augeas homepage:
"Augeas is a configuration editing tool. It parses configuration files in their native formats and transforms them into a tree. Configuration changes are made by manipulating this tree and saving it back into native config files."
In other words, Augeas is the dreamed Registry, with all the advantages (such as a uniform interface and tools), and the added bonus of being free/libre open source software and letting liberty on configuration file format.
To be able to use Augeas with NUT, you will need to install Augeas, and also the NUT provided lenses, which describe NUT configuration files format.
Having Augeas installed. You will need at least version 0.5.1 (prior versions may work too, reports are welcome).
As an example, on Debian and derivatives, do the following:
$ apt-get install augeas-lenses augeas-tools
And optionally:
$ apt-get install libaugeas0 libaugeas-dev python-augeas
On RedHat and derivatives, you have to install the packages augeas and augeas-libs.
These are the *.aug files in the present directory.
You can either install the files to the right location on your system, generally in /usr/share/augeas/lenses/, or use these from NUT source directory (nut/scripts/augeas). The latter is to be prefered for the time being.
for now, it’s easier to include an existing /etc/nut/ directory.
$ export AUGEAS_ROOT=./augeas-sandbox $ mkdir $AUGEAS_ROOT $ sudo cp -pr /etc/nut $AUGEAS_ROOT $ sudo chown -R $(id -nu):$(id -ng) $AUGEAS_ROOT
Augeas provides many tools and languages bindings (Python, Perl, Java, PHP, Ruby, …), still with the same simple logic.
This chapter will only illustrate some of these. Refer to the language binding’s help and Augeas documentation for more information.
Start an augeas shell using:
$ augtool -b
if you have not installed NUT lenses, add -I/path/to/nut/scripts/augeas.
From there, you can perform different actions like:
list existing nut related files:
augtool> ls /files/etc/nut/ nut.conf/ = (none) upsd.users/ = (none) upsmon.conf = (none) ups.conf/ = (none) upsd.conf/ = (none
or using:
augtool> match /files/etc/nut/* /files/etc/nut/nut.conf = (none) /files/etc/nut/upsd.users = (none) /files/etc/nut/upsmon.conf = (none) /files/etc/nut/ups.conf = (none) /files/etc/nut/upsd.conf = (none)
if you don’t see anything, you may search for error messages by using:
+ augtool> ls /augeas/files/etc/nut/*/errors and augtool> get /augeas/files/etc/nut/ups.conf/error/message /augeas/files/etc/nut/ups.conf/error/message = Permission denied
create a new device entry (in ups.conf), called augtest:
augtool> set /files/etc/nut/ups.conf/augtest/driver dummy-ups augtool> set /files/etc/nut/ups.conf/augtest/port auto augtool> save
list the devices using the usbhid-ups driver:
augtool> match /files/etc/nut/ups.conf/*/driver dummy-ups
C ~
A library is available for C programs, along with pkg-config support.
You can get the compilation and link flags using the following code in your configure script or Makefile:
CFLAGS="`pkg-config --silence-errors --cflags augeas`" LDFLAGS="`pkg-config --silence-errors --libs augeas`"
Here is an code sample using this library for NUT configuration:
augeas *a = aug_init(NULL, NULL, AUG_NONE); ret = aug_match(a, "/files/etc/nut/*", &matches_p); ret = aug_set(a, "/files/etc/nut/ups.conf/augtest/driver", "dummy-ups"); ret = aug_set(a, "/files/etc/nut/ups.conf/augtest/port", "auto"); ret = aug_save(a);
The augeas
class abstracts access to the configuration files.
$ python Python 2.5.1 (r251:54863, Apr 8 2008, 01:19:33) [GCC 4.3.0 20080404 (Red Hat 4.3.0-6)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import augeas >>> a = augeas.augeas() >>> a.match("/files/etc/nut/*") ['/files/etc/nut/upsd.users', '/files/etc/nut/upsmon.conf', '/files/etc/nut/ups.conf', '/files/etc/nut/upsd.conf'] >>> a.set("/files/etc/nut/ups.conf/augtest/driver", "dummy-ups") True >>> a.set("/files/etc/nut/ups.conf/augtest/port", "auto") True >>> a.save() True >>>
$ grep -A 2 augtest /etc/nut/ups.conf [augtest] driver=dummy-ups port=auto
The Perl binding is available through CPAN and packages.
use Config::Augeas;
my $aug = Config::Augeas->new( root => $aug_root ) ;
my @a = $aug->match("/files/etc/nut/*") ; my $nb = $aug->count_match("/files/etc/nut/*") ;
$aug->set("/files/etc/nut/ups.conf/augtest/driver", "dummy-ups") ; $aug->set("/files/etc/nut/ups.conf/augtest/port", "auto") ;
$aug->save ;
Here is a Python example that generate a complete and usable standalone configuration:
import augeas device_name="dev1" driver_name="usbhid-ups" port_name="auto" a = augeas.augeas() # Generate nut.conf a.set("/files/etc/nut/nut.conf/MODE", "standalone") # Generate ups.conf # FIXME: chroot, driverpath? a.set(("/files/etc/nut/ups.conf/%s/driver" % device_name), driver_name) a.set(("/files/etc/nut/ups.conf/%s/port" % device_name), port_name) # Generate upsd.conf a.set("/files/etc/nut/upsd.conf/#comment[1]", "just to touch the file!") # Generate upsd.users user = "admin" a.set(("/files/etc/nut/upsd.users/%s/password" % user), "dummypass") a.set(("/files/etc/nut/upsd.users/%s/actions/SET" % user), "") # FIXME: instcmds lens should be fixed, as per the above rule a.set(("/files/etc/nut/upsd.users/%s/instcmds" % user), "ALL") monuser = "monuser" monpasswd = "******" a.set(("/files/etc/nut/upsd.users/%s/password" % monuser), monpasswd) a.set(("/files/etc/nut/upsd.users/%s/upsmon" % monuser), "master") # Generate upsmon.conf a.set("/files/etc/nut/upsmon.conf/MONITOR/system/upsname", device_name) # Note: we prefer to omit localhost, not to be bound to a specific # entry in /etc/hosts, and thus be more generic #a.set("/files/etc/nut/upsmon.conf/MONITOR/system/hostname", "localhost") a.set("/files/etc/nut/upsmon.conf/MONITOR/powervalue", "1") a.set("/files/etc/nut/upsmon.conf/MONITOR/username", monuser) a.set("/files/etc/nut/upsmon.conf/MONITOR/password", monpasswd) a.set("/files/etc/nut/upsmon.conf/MONITOR/type", "master") # FIXME: glitch on the generated content a.set("/files/etc/nut/upsmon.conf/SHUTDOWNCMD", "/sbin/shutdown -h +0") # save config a.save() a.close()