FAI Class Server
Introduction
The FAI Class Server (FCS) evolved during a project I did in summer 2005 at the Federal Institute of Technology Lausanne. The project was part of a FAI setup to allow for fully automated Debian GNU/Linux installations on a number of different machines (workstations, notebooks, servers, and cluster nodes).
FCS is a helper application to manage FAI classes in a centralized manner. Its main features are:
Class assignment based on hostname pattern matching
Class dependency resolution
Sorting of classes according to a predefined order (useful for postinstall scripts that require a particular execution order)
Easily extensible with additional scripts (support for text config files is included but LDAP support should be easy to add, for instance)
License
FAI Class Server (FCS) is licensed under the GNU General Public License.
Download
Current version: 0.1 (2005-10-18) [fcs-0.1.tar.gz (14 kB)]
Screenshots
Screenshot 1 demonstrates class membership configuration during the first phase of a FAI installation. The hostname is sent to the FCS server, upon which the client is given a list of classes it should be a member of.
Screenshot 2 demonstrates how class dependency resolution works. The client sends a list of its current classes to the FCS server which responds with a list of follow-up classes.
Components
FCS consists of a server and a client part, the ladder one being divided into several parts. What follows is a description and configuration manual for all of these parts.
FCS server part
There are two operating modes fot the server part:
Stand-alone: The server part has a simple built-in HTTP server that listens for requests on a freely configurable port. This mode is useful for machines like FAI servers that may not have an HTTP server installed.
CGI: If the FCS server part is to be run on a machine on which there is already an HTTP server running, it can be run as a CGI script.
Both modes are functionally equivalent, however, there is a slight difference in the configuratin of the client parts. When running in stand-alone mode, the request path is always / whereas in CGI mode it depends on the location of the CGI script (e.g. /cgi-bin/fai/).
FCS client parts
At the moment there are two FCS client parts, one for hostname based class assignment and a second one for class dependency resolution. The parts come in the form of FAI class scripts that are located in the config/class directory.
The fcs-hostname script connects to the FCS server part and transmits the current (fully-qualified) hostname. In response it receives a list of class names the installing machine belongs to and adds those classes to the current list of classes.
The fcs-dependencies part behaves in a similar name but instead of the hostname it sends the current list of classes (including those added by the fcs-hostname script if it has been run before) to the server. The response again contains a list of classes to be added to the current class list, but this time as a function of the class list transmitted, namely the classes that depend on them (and so on—the process works recursively).
Installation
TODO
Configuration
Both, server and client parts, have various configuration options which are described below in detail. While the main configuration of the server part uses in-program configuration (meaning that a section of constants at the top of the source file can be edited), the remaining components use an approach based on text files.
Server part
Main configuration
The main configuration controls the port number of the built-in HTTP server and the locations of the different config files. The configuration options can be found at the top of the fcs.pl source file in the block titled Constants. The available options are:
| Option | Description |
| SERVER_PORT | [Stand-alone mode only] Determines the port number that the built-in HTTP server listens on. Make sure you set this to a port number that is not otherwise in use or the server will fail to start. |
| CLASSES_DIR | The location of the scripts used to determine if a given hostname is a member of the class. This must be a directory name. Unless the path starts with a slash, it will be interpreted relative to the directory containing the script. The functioning of these class membership scripts is described in more detail below. |
| DEP_CONFIG | The location of the configuration file describing class dependencies. The must be the name of an existing file whose syntax is described in the section Class dependency configuration below. |
| ORDER_CONFIG | The location of the configuration file describing class order. The file must exist and conform to the syntax described in the section Class order configuration below. |
Class membership scripts
When the FCS server receives a request of the form ?hostname=myhost.mydomain.org, it executes every script in the CLASSES_DIR directory with the hostname (myhost.mydomain.org in the example) as the first argument. If the script returns with value 0 ("true"), the host is taken to belong to the given class. If it returns with a non-zero value ("false"), the machine is not part of the class and nothing happens.
An example script that retrieves host-to-class associations from a text file is included. It is described in more detail in the Example scripts section below.
The recommended way of handling class membership scripts is to have a separate directory containing the actual scripts and create symbolic links in the CLASSES_DIR directory with the names of the classes. The script can then retrieve the class name from the name it was called as (usually $0). Another possibility is to create symlinks to /bin/true or /bin/false for classes that all/no machines should be members of.
Class dependency configuration
The class dependency file describes dependencies between classes. A sample is provided for illustration purposes.
Each line consists of two parts; a classname and a list of required classes (separated by whitespace or commas). Empty lines and comment lines (starting with the # character) are ignored.
Example: You want all machines that are members of the NOTEBOOK class automatically to be members of the PCMCIA and WIRELESS classes. Simply add the following line to the configuration file:
NOTEBOOK PCMCIA, WIRELESS
An important feature of FCS' class dependencies is the ability to resolve transitive dependencies. Let us explain this by means of a simple example:
Example: You want your desktop machines to have KDE and Xfce installed by default. On some machines, however, you decide to use the GNOME desktop instead. Because Xfce lacks a few applications that you want to make available to your users, you decide to install a subset of GNOME (a GNOMEAPPS class) whenever Xfce is installed. For this scenario you would use the following setup:
GNOME GNOMEAPPS XFCE GNOMEAPPS DESKTOP KDE, XFCE
As you can see there is a transitive dependency "DESKTOP => XFCE => GNOMEAPPS". So whenever a machine is a member of the DESKTOP class you not only want it to belong to XFCE but also to GNOMEAPPS.
This kind of dependency is automatically resolved by FCS as long as dependencies for required classes are defined before they are used. In the above example, if the DESKTOP class were defined in the first line, the transitive dependency could not be resolved (because by the time FCS reads the DESKTOP line it does not know about XFCE's dependency on GNOMEAPPS.
Class order configuration
A class order file defines a class order that is used during a reorder request. While class order is not used by the client parts included with FCS, it can prove useful in post-install scripts when you need scripts for individual classes to be run in a particular order.
The syntax for class order files is very simple. Each line contains the name of a class and the order of the lines defines the order used for sorting. Again, empty lines and lines with a leading # are ignored.
Example: To impose the order "X, KDE, DESKTOP", the configuration file could look as follows:
# Make sure X is configured before KDE X KDE DESKTOP
If classes are to be sorted that cannot be found in the class order configuration they are inserted at the end of the list. This can lead to a problem with two of FAI's predefined classes: DEFAULT (always first) and LAST (always last). If you omit them from your configuration, they might both end up at the end of the list, so DEFAULT would not be guaranteed to be the first class in the list anymore.
To work around this possible source of error, FCS handles these two classes in a special way: Unless specified otherwise the DEFAULT is automatically assumed to be at the first position, while the LAST class is automatically appended at the end.
In certain cases you may not want all unknown classes to be at the end of the list (remember: they would still precede the LAST class). For this case you can use the * placeholder. A final example illustrates this:
Example: You want all unknown classes to be between BASE and DESKTOP:
BASE X # Unknown classes before DESKTOP * DESKTOP
Recommended file structure
This section describes a possible file structure for the server part of FCS. It is merely a recommendation and by no means a requirement, so it can be adapted according to the needs of the user.
| Directory | Contents | Description |
| ./ | fcs.pl | FCS server part, main program |
| ./classes/ |
CLASS_A -> ../scripts/text.pl CLASS_B -> ../scripts/text.pl CLASS_C -> ../scripts/text.pl |
Host-to-class association scripts (symlinks in this case): called with the hostname as the first argument |
| ./config/ |
CLASS_A CLASS_B CLASS_C |
Host-to-class association configuration files for scripts/text.pl |
| ./scripts/ | text.pl | Example script: text-based host-to-class association |
| ./deps/ | deps.conf | Class dependency configuration |
| ./order/ | order.conf | Class order configuration |
Example scripts
scripts/text.pl is an example of a script that manages host-to-class associations based on simple text configuration files.
The script requires two pieces of information: a class name and a hostname. It gets the class name from the name it is called as ($0 in Perl or argv[0] in C). The hostname is retrieved from the first argument given to the script. (Remember that the FCS server part calls every script in the CLASSES_DIR directory—called classes in the recommended file structure above—with the hostname whose class membership it needs to determine.)
When the script is called, it looks for a configuration file with the determined class name. If such a file cannot be found, the script terminates with an error, which the FCS server part interprets as "not a member of the class". If a configuration file was found, it is parsed and its content evaluated line by line as explained below.
Script configuration: The script support several configuration options. All of them can be changed by modifying the Constants section of the script file itself.
Option Description CONFIG_DIR The location of the configuration files that contain the information which hosts belong to the given class. The specified directory is interpreted relative to the path containing the script itself. PARSE_DOMAIN_SECTIONS Determines if the configuration files may contain so-called domain sections. Domain sections are useful if the machines managed by FCS belong to different domains. The option should be set to 1 if the feature is enabled and to 0 otherwise. More information on domain sections is available below where the configuration file syntax is discussed. DEFAULT_DOMAIN Specifies the default domain name that is assumed for all host entries in the parsed configuration files. If this option is left empty, the host entries are taken to be fully-qualified hostnames unless domain sections are used. Domain sections can be used to override the DEFAULT_DOMAIN setting (provided that PARSE_DOMAIN_SECTIONS is enabled). Configuration file syntax: There are two kinds of lines in the configuration files: lines that start a domain section and lines that contain hostname rules.
Domain sections are introduced by a line with the following syntax:
'[' domain ']' | "[]"
In the first variant, domain is an arbitrary domain name (e.g. rubli.info, cluster.rubli.info, ...). All hostname rules following such a line are taken to be in the given domain, i.e. the domain is appended before evaluating the pattern. This implies that the use of the second syntax can be used to introduce a section containing fully-qualified hostnames.
Remember that the script's DEFAULT_DOMAIN can also be used to set the domain. A setting of "DEFAULT_DOMAIN = rubli.info" has the same effect as a "[rubli.info]" domain section at the top of every configuration file.
Hostname rules have the following syntax:
pattern [ <whitespace> ( '0' | '1' ) ]
The first field, pattern, is a Perl-compatible regular expression against which the hostname is matched. The second field is a boolean value that determines membership in the class. If it is omitted, the default value of 1 is assumed.
The configuration files are parsed line by line starting at the top. The first rule that produces a match is used. If the boolean value is 1, the script exits with a zero return value ("true" in the shell), otherwise it returns with a non-zero value ("false" in the shell). Empty lines and lines with a leading # sign are ignored.
Client parts
Configuration of the client parts is rather straightforward. It is limited to a single configuration file as can be seen from the following table explaining the equally simple file structure:
| Directory | Contents | Description |
| ./FAI/config/class |
60-fcs-hostname.source 98-fcs-dependencies.source |
Scripts for determining hostname-dependent class membership and class dependencies |
| ./FAI/config/class | fcs.conf | Configuration file used by the FCS client part scripts |
The fcs.conf configuration file has a number of settings that influence the behavior of the client parts:
| Option | Description |
| FCS_HOST | The name of the host the FCS server part is running on. |
| FCS_PORT | The port number of the FCS server part. |
| FCS_BASE_URL | The URL where the FCS server part can be reached. |
| FCS_DEBUG | Enables debug mode for the client parts. In debug mode the scripts wait for the user to press the Enter key after their task is completed. Uncomment this setting to enable debug mode. |
| FCS_SLEEP | The amount of time (as understood by the sleep command) to wait after a task is completed. This delay can be useful if you want to double-check the functioning of your FCS setup. |
| FCS_ERROR_SLEEP | The amount of time to wait after an error has occurred (e.g. if the FCS server could not be reached). The format is the same as for FCS_SLEEP. |
Since the configuration file is sourced by the client parts, you can use Bash-style comments.