home *** CD-ROM | disk | FTP | other *** search
-
- <!doctype linuxdoc system>
-
- <article>
-
- <!-- Title Information -->
-
- <title>Comanche Programmers Guide
- <author>Daniel Lopez Ridruejo, <tt/ridruejo@apache.org/
- <date>v0.15, 30 November1999
-
- <!-- Abstract -->
- <abstract>
- This paper is a work in progress that documents Comanche internals and the
- design philosophy behind it. It will help you get started if you want to
- write your own plugins or want to help develop the existing ones.
- </abstract>
-
- <!-- Table of Contents -->
- <toc>
-
-
- <sect> Introduction
-
- <p>
- The main issue that Comanche wants to address was the lack of appropriate
- management tools for popular internet software. The Apache web server and
- derivatives runs on more than 60% of all internet servers (acording to <url
- name="Netcraft" url="http://www.netcraft.com/survey">). Sendmail runs in
- approximately 75% of all mail servers on the internet (<url name="Sendmail
- website" url="http://www.sendmail.org">). (<url name="Bind"
- url="http://www.isc.org"> has a virtual monopoly for internet DNS servers.
- Big organizations running SMB networks (windows file and printer services
- protocol) often turn to a Unix Operating System running <url name="Samba"
- url="http://www.samba.org"> for their mission critical file servers..
- <p>
- These programs are free. Their source code is available for inspection and
- customization. However, although they are often technically superior to
- their commercial counterparts, they usually lack good management software.
- This steep learning curve often hinders their adoption both by the casual
- user and large corporations who want to keep down their administrative costs.
- <p>
- The purpose of this project is to implement a management system, code named
- Comanche, geared toward improving the usability and widespread adoption of
- Internet related Open Source software.
- <p>
- Design goals:
- <p>
- <itemize>
- <item>Avoid focusing on a single product. Create a framework for easily
- developing management programs
- <item>Provide the ability to easily develop simple modules yet still make it
- possible to architect complicated ones.
- <item>Build an intuitive GUI to hide complex tasks from casual users while
- providing full flexibility to advanced users.
- <item>Enable remote administration
- <item>Possibility to extend the framework in arbitrary programming languages
- <item>Support localization of both Help files and interface
- </itemize>
- The following sections give an overview of the architecture of Comanche.
- Later on we introduce XML usage in Comanche and we conclude with a step by
- step implementation of a simple module.
-
- <sect1> Design principles
- <p>
- After downloading, compiling and using many configuration programs and
- management frameworks, it was felt that there was room for improvement, and
- thus the idea of writing Comanche was born. Some of the key points that
- motivated that decision follow. To describe them, some thoughts are borrowed
- from the author of <url name="Perl" url="http://www.perl.org">, <url
- name="Larry Wall" url="http://kiev.wall.org/~larry/">.
- <p>
- <sect2>"Easy things should be easy and hard thing should be possible"
- <p>
- Comanche, as any other open source project can benefit greatly if other
- people were able to contribute to it. The idea is to develop a framework that
- encourages other programmers to contribute. Successful open
- source projects have a modular architecture. To become productive, a
- developer only has to deal with the module API and a few concepts of the
- overall architecture. The learning curve is much higher for one piece
- monolithic programs.
- <p>
- Existing frameworks usually aim to be comprehensive solutions, providing
- special functions for registring and accessing configuration files,
- starting/stopping programs, etc. This increases the amount of knowledge
- required to build even the simplest of the modules. One of the goals of
- Comanche is to make it easy to develop plug-ins. The API should be kept
- simple. A developer should be able to write a simple module for Comanche in
- a very short amount of time, without precluding the development of more
- complex modules.
- <p>
- <sect2>"There's more than one way to do it"
- <p>
- Some of the existing frameworks restrict the developer to the use of only
- certain extension languages, like C++ or Java. The design of the framework
- should not restrict the developer to the use of only certain languages.
-
- <sect2>"Laziness is one of the virtues of a good programmer"
- <p>
- Configuring complex programs can be a daunting task. Hard-coded interfaces
- make painful to maintain the program when new versions of the application
- are released and that requires changes to the syntax of directives, redesign
- of existing dialogs or creation of new ones. Usually all this requires changing
- the source code and recompiling with existing frameworks. It will be
- desirable to clearly separate the interface and directive description from
- the configurated engine itself, so interfaces can be generated dynamically.
- <p>
- <sect2>"Many acceptable levels of competence"
- <p>
- If this separation of content from presentation can be achieved, then it
- would be possible to maintain different versions of the interface.
- New users would be presented with the minimum set of information required to
- configure the program, while experts would be presented with an advanced
- view, that exposes the more obscure details.
-
- <sect2>"There are probably better ways to do that, but it would make the parser
- more complex. I do, occasionally, struggle feebly against complexity..."
- <p>
- The design of the program should be kept as simple as possible while
- covering the most common cases and uses. This may involve some functionality
- tradeoff.
-
- <sect2>"Historically speaking, the presence of wheels in Unix has never
- precluded their reinvention."
- <p>
- In this case it is believed that it will be a better, faster, rounder wheel.
-
- <p>
- Now that it has been stated what the ideal configuration framework, it
- should be analyzed which problem it should/would solve for different target
- groups:
-
- <sect2>End users
- <p>
- It should help them set up and manage popular open source applications like
- Apache and Samba. It should make the process easy by hiding the complexity and
- guiding them through the different options using wizards. When they feel
- confident, they should be able to switch to expert mode and be able to
- configure the more obscure parameters.
-
- <sect2>Experienced administrators
- <p>
- Usually experienced administrators set up an infrastructure to automate
- repetitive tasks (like adding users, creating mail aliases, etc.). This is
- usually accomplished using Perl or shell scripts. This kind of
- infrastructure is often poorly documented and the know-how is difficult to
- transmit. Comanche can make it really easy to create administration scripts and
- provide a graphical interface to them that can be then used by junior
- administrators.
-
- <sect2>Developers
- <p>
- It should help them providing a simple API, so they can concentrate on their
- original purpose: configure the application. The framework should take care
- of presenting an unified interface and interacting with the user.
-
-
-
- <sect> Architecture
-
-
- This section is an introduction to the Comanche architecture.
- <p>
- Comanche is designed around a modular architecture and has the following
- characteristics:
- <p>
- Even the most complex configuration programs can be reduced to follow these
- principles:
- <itemize>
- <item>Present information to the user and ask him for input.
- <item>Receive input from the user.
- <item>Act upon that input.
- </itemize>
- <p>
- <img src="images/dia-1.gif">
- <p>
- Comanche takes care of the first two items and leaves the
- third to the module author. It can optionally provide libraries to help
- with this step, but it gives him absolute freedom. The module author, not
- the framework is who knows better how to parse configuration files or take
- certain actions (like execute a external program or check environment
- variables). As stated before, the goal is to provide as much freedom
- as possible to the module authors and present them with a small,
- simple API.
- <p>
- To present information to the user, instead of having to hard-code
- interface and dialogs in the program itself, they are described in a mark up
- language based on <url name="XML" url="http://www.w3.org/xml"> (XML is a
- mark up language to represent structured data).
- The interface can be easily manipulated or even generated on the fly. The
- XML representation is platform independent, it can be rendered using a
- traditional UI toolkit or in a web based interface.
-
- <sect1>Simple API for developers
- <p> A lot of time was spent in designing a simple API. The plug-in or
- management module has to know how to:
- <itemize>
- <item> Deliver the XML description of the configuration options. This
- information will be rendered and presented to the user, who will manipulate
- it.
- <item> Receive the results from the user (also encoded in XML format).
- <item> Extract the results and act upon them.
- </itemize>
- <p>
- This can be reduced to the following APIs calls:
- <itemize>
- <item>RequestDocument
- <item>ReceiveDocument
- </itemize>
- <p> There are some others API calls for initializing the plugIn, etc. but
- these two are the main ones. The dialogs, if fixed, can be stored in text
- files or alternatively can be generated on the fly. In a way the plug-in
- acts like a traditional cgi-bin application. But instead of generating HTML
- , it generates user interface data encoded in XML, and instead of accepting
- form variables, it accepts XML encoded data.
-
- <sect1>Support for multiple extension languages
- <p>
- Comanche is developed mainly in Tcl, but that does not preclude future use of
- other languages for building extension modules (plugins). Since the
- interface is well defined, small and-text based it is possible to
- encapsulate the protocol into HTTP or <url name="Fast cgi"
- url="http://www.fastcgi.com">. Most programming languages support these
- interfaces, including Tcl, Perl, Java, Python, C, C++, etc.
- This is still not implemented, but the basics are there.
-
- <sect1>Easy addition and maintenance of configuration files
- <p>
- XML is not only used for exchange of information. It is also used for
- describing the interfaces and the configuration directives. Since XML is
- a text based language, it is easy to change the definition of directives or
- rearrange user interfaces without need to recompile.
-
- <sect1> Easy maintenance of different interfaces (and languages)
- <p>
- Since the information can be separated from the presentation it is
- possible to maintain several versions of the interface, based on the mother
- tongue and/or skill level of the end user.
-
- <p>
- The architecture of Comanche gravitates around three blocks:
- <itemize>
- <item> Namespace. Can be thought of as a hierarchical database or a directory
- server.
- <item> Plugins. They provide the configuration functionality. They register
- themselves with the namespace, and populate it creating nodes.
- <item> The console. It is the graphical tool used by the user to connect to
- the different namespaces (represented by computer icons in the tree)
- </itemize>
- <p>
- These elements are usually part of the same program, but the system has been
- designed such it should be relatively easy to have them running in separate
- machines or processes. They could be tied together using simple protocols
- like HTTP + SSL, thus someone running a console in one machine can
- securely administer remote boxes. The protocol is designed to work well over
- moderately slow links. Alternatively, the console instead of being a
- traditional application can be a web server module that renders the
- interface and interacts with the user. All of this is transparent to the
- module developer, which still sees the same simple interface described above.
- <p>
-
- <sect2>Namespace
- <p>
- The namespace is the "central switch" of the
- Comanche architecture. It acts as a broker between the plugins and the
- console. It helps organize information about the plug-ins in a hierarchical
- manner, and to arbitrate communication between users and plugins (so an
- user can configure several plugins at the same time or several users
- can communicate with one plug in simultaneously). plugins register with the
- namespace and they create new nodes under existing categories (like network
- services or system).
- <p>
- Plugins can also extend other plugins. To do so, plugins inform the
- namespace which nodes they are interested in. For example, there may be a
- need to add SSL (Secure Sockets Layer, necessary for secure communications
- between the browser and the server) configuration
- support to Apache. Instead of rewriting the existing Apache plug in, an
- extension SSL plugin is created. It tells the namespace its interest in all
- nodes created by Apache. Whenever the namespace receives a request for the
- property pages for a given node, the SSL plugin is also given an opportunity
- to contribute to the answer, so it can add new property pages. In case the
- SSL module is not installed or enabled, no new pages appear.
-
- <sect2>Console
- <p>
- The console is the end user interface. The console UI is divided in several
- areas, the main two are:
- <itemize>
- <item><bf>A tree structure on the left</bf>.
- It allows the user to connect to the different managed machines, and
- navigate them by clicking and expanding nodes
- <item><bf>A right pane</bf>.
- It visualizes information related to the currently selected node.
- </itemize>
- <p>
- The user navigates the tree on the left and configures the properties of the
- nodes by right-clicking on them and selecting the properties entry in the
- pop-up menu.
- <p>
- <img src="images/ug-console-general.gif" >
-
- <sect2>Plugins
- <p>
- Plugins are modules that implement the specific management behaviour. They
- are the ones that populate the namespace that is browsed by the console.
- They produce the content of the property pages that are delivered to the
- user and they act upon the received changes.
-
- <p><img src="images/dia-2.gif">
-
- <sect> XML based configuration
- <p>
- This section explains introduces a configuration language based in XML.
- Traditionally different applications have stored their configuration
- settings in a variety of formats ranging from databases to text files, from
- the Windows registry to directory services like LDAP.
- <p>
- The most common configuration format employed by Unix applications is plain
- text files. The exact syntax employed inside the text file varies greatly
- from application to application: Samba uses a simple pair key/value Windows
- .INI format, Apache allows sections and nested subsections,
- Bind also structures information with sections delimited by curly braces, etc.
- There are advantages/disadvantages of having a text based configuration as
- opossed to a GUI, such as easy automation with scripts, remote
- administration, etc.
- <p>
- A XML based configuration language was designed with the following goals:
- <itemize>
- <item><bf>Simple</bf>. An human should be able to read, modify or write from
- scratch the XML documents. Parsers for the configuration parser should be
- easy to write.
- <item><bf>Universal</bf>. The language should be general enough that it can
- be applied to describe the configuration settings of a variety of programs.
- <item><bf>Extensible</bf>. The language should admit easy generation of new
- configuration parameters.
- <item><bf>Multilingual</bf>. It should be possible to localize (translate) the
- information about the directives, help text, etc
- <item><bf>Comprehensive</bf>. By combining simple basic blocks it is
- possible to describe complex configuration directives.
- <item><bf>Verbose</bf>. The description of the directive should include
- information about the class of the directive (string, number, ...), range of
- values accepted, etc. This metadata helps the user interface and the parser
- when validating or displaying the data.
- </itemize>
- <p>
- The XML configuration language is built on top of basic building blocks.
- These blocks represent parameters from a semantic point of view, for what
- they mean, not how they are represented. That is, if there is a directive
- "userName" that can accept the name of a person as its value, the directive is
- thought as being a directive of class string rather than thinking about the
- directive in terms of how would it be represented in a GUI (in an entry
- form). This decoupling between the meaning of the directive and the
- user interface representation is of great importance as it will become clear
- in the section about XML User Interface.
- <p>
- The current basic blocks are the following:
- <itemize>
- <item>string
- <item>number
- <item>boolean
- <item>choice
- <item>label
- <item>structure
- <item>list
- <item>alternate
- </itemize>
-
- To understand the following sections, it is important that there are two
- components to consider:
- <itemize>
- <item>Configuration file: This is the actual configuration information of the
- program being manipulated. If it is a mail server it will have mail aliases,
- mailing list information, etc.
- <item>Directive description: This describes what the tags found in the
- configuration file actually mean and how they can be nested, etc. If it is
- the mail server mentioned above, it will explain how the mail aliases are
- described or how to store the members of the mailing lists.
- </itemize>
-
- A simple XML configuration file of a fictitious server could be:
- <p>
- <verb>
- <server>
- <name>Mike's server&etago;name>
- <ipAddress>10.0.0.1&etago;ipAddress>
- <port>80&etago;port>
- &etago;server>
- </verb>
- <p>
- But how it is possible to know, when a server tag is found, which
- elements are allowed inside, and which are the ranges of accepted values? We
- need a configuration directives metalanguage. The server directive could be
- described as follows:
- <verb>
- <structure name="server" label="Server">
- &etago;syntax>
- <string name="name" label="Server Name"/>
- <string name="ipAddress" label="IP address"/>
- <number name="Port" label="Port"/>
- &etago;syntax>
- &etago;structure>
- </verb>
- <p>
- The syntax above will be explained in the following sections. It is important
- to note that although
- the XML standard has a similar mechanism for defining the structure of a
- document, called DTDs (Document Type Definitions) they are not suitable for
- this purpose. If only because DTDs define the structure of a document (which
- tag can appear where) but do not offer any information about the data hold
- by those elements. Other XML standards, like XML Schemas aim to solve this
- problem, but they were only early drafts at the time Comanche was written.
- As the standards mature a move to them will be considered.
-
- <sect1>String
- <p>
- A string element represents text values and has the following XML
- definition.
- <p>
- <verb>
- <string name="stringName" label="This briefly describes the directive">
- <default>Some default value&etago;default>
- &etago;string>
- </verb>
- <p>
- This directive will be represented in the XML configuration file as:
- <verb>
- <stringName>This is some value&etago;stringName>
- </verb>
- <p>
- If the directive stringName does not appear in the configuration file, it
- will be assumed to have the value "Some default value".
- <p>
- The default value and tags are optional.
- A graphical representation could be the following:
- <p><img src="images/guistring.gif">
- <sect1>Number
- <p>
- A number elemenet represents numbers and has the following XML definition.
- <p>
- <verb>
- <number name="numberName" label="This briefly describes the directive">
- <default>123456&etago;default>
- &etago;number>
- </verb>
- <p>
- This directive will be represented in the XML configuration file as:
- <verb>
- <numberName>123456&etago;numberName>
- </verb>
- <p>
- If the directive numberName does not appear in the configuration file, it
- will be assumed to have the value "123456".
- <p>
- The default value and tags are optional
- A graphical representation could be the following:
- <p><img src="images/guinumber.gif">
- <sect1>Boolean
- <p>
- A boolean element can only hold two values, true or false.
- <p>
- <verb>
- <boolean name="booleanName" label="Boolean label">
- <default>1&etago;default>
- &etago;boolean>
- </verb>
- <p>
- In the XML configuration, it will appear the following
- <p>
- <verb>
- <booleanName>1&etago;booleanName>
- </verb>
- A graphical representation could be the following:
- <p><img src="images/guiboolean.gif">
- <sect1>Choice
- <p>
- The values can be one of a collection of fixed ones
- <verb>
- <choice name="choiceName" label="Choose a fruit">
- <syntax>
- <option name="orange" value="Juicy orange" />
- <option name="lemon" value="Acid lemon" />
- &etago;syntax>
- <default>orange&etago;default>
- &etago;choice>
- </verb>
- <p>
- This directive will be represented in the configuration file as:
- <verb>
- <choiceName>lemon&etago;choiceName>
- </verb>
- <p>
- If the directive choiceName does not appear in the configuration file, it
- will be assumed to have the value "orange".
- <p>
- The default value and tags are optional
- A graphical representation could be the following:
- <p><img src="images/guichoice.gif">
- <sect1>Label
- <p>
- This element represents a fixed value. It will be used in other composite
- elements.
- <verb>
- <label name="labelName" label="This is the value of the label" >
- &etago;label>
- </verb>
- <p>
- The directive will be represented as:
- <p>
- <verb>
- <labelName>This is the value of the label&etago;labelName>
- </verb>
- A graphical representation could be the following:
- <p><img src="images/guilabel.gif">
-
- <sect1>Structure
-
- <p>
- This is an element that is a composite of others. The directive is composed
- of other directives. The general XMl description of the directive is as
- follows:
- <verb>
- <structure name="structureName" label="Description of the structure">
- <syntax>
- (... Here comes the XMl description of the structure
- components ..)
- &etago;syntax>
- &etago;structure>
- </verb>
- <p>
- This is better explained through an example. Let's assume a directive
- "person", which is composed of three other directives: a name (string), a
- surname (string) and an age (number)
- <p>
- The description would be:
- <verb>
- <structure name="person" label="Description of a person" >
- <syntax>
- <string name="name" label="Name" />
- <string name="surname" label="Family name" />
- <number name="age" label="Age">
- <default>21&etago;default>
- &etago;number>
- &etago;syntax>
- &etago;structure>
- </verb>
- <p>
- A representation of an instance of this directive in the configuration file
- would be:
- <verb>
- <person>
- <name>John&etago;name>
- <surname>Smith&etago;surname>
- <age>30&etago;age>
- &etago;person>
- </verb>
- <p>
- There is no default for the directive itself, but rather each one of the
- elements defines its own default.
- <p>
- A possible graphical representation:<p>
- <img src="images/guistructure.gif">
-
- <sect1>List
-
- <p>
- A list is a collection of elements of the same type. The list element definition
- (the part inside the syntax tags) can be itself be described in terms of other basic
- building blocks.
- <verb>
- <list name="listName" label="Comment about the list">
- <syntax>
- (... XML description of the list elements ...)
- &etago;syntax>
- <default> (... depends on the list element ...) &etago;default>
- &etago;list>
- </verb>
- <p>
- The following example illustrates the use of the list element:
- <verb>
- <list name="userNames" label="Names of users">
- <syntax>
- <string name="user" label="Name of the user" >
- <default>nobody&etago;default>
- &etago;string>
- &etago;syntax>
- <default>
- <item>dani&etago;item>
- <item>&etago;item>
- &etago;default>
- &etago;list>
- </verb>
-
- <p>
- An entry io the XML conf file that uses this list would be:
- <verb>
- <userNames>
- <user>user1&etago;user>
- <user>user2&etago;user>
- &etago;userNames>
- </verb>
-
- A possible graphical representation:<p>
- <img src="images/guilist1.gif">
- When the user adds an element:
- <p>
- <img src="images/guilist2.gif">
-
- <sect1>Alternate
- <p>
- This element is similar to the structure element, but in this case instead
- of being a collection of elements, it is one (and only one) of the elements.
- <verb>
- <alternate name="alternateName" label="some text describing the alternate" >
- <syntax>
- (... XML description of the possible elements ...)
- <syntax>
- <default>
- (... XML description of the element and value ...)
- &etago;default>
- &etago;alternate>
- </verb>
- As an example, the Apache bind directive is implementated as an alternate
- <verb>
- <alternate name="bindAddress" label="Address to bind the server" >
- <syntax>
- <label name="allAddresses" label="All available addresses" />
- <string name="specific" label="Specific address/domain-name" >
- &etago;string>
- &etago;syntax>
- <default><specific>127.0.0.1&etago;specific>&etago;default>
- &etago;alternate>
- </verb>
- <p>
- A possible graphical representation:
- <p><img src="images/guialternate.gif">
- <p>
- In the XML configuration file, a bindAddress directive would look like:
- <verb>
- <bindAddress>
- <specific>10.0.0.1&etago;specific>
- <bindAddress>
- </verb>
- <p>
- or if the web server is going to listen to all addresses available:
- <verb>
- <bindAddress>
- <allAddresses/>
- &etago;bindAddress>
- </verb>
- <p>
- These are the basic building blocks that, combined, can be used to create
- arbitrarily complex directives. Yet the rules are very simple.<p>
- These XML elements are manipulated in Tcl in a special way, that isolates
- the XML syntax details (that may change in the future) and allows similar
- elements to be accessed in a similar way (i.e reading a string or numeric
- value is done in a similar way)<p>
- The process is the following: a XML document containing the directives is
- parsed using a XML parser. This XML parser's callbacks are used to construct
- a Document Object Model representation of the XML document. A DOM
- representation of a XML document is a tree like structure of the document
- that can be accessed programtically. For example, the following XML document:
- <verb>
- <server>
- <name>Daniel&etago;name>
- <surname>Lopez&etago;surname>
- &etago;server>
- </verb>
- Its DOM
- representation would be:
- <verb>
- server (element)
- |
- |---name (element)
- | |
- | \_ text node (value="Daniel")
- |
- |---surname (element)
- |
- \_text node (value="Lopez")
- </verb>
-
- The DOM implementation allows navigation of the document. To get the value
- "Daniel" the steps are as follows:
- <itemize>
- <item> ╖ Ask for the first node. It returns as a reference to "server"
- <item> ╖ Ask for the children of "server", get a reference to "name"
- <item> ╖ Ask for the children of "name", get reference to the text node
- <item> ╖ Get the value of the text node: "Daniel"
- </itemize>
- Manipulating XML documents this way can be cumbersome. A new method was
- devised to transition from XML documents to a DOM tree and from a DOM tree
- to xuiObjects. What is a xuiObject? It stands for XML User Interface Object.
- It is a Tcl object that encapsulates the functionality of its corresponding
- XML element. After those objects are created, it is possible to manipulate
- them easily, combine them and serialize them back to XML.
- <p>
- That is, a xuiString encapsulates the functionality of a XML string
- element. This functionality can be accessed invoking different methods:
- <p>
- If the variable xuiStr contains the name of an object instance of a
- xuiString class it is possible to do the following in the Tcl programming
- language:
-
- <verb>
- $xuiStr getValue
- </verb>
- The previous Tcl code invokes the method getValue on the object referenced
- by the xuiStr variable. The result of the invocation will be the return of
- the value of the string. If the string was defined as:
- <verb>
- <someString>Some value<&etago;someString>
- </verb>
- And xuiStr contained a reference to an object that represents that
- someString XML code, getValue would return "Some value".<p>
- Similarly,
- <verb>
- $xuiStr setValue "Another value"
- </verb>
- Will set the new value for the string. If the object is serialized back to
- XML, the result would be:
- <verb>
- <someString>Another value&etago;someString>
- </verb>
- <p>
- If the xuiObject is a xuiList, it has methods available to create, add,
- remove certain elements, etc.
- <p>If the xuiObject is a xuiList, it has methods available to create, add,
- remove certain elements, etc.
- Assuming $myList is a xuiList of strings defined by the following XML
- declaration:
-
-
- <verb>
- <list name="myListName" label="Some comentary">
- <syntax>
- <string name="someStringName" label="some label" />
- &etago;syntax>
- <default>
- <item>bla&etago;item>
- &etago;default>
- &etago;list>
- </verb>
- <p>
- If $MyList has just been created it has a default content
- of one children with the value "bla", which XML representation would be:
- <verb>
- <myListName>
- <item>bla&etago;item>
- &etago;myListName>
-
-
- set childList [$myList getChildren]
-
- # In Tcl, code in brackets [] is executed and the result is substituted.
- # The previous statement works as follows:
- # - Invokes the method getChildren on the $myList object
- # - Store the result on the childList variable
- # Now childList contains all the children of $myList, in this case only one,
- # a xuiString element with value "bla"
-
- puts [$childList getValue]
-
- # puts is the Tcl command for printing a value to the standard output
- # The code inside the brackets gets the value of the list element, in this
- # case it will print "bla" since we have a single element, which has that
- # value.
-
- set newChild [$myList newChild]
-
- # The newChild method invocation creates a new list element and the
- # reference is stored in the newChild variable
-
- $newChild setValue "foo"
-
- # This new child, which is of the type xuiString, is asigned the value "foo"
-
- $myList insertChild $newChild
-
- # Finally, the child is inserted at the end of the xuilist.
- # In summary: A new children has been created and inserted in the list.
- # If the object was serialized, the result would be the following:
-
- <myListName>
- <item>bla&etago;item>
- <item>foo&etago;item>
- &etago;myListName>
-
- </verb>
- <p>
- This distinction between the XML representation of the object and
- the object itself is very important for a number of reasons:
- <itemize>
- <item>The XML document description specifics may change in the future. The XML
- objects are used widely through Comanche. Small changes on the syntax of the
- XML document would have wide impact and would require a multitude of other
- changes. The encapsulation on Tcl objects provides a level of abstraction
- that isolates most of these changes from the rest of programs.
- <item>Similar objects can be manipulated in a similar way (string, number,
- etc.). From the point of view of the programmer, it is assigning a value to
- an object via methods, with no required knowledge of how the XML output will
- look.
- <item>Objects can be easily manipulated and then rendered back to XML (or to
- some other format, like HTML). The rendering logic is separated from the
- object logic. The same object (a xuiString object) can be rendered in
- different GUI controls. This is the topic of the next section.
- </itemize>
-
- <sect>XML User Interface
- <p>
- Tcl, together with the graphical toolkit extension Tk was chosen to provide
- a Graphical User Interface for Comanche. As seen in previous sections, the
- interface can be described in terms of a mark up language based on XML. The
- interface description can be parsed and abstracted into [incr tcl] objects
- (see Glossary on Tcl and [incr tcl]). This intermediate abstraction layer
- allows for different rendering engines. The rendering can transform the
- objects into DHTML (Dynamic HTML) that can be rendered by a
- web browser or into a traditional GUI representation. It is possible for the
- front ends to issue callbacks and manipulate the Tcl object. If XUI objects
- share the same interface (like string, number), the same GUI object class
- can manipulate them. Conversely, the same xui object can be rendered
- differently by different GUI object class: an element of the type structure
- can be rendered like a collection of property pages or as several groups of
- directives.
- <p>
- <img src="images/ch6-property-page.gif">
- <p>
- Examples of guiInterfaces are :
-
- <sect1>guiString
- <p>
- Can render xuiString and xuiNumber elements.
- <p><img src="images/guistring.gif">
- <p><img src="images/guinumber.gif">
- <sect1>guiLabel
- <p>
- It is used to represent elements of the type label
- <p><img src="images/guilabel.gif">
- <sect1>guiLabeled
- <p>All the elements that have a label inherit from this guiObject class. It
- provides for text alignment of the labels so the interface looks nice.
-
- <sect1>guiBoolean
- <p>
- It is used to represent elements of the type guiBoolean
- <p><img src="images/guiboolean.gif">
-
- <sect1>guiImage
- <p>
- It is used to represent images
-
- <sect1>guiChoice
- <p>
- It is used to manipulate xui elements of the type choice.
- It is generally represented as a combobox. It could easily be represented as
- a collection of radiobuttons.
- <p><img src="images/guichoice.gif">
-
- <sect1>guiList
- <p>
- It is used to manipulate list objects
- <p><img src="images/guilist2.gif">
-
- <sect1>guiStructure
- <p>
- Is is used to manipulate xuiStructure elements. xuiStructure elements can
- represent compound directives or groups of other xuiElements. Depending on
- certain attributes being present (style) groups of directives can be
- represented in different ways: horizontally or vertically, surrounded by a
- labeled frame or with no decoration.
- <p><img src="images/ch6-gui-struct1.gif">
- <p><img src="images/ch6-gui-struct2.gif">
-
- <sect1>guiAlternate
- <p>Is is used to manipulate xuiAlternate elements.
- <p><img src="images/ch6-gui-alternate.gif">
- <sect1>guiPropertyPage
- <p>
- This gui element manipulates xuiStructures interpreting them as property
- pages:
- <p><img src="images/ch6-guiPropertyPage.gif">
-
- <sect1>How it works
- <p>
- This section describes how the process works from the instant that the user
- requests some information to the point that the user is presented with a
- property page that he can fill and return the information to the plugin.
- <p><img src="images/ch6-everything.gif">
- <p>
- <itemize>
- <item>User selects to view the properties of a given node, by right clicking
- on the node and selecting the "Configure node" entry from the menu.
- <item>The message is sent to the namespace, which contacts the appropriate
- plugins and generates the property pages document, which it is a XML
- description of the property pages.
- <item>The console receives the document, transforming it into a xuiObject of
- the type xuiPropertyPages (the XML definition is transformed into Tcl code).
- <item>The console needs to allow the end user to manipulate the
- xuiPropertyPages object and for that purpose creates a guiPropertyPages
- (presentation) object and connects it to the xuiPropertyPages object (data).
- <item>The guiPropertyPages object is passed the frame where it has to display
- its information, the propertyPages object and a reference to an object
- factory. It creates a listbox menu on the left and a notebook on the right.
- For each one of the property pages (elements of the xuiStructure), it
- creates an entry in the listbox (with an additional image if the attribute
- icon is present) and uses the guiObject factory to render the property page
- on the notebook.
- <item>When an element is selected on the listbox, the appropriate property page
- is displayed on the right notebook.
- <item>When the user is done, it can press the Ok button. The GUI representation
- can be destroyed then, but the xuiPropertyPages object will have the
- modifications performed by the user.
- <item>The xuiObject is then passed to the namespace, which will select the
- appropriate property pages and deliver it to the plug ins so they can act
- upon it.
- </itemize>
-
- <sect>Distributed architecture
-
- <p>The architecture of the system has being designed with distributed operation
- in mind. This translates into the following ideas:
- <itemize>
- <item>Few, well defined API calls. The idea is to reduce the traffic over the
- net and to simplify the implementation of different front end clients.
- <item>The inter process protocol is based on XML, which in turn is based in text
- and can be easily transported over other protocols and manipulated by other
- languages.
- <item>There is no notion of a single user. Requests can be server concurrently
- in a web server like fashion. Little or no state is kept.
- </itemize>
- <p>
- There are still issues that need to be addressed like delegation of
- authority and how to prevent administrators working concurrently on a
- configuration from interfering with each other
-
-
- <sect1>Different models for distributed operation
- <p>
- At least two models have been considered for developing an architecture that
- would allow for remote administration of machines
-
- <sect2> Web based approach
- <p>
- Namespace and plugins would reside in the remote machine. A web front end
- would also reside in the same machine and would accept requests from client
- browsers.
- <p>
- <sect2>Distributed application approach
- <p>
- The other approach is to encapsulate the protocol between the console client
- and the namespace over HTTP and have them reside in different servers. This
- would require installation of a Tcl client in the administrator machine, but
- would allow centralized administration from a single machine (the web based
- approach would require connecting to each machine that requires
- administration)
- <p>
- <sect1>Few, well defined API calls
- <p>
- The API calls between the three architectural blocks are few and well
- defined, as explained in the following sections:
-
- <sect2>Namespace / Plug-in
- <p>
- The communication that takes place requires the following information to be
- exchanged.
-
- <p>The plugins need to register with the namespace and explain which nodes it
- is interested in extending, etc.
- <p>
- <verb>
- registerPlugInInterests
- The information that the plug in would provide would be
- name
- version
- description
- node types that it provides
- node types that it extends
- category the plug in belongs to: network services, user management,
- system management
- </verb>
- <p>The plugIns needs to query the tree structure, add and remove nodes, etc
- The API functions to perform that are:
- <verb>
- getRootNode
- addNode
- configureNode
- removeNode
- getChildren
- </verb>
- <p>The namespace needs to request and deliver information from the plug in
- <itemize>
- <item>deleteNodeRequest (When the user wants to delete a node)
- <item>requestXuiDocument (The user requests a document. it can be a property
- page, a wizard or a right pane content)
- <item>answerXuiDocument (the user has filled some information and it has to be
- returned to the plug in for processing)
- <item>populateNodeRequest (The user is exploring a node and double-clicks on
- it, the namespace takes note and urges the plugin to add nodes. This
- allows for dynamically generating trees (useful for navigating a server's
- filesystem, for example.)
- </itemize>
-
- <sect2>Namespace / View
- <p>
- Similarly, the view needs to access the namespace, basically for the same
- purpose: query the tree structure, request information for display to the
- user and deliver back the user feedback. For those purposes it uses the
- previously detailed functions. In addition, the namespace informs the view
- when certain events occur: a node has been added or modified, etc
- <p>
- Also the namespace keeps track of which view has browsed which nodes and
- thus avoid informing the views of event regarding nodes the user has not yet
- browsed.
- <p>
- A future option may to request not to be notified of updates, and have
- the user refresh the display when necessary. This may be useful for slow
- links or the web based interface.
-
- <sect1>Inter process protocol based on XML
- <p>
- The interprocess communication that takes places is based on XML. The data
- ,object and method invoked are encoded in XML.
- <p>
- The interprocess communication is hidden in the infrastructure. The API
- offered to the module author is identical, no matter if the plug in is being
- used locally or remotely. When a component of the system talks to another
- component, it does so using xui objects. The system keeps track if the
- component that is being called is remote or local, if it is local, it
- directly passes the xuiObject to the called entity. If the entity is remote,
- it performs a remote call and serializes the object into XML. At the other
- end, the serialized object is transformed again into a xui Object.
- <p>
- How does the system know if the object called is remote or local? First,
- objects must register themselves before being able to invoke / receive any
- methods. If the object is accessible locally (for example, namespace and
- plug ins are living in the same Tcl interpreter) nothing is done and
- future communication takes place directly. If the object being registered is
- accessing the system remotely, a "fake object" will be created that will
- remember how to access the remote object. This fake object will then be
- accessed normally as a local object by the rest of the system. When a method
- is invoked in this fake object, it will in turn take the arguments, the
- method and the identity of the caller, serialize them and sends it to the
- remote object. This also involves timeouts (that can be tuned depending on
- the situation) so if the remote end becomes unavailable the application will
- get informed and the object will get deleted.
- <p>
- All this process is greatly simplified by the fact that arguments are
- passed as xuiObjects, which are composed of only a few building blocks. Thus
- arbitrary functions can be called with arbitrary arguments, since the system
- knows how to serialize them. This allows for greater flexibility, since this
- generic mechanism avoids:
- <itemize>
- <item>having to declare each one of the possible functions.
- <item>having to explicitily distinguish between remote and local operations.
- </itemize>
-
- The XML protocol can be encapsualted in a variety of transport protocols:
- <itemize>
- <item>Over HTTP, both directly (using GET and POST methods) or over XMl-RPC
- <item>Plug-In communication with the namespace could also be done using a
- Fast-CGI approach.
- </itemize>
- Note: none of the above is yet implemented. Comanche can only run as a local
- application right now.
-
- <sect1>Concurrency handling
- <p>
- The namespace server will act in a similar fashion to a web server, in the
- sense that it can serve requests simultaneously. In fact, initial
- feasibility tests where performed using the tclhttpd web server.
- In both cases, XML-RPC was used as the underlying communication mechanism.
- Requests are served in a first come first served basis. There is a single
- process running and speed is not likely to be an issue (the network part is
- usually the bottleneck. Because of that network transmission is done using
- fileevents (fileevents is a Tcl feature that allows serving of multiple
- requests using callbacks to detect when a socket has received new data or
- the data scheduled to send has been effectively transmitted).
- <p>
- Concurency means several problems need to be addressed: what happens when two
- different users are configuring the same application or where the same user
- configures the application using different windows (in the case of the web
- interface, opening several browser windows). There is the potential for the
- following scenarion to happen: Administrator A selects property pages for
- virtualhost v1. Administrator B selects property pages for the same virtual
- host. Administrator B presses OK and commits the changes. Administrator A
- presses OK and commits the changes.
- <p>
- The following can happen:
- <itemize>
- <item>Administrator A will overwrite administrator B changes. Administrator B
- does not even know that. This is Bad
- <item>Changes could be merged a la CVS style. But the concept of merging
- changes is more ambiguous here. Merging could also lead to inconsistencies.
- </itemize>
- Alternative, more desirable solutions are the following:
- <itemize>
- <item>Only one admin can be editing a node/service at a given time. Users
- with enough rights should be able to kick out other admins to avoid deadlock
- situations (the administrator browser crashed, but the admin appears to the
- system as still logged, preventing anyone else from administering the
- machine). Some schema of auto-logout after a period of inactivity could also
- be implemented.
- <item>More than one admin can be logged and editing the same node. If the
- previously described situation with admin A and admin B occurs, the solution
- is to prevent Admin A to commit its changes, informing it that the node has
- been modified in the mean time and the information is no longer valid.
- </itemize>
-
- <sect1>Delegation of authority
- <p>
- Currently there is no concept of users or privileges in Comanche.
- It needs to run with the privileges required to edit by hand the
- configuration files of the programs it is configuring. It would however, be
- interesting to have some authentication and delegation schema for certain
- situations: an ISP may be hosting hundreds of web sites as virtual hosts for
- their customers. In the current situation, the customer must explain what
- changes it needs to make to the configuration files and the ISP staff
- performs that for them. This has an obvious administrative overhead and slow
- turn around time. This problem is partially solved currently :
-
- <itemize>
- <item><bf>Using Frontpage server extensions</bf>. This allows customers to use
- proprietary Ms tools to configure and maintain their web servers. This
- extensions have a track record of security problems and messy code, so they
- are not very popular with ISPs, which however have to install them due to
- customer demand.
- <item><bf>Use .htaccess files</bf>. These files allow per directory configuration files
- If its used is enable, Apache will look for every one of these files and
- apply the parameters that it finds. They are used for example to allow users
- to specify password protected pages and directories. .htaccess files are
- however, a serious performance hit for highly loaded servers
- </itemize>
- <p>
- In summary, delegation of authority is an interesting feature, but poses a
- series of challenges that are out of the scope of a first implementation of
- Comanche. The architecture, however, if flexible enough to implement such
- hooks for authentication and delegation. These controls could be placed when
- views register with the namespace, when xuiRequests and xuiAnswers are
- requested, etc.
-
-
- <sect>Programmer tutorial
- <p>
- This section guides a programmer in the process of writing a simple plugin
- for Comanche. The purpose is to describe the APIs that module authors should
- know and give examples of how they can be used. Although the module is
- written in Tcl, knowledge of Tcl is not strictly necessary or assumed. The
- code is extensively commented and explained to guide the reader.
- <p>
-
- <sect1>Creating a module.
- <p>
- The main tasks that a Comanche module has to carry out are:
-
- <itemize>
- <item>Read any internal configuration and initialize itself
- <item>Answer requests for information
- <item>Accept answers from the client
- </itemize>
- <p>
- We will develop a simple module. This module queries the hostname
- of the machine and allows the user to change it. To do so, the plugin will
- rely on the "hostname" system command. In certain operating systems, like
- Red Hat Linux, changing the hostname permanently involves changing some text
- files that get read at startup. Since this is just a demonstration of how to
- write a simple module for Comanche, we will not worry about that. This
- simple plugIn will add a node to the Comanche console. When the user clicks
- on the node, a page on the right will appear that gives the current
- hostname. When the user right clicks on the node, a menu will appear that
- allows the user to pop up a property page to change the hostname value.
- <p>
- Every Comanche module should be designed as a [incr tcl] module (this is not
- necessary if it is done via the remote plugin interface, which is not
- implemented in this version and that allows plugins to be written in a
- variety of languages)
- <p>
- [incr Tcl] is an object oriented extension of Tcl. It allows you to create
- classes which define objects. Objects have functions that can be called on
- the object and that are called methods. We could define a class dog, which
- represents dogs in abstract. We could define a method, bark, that when
- invoked would print "Barf!" on the screen. In [incr tcl] this is done in the
- following fashion:
- <verb>
- class dog {
-
- method barf {} {
- puts "Barf!"
- }
-
- }
- </verb>
- <p>
- We can create an object called scooby, which is an instance of the class dog.
- <p>
- <verb>
- dog scooby
- </verb>
- <p>
- Now we can tell scooby to bark:<p>
- <verb>
- scooby bark
- </verb>
- <p>
- and we get:<p>
- <verb>
- Barf!
- </verb>
- <p>
-
- The skeleton of the plug in looks something similar to the following:
- <verb>
- class hostnamePlugIn {
- inherit plugIn
- }
- </verb>
- <p>
- In a similar fashion to the above, we are going to be creating an object of
- the class plugin. When we have a plugin, we can tell it to do certain things
- for us: we can tell it to add nodes to the namespace, we can ask it
- information about nodes that belong to it, etc.<p>
- The kind of information that we ask is usually property pages for
- displaying/modifying the plugin settings. Most of the work in a plugin
- resides on the design of these property pages.
- <p>
- We are inheritting from the plugIn class, which implements the following
- methods:
- <verb>
- method init { args }
- method requestXuiDocument { xuiData }
- method answerXuiDocument { xuiData }
- method deleteNodeRequest { xuiData }
- method populateNodeRequest { xuiData }
- </verb>
- <p>
-
- From all these, the only ones that we need to implement are the first three
- ones, since we only have one node (populateNodeRequest is the way the
- namespace tell us to add nodes that are children of another) and we do not
- want to delete it. The remaining three functions (init, requestXuiDocument,
- answerXuiDocument), deal with initialization routines, and passing/getting
- information to/from the user.
-
- <sect1>init
- <p>
- This function will get called at initialization time. It gives our
- plugin a chance to initialize internal data structures, read external files,
- etc. and finally add nodes to the namespace if necessary. There are several
- helper objects that can be used when managing many nodes. Since we are adding
- a single node, it is easier to add it directly and keep track of where we
- added it in a variable.
- <p>
- <verb>
- # args contains the options that are passed to the plugIn at initialization
- # time.
- #
- # -namespace contains the name of the name space server
-
-
- method init { args } {
-
- # args is a list of pair/value options
- # The following is to convert the list to an array, called options
-
- array set options $args
-
- # This is the way Tcl assigns a variable value
- # Now namespace contains the value of the element -namespace
- # of the array options
-
- set namespace $options(-namespace)
-
- # The [] tell Tcl to treat the text contained in the brackets as a
- # command, execute it and substitute the result. So the sequence of
- # events is as follows:
- # - Ask the namespace for the root node (will return a xuiNode object)
- # - Get the unique id number for that node
- # - Assign that value to the hostnameNode variable
- #
-
- set parentNode [[ $namespace getRootNode] getId]
-
- # Add a node to the namespace, we need to tell the namespace:
- # - Who we are: $this
- # - Which namespace we want to hook up under: $namespace
- # - Which node we want to hook the new node under: $parentNode
- # - Several icons for open and closed
- # - Classes: List with node classes. Leaf means that it cannot have
- # children. Hostname means that it belongs to our plugin.
- # - Label: Text that will be displayed next to the icon
-
- set hostnameNode [::plugInUtils::addNode $this $namespace $parentNode \
- -classes {hostname leaf} \
- -openIcon networkComputer \
- -closedIcon networkComputer \
- -label {Hostname settings}]
-
- # We remember the Id of the node that we just added
-
- set hostnameNodeId [$hostNameNode getId]
- }
- </verb>
- <p>
- We add a couple of variables to the plugIn, to also store the id for the
- node just added and the name of the namespace
- <p>
- With just the above, the plugin will add the node to the namespace:
- <p><img src="images/pg-hostname.gif">
- <verb>
- class hostnamePlugIn {
- inherit plugIn
- variable namespace
- variable hostnameNodeId
- }
- </verb>
- <p>
- By declaring the variables in the plugin class, we make sure that they are
- persistent and accessible when other methods are called.
- <p>
- Next step is to implement the rest of the functions required for displaying
- menus, right pane contents and a pop up property page. When we receive/send
- a XML document using <verb>requestXuiDocument</verb> or
- <verb>answerXuiDocument</verb> we have to specify the kind of document we
- are receiving/transmitting (menu, property page, etc)
- <p>
- This involves processing xuiStructures for storing the answer, etc. We can
- save ourselves a lot of trouble if we directly inherit from the basePlugIn
- class, which already takes care of many of those details.
- <p>
- The basePlugin class defines the following methods:
- <verb>
- method _inquiryForPropertyPages { node }
- method _inquiryForMenu { node }
- method _inquiryForWizard { type node }
- method _receivedWizard { type node }
- method _inquiryForRightPaneContent { node }
- method _receivedPropertyPages { node xuiPropertyPages }
- method _receivedCommand { node command }
- </verb>
- <p>
-
- We are going to provide content now for each one of the functions and we
- will be one step ahead in building our plugin
- <verb>
- _inquiryForRightPaneContent
- </verb>
- <p>
- This function takes as an argument the node for what the content is being
- requested. It must return the HTML-like text to be displayed in the right
- pane portion of the interface. Since our plugin only has one node, it is
- safe to assume that when the function is called the node is the right one,
- so we do not need to double-check it. If a plugin had more than one node, it
- would be necessary to distinguish between them.
- <p>
- The function is then, simply:
- <verb>
- body hostnamePlugIn::_inquiryForRightPaneContent { node } {
-
- # Set the variable result to a snippet of HTMl-like code
- # The link, instead of a normal HTML link is a command directed
- # to the console. In this case it tells the console to show
- # the property pages for the selected node when clicked.
-
- set result {
- <h1>Hostname Settings<h1>
- <br> This is a small plug in that allows to display and
- <a href="command propertyPages"> change&etago;a>the hostname value.<br>
- The current value is }
-
- # Current value is given by executing the system command hostname
-
- append result [exec hostname]
- return $result
- }
- </verb>
- The previous addition will show in the console as follows:
- <p>
- <img src="images/pg-hostname-right.gif">
- <p>
- Menu generation is still not implemented, there is a generic menu in place.
- When the user clicks on the menu entries, nothing will happen except when
- the user selects "Configure node". This will trigger the
- <verb>_inquiryForPropertyPages</verb> method
- <p>
- For returning property pages, instead of creating a new property page object
- per request, we will keep a property page and update it every time it is
- requested.
- <p>
- We add the following to the plug in definition
- <p>
- <verb>
- variable hostnameXuiPP
- variable hostnameEntry
-
- constructor {} {
-
- # We create a global object of type xuiPropertyPage
- # the #auto keyword will assign an arbitrary name.
- # This is necessary because if we hardcode the name, this would
- # prevent having two instances of the same plugin
-
- set hostnameXuiPP [xuiPropertyPage ::#auto]
-
- # Set default icon, title and name of the property page
-
- $hostnameXuiPP configure -icon network
- $hostnameXuiPP setLabel {Configuring hostname}
- $hostnameXuiPP setName hostnamePP
-
- # Create the xuiString object that will hold the hostname value for the
- # user to modify ...
-
- set hostnameEntry [xuiString ::#auto]
- $hostnameEntry setLabel "Hostname"
- $hostnameEntry setName hostname
-
- # ..and add it to the property page
-
- $hostnameXuiPP addComponent $hostnameEntry
- }
- </verb>
- <p>
- The constructor method is called everytime a hostnamePlugIn object is
- created. It set ups a XUI property page object. Every time they ask us for
- a property page, we fill the current hostname and we return the property
- page back. When it comes back, it will contain the data, probably modified
- by the user.
- <p>
- The following methods perform just that:
- <p>
- <verb>
- body hostnamePlugIn::_inquiryForPropertyPages { node } {
-
- # User is asking for a property page to display for this node
- # We set the current hostname in the entry
-
- $hostnameEntry setValue [exec hostname]
-
- # We return the property page
-
- return $hostnameXuiPP
- }
-
- body hostnamePlugIn::_receivedPropertyPages { node xuiPropertyPages } {
-
- # We extract the appropriate property page from the xuiStructure
- # containing the property pages.
- # (there is only one page, but we ask it by name)
-
- set pp [$xuiPropertyPages getComponentByName hostnamePP]
-
- # From that property page, we get to the string containing the hostname
- # and get its value
-
- set newHostname [[$pp getComponentByName hostname] getValue]
-
- # Change the hostname to the one supplied by the user
-
- catch {exec hostname $newHostname}
- }
- </verb>
- <p>
- And that is all, the plugIn is completed, we do not care about the rest of
- available functions by now (asking for wizards, etc...), since the plugIn is
- a simple one. We need now to package the plugIn in a certain way so Comanche
- can discover it and load it at start up. Comanche stores modules under the
- subdirectory modules/ Under modules, each directory contains a plugIn. For
- each plugIn, a special file called init.tcl will get sourced.
- <p>
- The module needs to define certain functions that will get called at the
- appropriate time:
- <verb>
- modulename_init
- modulename_restart
- modulename_info
- modulename_unload
- </verb>
- <p>
- Using the module name is a convention. It will probably be replaced by use
- of Tcl namespace facility, just not yet.
- <p>
- By now we only define the modulename_init function, in this case
- hostname_init, that will get called with the following arguments
- -namespace namespaceObject
- <verb>
-
- # This file will get sourced when Comanche starts to load the module
- # and declare the hostname_* functions
-
- # Determine my current directory
-
- set currentDir [file dirname [file join [pwd] [info script]]]
-
- # Load the file containing the class definition
-
- source [file join $currentDir hostname.tcl]
-
- # Will get called each time we want to add a plugin. In this case, we are
- # only adding one
-
- proc hostname_init { args } {
- array set options $args
- set hostnameInstance [hostnamePlugIn ::#auto]
-
- # Hook up the plugin to the namespace
-
- $hostnamePlugIn init -namespace $options(-namespace)
- }
-
- # This function is used to provide information about the installed plugins
-
- proc hostname_info {} {
- array set info {description {Example module that changes hostname}}
- array set info {name {hostname}}
- array set info {version {1.0}}
- array set info {icon network}
- return [array get info]
- }
- </verb>
-
- Where do you go from here? Have a look at the other documents at the docs/
- subdirectory and at the source code for the modules at plugins/.
- Writing a XML definition to support an apache module (such as PHP)
- is really easy. have a look at plugins/apache/modules
-
- </article>
-