This chapter will describe the backend architecture (principles and implementation) as well as its usage.
Architecture wise, you've got:
A data-access component: the 'config-wrapper', which manages the configuration file by means of a simple transaction system, and generates events (calls the system configuration component, passing names of modified variables).
A system configuration component: the 'event-handler', which receives events and triggers corresponding actions to update the system and keep it in a coherent state. Actions take the form of templates processing (replacing system files with up-to-date content), scripts, and services management.
For the sake of simplicity, the backend uses a central ASCII configuration file, storing variable-value pairs (like DomainName=mydomain.com). Hence it's both human readable and easy to use for templates processing.
There are two kinds of variables: standard variables (also called normal or static variables) that store a value that you can get or change (set); and proxy variables (also called virtual or dynamic variables), that don't store a value but instead execute a script when they're accessed.
For instance, Eth0IP is a standard variable. It is stored in the configuration file like this: Eth0IP=192.168.1.1. You can get its value (you'll get 192.168.1.1) or set a new value.
EthernetInterfacesList, on the other hand, is a proxy variable. In the configuration file you can read: EthernetInterfacesList='get: interfaces.pl net;'. It means that when you try to get the value of the EthernetInterfacesList variable, the script interfaces.pl wil be executed with 'net' as a parameter, and in return you'll receive the list of detected Ethernet cards. These kinds of variables can have both a get and set methods at the same time, triggering scripts for each method (it can be different scripts or the same script with different arguments). There's a slight difference between the get and set methods, as the get action will execute the script immediately, while the set action will execute the script only at commit time (see below about transactions).
Transactions are a means of keeping the system coherent. That means not applying modifications to the system each time a single parameter is modified, but instead repercuting several modifications at once in a coherent way, and only when the user is sure a particular set of related parameters have the correct values. It also prevents conflicting modifications to the system parameters from happening at the same time, leading to an unpredictable results.
Each time you want to access and modify data you have to initialize a transaction. All further data manipulations will happen in the context of this particular transaction, and will only lead to effective system modifications when the transaction is committed.
The way it is implemented is actually quite simple. When you initialize a transaction, two copies of the configuration file are made : a backup copy and a working copy. Both copies are dedicated to a particular transaction. The working copy is the one where all modifications take place; these modifications won't be taken into account to update the system until the transaction is commited (that is, the "master" configuration file is modified at once and only with a commit operation). The backup copy is left untouched during the whole transaction, and is used at commit time to check if any other transaction had been committed while working in this particular transaction (i.e. it will check if the "master" configuration file has been modified before committing the current transaction).
Events generation is also a very simple process. When a transaction is committed, the config-wrapper (the data-access component) isolates the variables that have been modified.
The names of these variables are the actual events. These names are passed to the event-handler at once to trigger appropriate actions and thus update the system.
Events are managed by the "event-handler". When it receives a list of events (a list of names of variables that have just changed because of a transaction commit), what it does is simply to parse the /usr/share/naat/events/ subdirectories. These folders all have the same layout : /usr/share/naat/events/[event-name]/{pre,main,post}.
In each event-name folder are three subfolders named pre, main and post, which are the three steps of actions to be taken, in that order. In each step we find several hints, i.e. 0-length files whose name indicates both the type of action : template, script or service; and the precise name of the action (the name of the template, script or service). For instance, the hint for a template of /etc/sysconfig/network, triggered by the DomainName event (among others), is /usr/share/naat/events/DomainName/main/template--etc--sysconfig--network. That means that whenever the DomainName system parameter is modified (as a consequence of a committed transaction), the 'network' template (found in /usr/share/naat/templates/etc/sysconfig) will have to be processed to replate the system file /etc/sysconfig/network with up-to-date content. See next section for more details about actions.
The role of the event-handler is to list all these actions, correponding to the events received, to order them and assert their unicity in each step (that is, do not perform the same action twice in a particular pre, main or post step). It then processes these actions.
The events folders and actions hints are generated by a script called events.sh.
As said previously, actions to perform on account of events are defined by hints. There are three types of actions (template processing, script execution and services management), but you can start, stop, restart or reload services, so there are six types of hints: template--*, script--*, start--*, restart--*, reload--* and stop--*. These hints can be in any of the pre, main and post subfolders of all event-names folders.
Pre (1) actions are applied before main (2) actions, and post (3) actions occur last. In each step, order of actions is as follows: templates (A), scripts (B) and services (C). Services are first stopped (C.a), reloaded (C.b), restarted (C.c) and started (C.d), and if a same action concerns several services in the same step, order of priority in the current runlevel is taken.
So the final order is : 1.A 1.B 1.C.a 1.C.b 1.C.c 1.C.d 2.A 2.B 2.C.a and so on..., and in each of these, actions are performed only once.
Templates are in subfolders of /usr/share/naat/templates which match the actual place of the corresponding system file. For instance /usr/share/naat/templates/etc/sysconfig/network for the template of /etc/sysconfig/network. The corresponding hint is template--etc--sysconfig--network.
Scripts are in /usr/share/naat/scripts, and are given root priviledge when launched with sudo by a user of the admin group.
Services hints look like restart--network, which will restart the "network" service.