Mount Linux Olympus - Plugin HOWTO

Aaron Seigo <aseigo@mountlinux.com>

2000-10-4 v1.1


This document describes how to create a plugin for the Olympus open source administration system sponsered by Mount Linux.

1. Getting Started

2. Understanding the Olympus Framework

3. The Plugin Superclass

4. Netmessages and the Network

5. The Remote File Interface (RFI)

6. CommandXML

7. Creating the GUI

8. Licensing and the Official Olympus Distribution


1. Getting Started

The goal of this HOWTO is to provide comprehensive documentation of the plugin API provided by the Olympus client as well as to help plugin designers create consistent plugins that take full advantage of the Olympus system.

It is recommended that all plugin developers:


This will hopefully help avoid wasted and/or duplicated efforts.

There is a template plugin that can be used as a reference as well as a starting point included in the Olympus source distribution. This template can be found in:

olympus/docs/templates/plugins/

2. Understanding the Olympus Framework

It helps to understand the larger framework of a system when writing components for it. In this section we look at the design of Olympus in "broad strokes". Further information can be found in the docs/ directory of the Olympus source distribution.

Olympus is a client/server administration system. The server executes the requests of the client. The client collects information from the server as to the state of the machine and from the user as to what they want to do. These two pieces of software comunicate with each other via a network protocol called netmessage.

This division between client and server is extremely important for three reasons:

  1. It allows one client to manage large numbers of machines remotely or localy
  2. It enables enforcement of policy and security on the server side
  3. It creates a layer of abstraction between the actual system and the user interface

Due to this design, a single interface can (in theory) be used to command any number of machines running any of the various flavours of Linux/BSD/Unix from any workstation that runs a graphical environment supported by Qt (which is just about everything except MacOS/BeOS*) without having having to worry about security, communication, system specific details, etc.

The client itself takes care of all the details of the network, encryption and host management. It also launches the individual plugins as needed.

The server maintains a database of the locations of various executables and configuration files, Olympus user accounts and permissions and records of administration activity. In future it will also contain information as directed on other machines running the Olympus server sotware. Paths (and detalis on using) executables and configuration files are keyed in the database according to function. In concert with the Remote File Interface and CommandXML, plugins can use this as a mechanism for executing commands and modifying config files in a platform independant way without losing much (if anything) in the way of system specifics.

The plugins interact with the client and server via a set of four APIs in the client, each of which is covered in detail in the following sections. These APIs cover interaction with the client (plugin superclass), server requests (netmessage), configuration files (remote file interface), and command execution (commandXML).

* MacOSX/BeOS have X11 environments available so a port of QT to these environments should be possible at some point.

3. The Plugin Superclass and Conventions

The plugin superclass is inherited by all plugins (surprise!). It allows the plugin to be loaded by client at run-time as well as providing an API to various client resources such as the network and the plugin registry.


3.1 Naming and Registering the plugin

The first step in making a plugin is creating a subclass of plugin and including plugin.h. All subclasses of plugin have as their class name

mod_<SOMETHING>

This prevents name collisions with other parts of the client. For example, there is a mod_admin, a mod_log, and a mod_sysinit.

The shared library that the plugin is compiled into is required to be named

mod_<SOMETHING>.so

Therefore, there is a mod_admin, a mod_log, and a mod_sysinit. Each shared library should contain exactly one plugin subclass and its support classes. (Note: On Win32, the plugin libraries will end in .dll rather than .so.)

Within the header file, the plugin needs to register itself and implement all required virtual methods of the plugin superclass.

To be loadable, a plugin must implement one external function to provide the hooks the client requires. This is as simple as including the following in the main source file of the plugins (preferable mod_<SOMETHING>):

extern "C" { plugin* launchPlugin() { return new mod_<SOMETHING>; } }


3.2 Virtual methods

All plugin subclasses must reimplement eight virtual methods. These methods can be broken out into two different categories: identifcation methods and functional methods.

The identification methods allows the client to peer inside the class and relay vital information to other components and the user. These methods include:

virtual const char *name()
virtual const char *group()
virtual const char *desc()
virtual const char *credits()
virtual const char *version()

All of the above methods return const char *s.

The functional methods are a bit more involved and critical to proper operation. The first of these methods is:

exec(hostObj *_host, unsigned int _moduleID, moduleList *_modItem)

This method is called whenever the plugin is to be launched, usually as a result of the user double-clicking on its icon. Of the three parameters passed to exec(...), only _moduleID is of long term importance to the plugin as it is passed to every
netmessage created. The other two items are needed by the client for various bookkeeping and API reasons. In fact, the first line of the exec(...) method should be:

init(_host, _moduleID, _modItem);

This will put all the mechanisms in place that are required by the client for a properly behaving plugin.

When a netmessage is received from the host for an instance of a plugin, it is passed to the plugin through:

virtual void recv(netmessage* message, int objectID);

The objectID maps to one of the numerical IDs found in

olympus/src/common/include/commid.h

which is #include in plugin.h. It is possible to tell exactly what type of netmessage was received. Also note that once a netmessage is passed to the plugin, the plugin "owns" it and is responsible for its deletion.

The getFocus() method is called whenever the plugin needs to step to the front and grab the GUI focus. This is a simple yet important thing to take care of so that the plugin is easily findable when open.

In addition to the five informative and three funcational methods, there are three other virtual methods that may be overloaded if desired. These optional methods are:

virtual void connected();
virtual void disconnected();
virtual void messageSent(uint16 messageID, uint16 statusCode, int percentDone);

The first two methods are called whenever the network connection to the host is made or broken (respectively). messageSent(...) is called whenver a netmessage is sent. Included in its parameters is the ID of the message sent, the statusCode returned from the netmessage and a report on how much of the message has been sent.


3.3 Client Interface

The plugin superclass also contains an API for plugins to access the network, get host information, store persistent information and launch other plugins. (Future embelishments will include easy access to a help browser system and more robust inter-plugin communication). Each of these methods along with a description of their purpose is found below:



4. Netmessages and Plugins

All communications between the Olympus client and server are done via netmessages. All netmessages are subclasses of the netmessage superclass. This superclass takes care of serializing and deserializing objects, sending them across the network and keeping record of how things are going. Each subclass of netmessage does one specific (although usually fairly broad) thing such as execute programs, get listings of files, fetch files, etc.

Each netmessage takes a transport object which takes care of the low level network activity and can be retreived via plugin::rawSocket(), the moduleID of the plugin which acts as a return address on the message and an object ID. Each netmessage has a unique object ID as defined in:

olympus/src/common/include/commid.h

When created, each netmessage is stamped with a message identification number. This gives each netmessage a four part fingerprint that is used to route the message: host, object ID, module ID, and message ID.

To send a netmessage to the server a plugin needs only to call uint32 plugin::queueMessage(netmessage*) which takes care of all network details from there, including:

ququMessage(...) returns the ID number that has been assigned to that message. Each ID is guarenteed to be unique (even in the case of a roll-over due to exhausting all four billion plus available IDs). All replies to this netmessage will have this same messageID. Therefore, to track which reply belongs to which message sent all a plugin has to do is keep track of these messageIDs.

Replies are routed to the plugin by means of the pure virtual plugin::recv(netessage *message, int objectID). Once handed off to the plugin, the netmessage is now owned by the plugin which must take care of deleting it when finished with it.

For information on the specific netmessages and further details on the inner working of the entire protocol, refer to the netmessage documentation found in the olympus/docs/ directory.


5. The Remote File Interface (RFI)

The Remote File Interface, or RFI, is an extremely powerful mechanism to manipulate remote configuration files programatically. An RFI object takes the name of a .rif file, fetches the appropriate remote file, parses it, allows editing, and (if instructed to) puts the file back together again and commits it to the remote machine (with backup for rollback capabilities).

.rfi files are an XML implementation designed specifically for describing data structures in text configuration files (yes, those files we have come to know and love in the Linux/UNIX world). The remote file is defined in a platform independant manner in this file, though this can be over-ridden at run-time.

Once retrieved and parsed, the file can be treated as a data structure in memory complete with [] and = operators. Some of the important features of RFI are:

  • Respects data in the file it doesn't understand and preserves it by marking it as unparsable data.
  • Knows about line and block comments and respects these too.
  • Can handle arbitrarily complex (nested and variable) data "types" as defined in the .rfi file.
  • Lots of sanity checking for things such as multiple matches when there should only be a single value
  • Can be reset to original state after undesired editing
  • Output file maintains order of items in file unless specifically re-orderred by the plugin. This includes unparsed and comment data.
  • Plugins have access to all .rfi files, so any plugin can parse any system file for which one is defined

For more detailed information on using the RFI and writing .rfi files, refer to the RFI documentation found in the olympus/docs/ directory.


6. CommandXML

CommandXML is a concept that will allow platform independant complex comand execution. CommandXML is only a fig-newton of our fertile imaginations. The design of this technology is pretty well done. Wait a week or two and the code should be ready as well.


7. Creating the GUI

Graphical interface standards are still being formed and decided upon. For now, use common sense and make something pretty, easy to master, powerful and fun. You know, just simply whip up a power-interface. Seriously though, more concepts for standard methods of doing things will find themselves appearing here over the next few months.


8. Licensing and the Official Olympus Distribution

The Olympus client and server are released under the GNU GPL version 2 as included with the official Olympus source distribution. The only exception to this is the header for the plugin superclass, which is found at

olympus/src/client/include/plugin.h

within the Olympus source distribution. This file is dual licensed under the GPL and a BSD-style license (minus advertising clauses). The reason for this is to allow the creation of plugins for the Olympus system that are not licensed under the GNU GPL.

The Mount Linux Olympus development team feels that while the GPL is the optimal license for the Olympus system itself, that due to the opinions and/or needs of plugin authors the GPL may either be undesirable or unworkable. Therefore a plugin may be licensed as the author sees fit. This includes closed source plugins, plugins under Artistic or BSD style licenses, etc.

However, only plugins copyrighted under a license that is compliant with the Debian Free Software Guidelines will be considered for inclusion within the official Olympus distribution.