COAS: A Flexible Approach to System Administration Tools

Caldera is working on a new easy-to-use configuration tool for Linux. Mr. Kirch gives us the details.
Data Model

Let's take a closer look at the internal data representation. All information is stored in a tree, with each node having an individual name. For instance, the node containing the password of the root user is named system.accounts.users.0.password. If you're familiar with SNMP, think of the way SNMP variables are named.

Nodes can have different types; e.g., system is a directory, users is a list and password is a scalar. Scalar nodes can have various constraints attached to them; for instance, a string may be required to match a regular expression or contain only values from a predefined set of choices. You can also attach your own parsing and representation functions (written in C) to a scalar type, creating custom types that do such things as convert date strings, e.g., Jun 12 or tomorrow, to UNIX time.

All this information is provided by the so-called schema. The schema acts as a sort of blueprint for the data model in much the same way an SNMP MIB definition describes the types and organization of entities for SNMP.

For instance, the definition of the mouse parameters might look like this:

MSGCATALOG "peripherals/mouse"
    "Busmouse", "MouseSystems",
    "Mouseman", "Microsoft",
device         RECORD {
    model      STRING
    protocol    MouseProtocol
    deviceFile   DevicePathName DEFAULT
    emulate3btn   BOOLEAN DEFAULT "false"

This creates a record named mouse containing five scalar nodes. For instance, model is a plain string variable, while deviceFile is a special string type whose definition is shown above the record. The first two lines contain some syntactic sugar that need not concern us at the moment.

%Those funky strings (|":MOUSE_EMULATE_NONE:"|)
%are tags for the COAS message catalogs.
This definition would be stored in a file named peripherals/mouse.schema (usually below /usr/lib/coas/schema) so that the mouse configuration would be accessible by the name peripherals.mouse.device.

When accessing data items, COAS instantiates the portions of the instance tree from the schema definition and populates the data by invoking so-called “mappers”. These mappers are responsible for parsing and writing back system files, locking them if necessary. Usually, they are written in C++ and kept in shared libraries loaded on demand. The most recent release also supports mappers written in Python.

In the case of the mouse device, there is no standard location where this information is stored. On a Red Hat box, for example, it is kept in /etc/sysconfig/mouse, a file which contains a list of shell variable assignments. COAS already has a general-purpose mapper for this type of file (it turns out that about 80% of all system files are quite close to four or five standard formats), so all that is left is defining the mapping. This is done by the so-called platform repository, where we might enter code like this:

peripherals.mouse.device {
    mapper     builtin.sysconfig
    path      /etc/sysconfig/mouse
    relation    MOUSETYPE:model:\

The mapper keyword associates the mapper specified with the mouse device node. When accessing the device node, the first time, COAS detects this and invokes the mapper in order to populate the tree below the mouse device node. The mapper retrieves the path parameter and reads the file specified. The relation parameter tells the mapper which shell variables within the file correspond to which data model nodes.

The same thing happens when you have modified a protocol (e.g., the mouse) and invoke the device node's commit function. The data engine will invoke the mapper in order to write the data back to the file. Again, the mapper will use the specified relation to determine which data model values will be assigned to which shell variables. Note that in an act of vi-administrator friendliness, the mapper does not touch shell variables it does not know about and tries to preserve comments as well as it can.

The platform information is usually installed by merging it with the main COAS platform definition, which resides in /usr/lib/coas/repository.

User Interaction

Having written and installed the above files, you can already display and modify the mouse configuration using COAS. For example, COAS comes with small utilities such as coas dump and coas change that let you dump portions of the data tree or modify individual nodes. You can even write Python scripts that perform more complex operations on your data.

However, the ultimate goal (at least for us) is a Python module that interacts with the user, guiding him through the administration task. The module sits on top of the database engine and operates exclusively on the abstract data representation. It displays data to the user, selects which items are to be edited, provides on-line help, etc.

Why Python? Well, a very early prototype used Tcl as the scripting language, but for various reasons it didn't work too well. In contrast to Tcl, Python has fairly good object support and at least as good an extension mechanism. The other candidate was Perl, but we decided against it because it is so easy to write horrible code in Perl.

Communication with the user happens via an abstract user interface API written in C++, which currently supports a curses and a Qt front-end. Work on an extended Qt front-end that takes advantage of features provided by KDE is in progress. Of course, in order to be able to use this API from Python, a Python wrapper is provided.

The user interface provides a limited but useful set of dialogs: notice/question dialogs consisting of a text and a few buttons; list dialogs (single- and multi-selection, with or without check boxes, etc); prompt dialogs (containing edit fields for one or more scalar values); and table dialogs (which display data in a table, allowing in-place editing).

Listing 1

For instance, a minimal module for editing the mouse configuration would look like Listing 1 (some of the Python fluff, such as import statements, is not shown). For those not familiar with Python, this code defines the class Mouse, derived from the CLAM class defined in module clam. The {__init__} method is Python's way of declaring a constructor.

The method run is invoked by COAS. The first thing it does is look up the data model node for the mouse device. As described above, this step will trigger the parsing of the configuration file into the internal data representation.

Next, a prompt dialog is created and three edit fields are added for the mouse's model, protocol and device file. The last few lines are the somewhat standard dialog loop. Depending on whether the user terminates the dialog by pressing the Okay or Cancel button, either the commit or cancel method (inherited from the CLAM base class) is invoked, which displays a small question dialog along the lines of “Do you really want to save/cancel?”