Full documentation of cfengine along with several papers are available from the homepage
. Cfengine is used by linxus to provide a framework for configuring machines. It facilitates editing text files, setting permission, copying files, etc.. The current configuration can be retrieved from the bazaar repository on linxus103. The archive name is email@example.com
, and the tree is cfengine--stable--1.0. The following commands will allow you to register and retrieve the tree.
baz register http://firstname.lastname@example.org
baz get email@example.com/cfengine--stable--1.0
Cfengine has a class system which acts similiar to the way conditional statements work in many progamming languages. This allows scripts to be written that can work on multiple operating systems and produces convergent behaviour. Convergence is one the most desirable features of cfengine, it will always try and move the system towards a known state.
The individual cfengine scripts are also refereed to as classes. Ideally, they would be placed into a hierarchical class system so that machines could have a few classes associated with them which would pull down all the dependent classes as well. In essence this would behave similiar to apt. The way it currently works in cfengine is that the script classes.cf is imported into the main cfengine configuration. This in turn calls ldapquery.py which returns a period seperated list of classes assoicated with the machine. This then determine which classes/cfengine scripts are imported.
For example if ldapquery.py returned:
Then linxus_passwd.cf, linxus_workstation.cf, and cups_client.cf would be imported into the cfengine configuration.
Notice that the naming system of the class is generally two underscore seperated words, all lowercase. This avoids confusing the cfengine parser and gives a consistent naming scheme. Names should describe both the software it configures and the role it has. For instance cups_client.cf configures machines to use CUPS as a client for printing.
Further information relating to
can be found at CfengineClasses
The configuration system works by getting the configuration from the cfmaster bazaar repository. The cfengine script to do this is baz_update.cf. It will update all the cfengine configuration files located in /config. To avoid disturbing files that use that area for staging the bazaar merge command is used to pull down any updates.
By using a revision control system multiple branches can be maintained for testing purposes. A testing environment could be setup that used, for example, the tree cfengine--testing--1.0. Once, changes were verified they could then be applied the the production environment.
The configuration resides in /config on linxus103. This area, as noted, gets updates via cfengine from the bazaar repository. It contains all the cfengine scripts and associated files. The directory structure is as follows: classes are located under /config/cf, files associated with a class are located under /config/files/$classname.
This directory is also used as a staging area for distributing files to clients. Files can be created on the server and then pulled down by the client. For instance the passwd file associated with linxus_workstation is created on the server by the linxus_passwd class. Clients using the linxus_workstation class can pull down the file by copying /config/files/linxus_passwd/passwd.linxus_workstation.
It's generally a good idea to use templates for configuring software instead of relying heavily on cfengine's more complex file editing tools. An, instance where a template may be better is for gdm's configuration file which is broken into sections declared by square braces. Using cfengine the script can become quite complicated but using a template with unique variable names will make for a simpler script. The convention currently used is that all variables should be declared in the 'control' section of the cfengine script. The same variable names should be used, except all upper case and surrounded by angled braces in the template file. The cfengine 'ReplaceAll' command can be used to fill in the correct values after the file has been copied to the client.
For example the template file for configuring the CUPS file cups.client would be as follows:
The cfengine script would look like the following script
. The decision whether to use a template or use the cfengine commands is left as an exercise for the reader.
Cfrun is a tool used by cfengine to send push events to clients. It is needed in the rare event that a pull needs to be triggered on a client machine. For cfrun it work the client needs to be running cfservd with a configuration to run cfrun. The following is an example of a valid cfservd.conf for a client to run cfrun.
domain = ( uwaterloo.ca )
cfrunCommand = ( "/var/lib/cfengine2/bin/cfagent" )
AllowUsers = ( root )
Every host that cfrun is to be run on must be entered into the cfrun.hosts file located in /etc/cfengine. The syntax of this file is described in the cfengine documentation, it would be useful to write a script to generate it on linxus103 based on a LDAP query. The syntax of the cfrun command is also described in the documentation, the following is an example that will define the class runpkgsync on the remote hosts, and run on all machines that are members of the debian class.
cfrun -- -D runpkgsync -- debian
When cfengine is installed it generates a public and private key for handling authentication. However, some method is still needed to exchange the keys between the client and server. There is an option to trust hosts on a subnet, so whenever a host makes first contact with the server they will exchange there public keys and trust each other. A better way of doing this is to exchange the keys during the installation process. A hook was created for FAI in order to accomplish this via a scponly account on linxus103. The hook is called after the base environment is installed which prompts the user for the password to scp the key over. The permissions on the ppkeys directory on linxus103 where changed to allow the user handling scp keys to write to the directory.
Work To Be Done
- Create a confdir hook for FAI to use rsync to get the configuration information instead of mounting via nfs.
- Create an emergency recovery script to create a working cfengine configuration in case something "really bad" happens.
- Implement the directory services stuff for managing machines
- Implement the hierarchical class system for managing cfengine scripts
- 05 Jul 2007