[ previous ] [ Abstract ] [ Copyright Notice ] [ Contents ] [ next ]

FAI Guide (Fully Automatic Installation)
Chapter 6 Installation details


6.1 The configuration space

The configuration is the collection of information how exactly to install a computer. The central configuration space for all install clients is located on the server in /usr/local/share/fai and its subdirectories. This will be mounted by the install clients to /fai. Following subdirectories are present and include several files:

class/
Scripts and files to define classes and variables and to load kernel modules.

disk_config/
Configuration files for disk partitioning and file system creation.

package_config/
File with lists of software packages to be installed or removed.

scripts/
Script for customization.

files/
Files used by customization scripts, eg. user created kernel packages. Most files are located in a subtree structure, which reflects the ordinary directory tree. For eg. the templates for nsswitch.conf are located in /fai/files/etc/nsswich.conf.

hooks/
Hooks are user defined programs or scripts, which are called during the installation process.

The main installation script rcS_fai uses all these subdirectories in the order listed. The FAI package contains templates for all these configuration scripts and files in /usr/share/fai/templaes. Copy the configuration templates to the configuration space and start an installation. These files need not belong to the root account. You can change their ownership and then edit the configuration with a normal user account.

     # cp -a /usr/share/fai/templates/* /usr/local/share/fai
     # chown -R fai /usr/local/share/fai

All these files contain configuration for some example hosts. A cluster of workstations (bigfoot, ant01, ant02,...) and a Beowulf cluster with a master node called nucleus and computing nodes atom01, atom02,... are included.

bigfoot
This is a server with much software. It provides the home directory /usr for its NFS clients. Also some daemons are installed and activated by default.

ant01,...
These dataless clients mount /usr and /home from bigfoot. Most of the disk space is spend for a scratch partition, which is exported to a netgroup of hosts.

nucleus
This Beowulf master node is a server with much software. It provides the home directory /usr/local for its computing nodes. Also some daemons are installed and activated by default.

atom01,...
These Beowulf clients mount /usr/local and /home from nucleus. Most of the disk space is spend for a scratch partition, which is exported to a netgroup of hosts.

Start looking at these examples and study them. Then change or add things to these examples. But don't forget to plan your own installation !


6.2 The default tasks

After the kernel has booted, it mounts the root file system via NFS from the install server and init starts the script /sbin/rcS_fai. This is the script which controls the sequence of the installation. No other scripts in /etc/init.d are used.

The installation script uses many subroutines, which are defined in /usr/share/fai/subroutines. All important tasks of the installation are called via the subroutine task name appended by the name of the task as an option (eg. task instsoft). The subroutine task calls hooks with prefix name if available and then calls the default task (defined as task_name in subroutines). The default task can be skipped on demand if the file /tmp/skip.name exists.

This is the description of all default tasks.

confdir
The kernel append parameters define variables, the syslog and kernel log daemon are started. The list of network devices is stored in $netdevices. Then additional parameters are fetched from a DHCP or BOOTP server and also define variables. The resolver configuration file is created and the configuration space is mounted from the install server to /fai. The file /fai/hooks/subroutines is sourced, if it exists. Using this file, you can define your own subroutines or override the definition of FAI's subroutines.

setup
This task sets the system time, all FAI_FLAGS are defined and two additional virtual terminals are opened on demand. A secure shell daemon is started on demand for remote logins. A list of all local hard disks is stored to $disklist and $device_size contains a list of disk devices and their size.

defclass
Defines classes using scripts and files in /fai/class and classes from /tmp/additional-classes.

defvar
Sources all files /fai/class/*.var for every defined class. If a hook has written some variable definitions to the file /tmp/additional.var, this file is also sourced.

action
Depending on the value of $FAI_ACTION this subroutine decides which action FAI should perform. The default actions are: sysinfo, install, backup. If $FAI_ACTION has another value, a user defined action is called, if a file /fai/hooks/$FAI_ACTION exists. So you can easily define your own actions.

sysinfo
Called when no installation is performed but the action is sysinfo. It shows information about the detected hardware and mounts the local hard disks read only to /tmp/target/partitionname or with regard to a fstab file found inside a partition. Log files are stored to the install server.

backup
Called when action is backup. Currently the default backup subroutine performs no action.

install
This task controls the installation sequence. The major work is to call other tasks and to save the output to /tmp/rcS.log. If you have any problems during installation, look for errors there. You can find examples of the log files for some hosts in the download directory of the FAI homepage.

partition
Calls setup_harddisk to partition the hard disks. The task writes variable definitions for the root and boot device ($ROOT_PARTITION, $BOOT_PARTITION) to /tmp/disk_var.sh.

mountdisks
Mounts the created partitions according to the created /tmp/fstab file relative to $FAI_ROOT.

extrbase
Extracts the base tar file base.tgz, which is created by make-fai-nfsroot.

mirror
If a local mirror is accessed via NFS when $FAI_DEBMIRROR is defined, this directory will be mounted to $MNTPOINT, which is defined in /etc/fai.conf.

updatebase
Prepares the extracted base system for further installation and updates the list of available packages. Updates the packages to the newest version. Creates fake scripts for some commands inside the new installed system using dpkg-divert(8).

instsoft
Installs the desired software packages using class files in /fai/packages_config.

configure
Calls scripts in /fai/scripts/ for every defined class.

finish
Unmounts the proc filesystem in the new installed system and removes diversions of files (rmdivert).

faiend
Automaticly reboots the install clients or waits for manual input before reboot.

chboot
Changes symbolic link on the install server, which indicates which kernel image to load on the next boot from network card.

savelog
Saves log files to local disk and to the install server.


6.3 The setup routines of the install clients

After the subroutine fai_init has done some basic initialization, the setup continues by calling the task confdir and the task setup. The command bootpc(8) is called and its output is used to define the corresponding global variables which are save in /tmp/bootp.log. This is an example for this log file.

     /tmp/bootp.log:
     
     # --- network device eth0 ---
     SERVER='134.95.9.149'
     IPADDR='134.95.9.200'
     BOOTFILE='/boot/fai/bigfoot'
     NETMASK='255.255.255.0'
     NETWORK='134.95.9.0'
     BROADCAST='134.95.9.255'
     GATEWAYS_1='134.95.9.254'
     GATEWAYS='134.95.9.254'
     ROOT_PATH='/usr/lib/fai/nfsroot'
     DNSSRVS_1='134.95.9.136'
     DNSSRVS_3='134.95.100.208'
     DNSSRVS_4='134.95.140.208'
     DNSSRVS='134.95.9.136 134.95.100.208 134.95.140.208'
     DOMAIN='informatik.uni-koeln.de'
     SEARCH='informatik.uni-koeln.de uni-koeln.de'
     YPSRVR_1='134.95.9.10'
     YPSRVR='134.95.9.10'
     YPDOMAIN='informatik4711.YP'
     TIMESRVS_1='134.95.9.10'
     TIMESRVS='134.95.9.10'
     NTPSRVS_1='134.95.81.172'
     NTPSRVS_2='134.95.140.172'
     NTPSRVS='134.95.81.172 134.95.140.172'
     HOSTNAME='bigfoot'
     T170='kueppers:/usr/local/share/fai'
     T171='sysinfo'
     T171='install'
     T172='createvt sshd'

It's not a bug, if a variable (T171 in the example above) is defined twice. The second definition is created by the host specific entry in /etc/bootptab and supersedes the first one.

The tag T172 is the definition for $FAI_FLAGS. It contains a space separated list of flags. Following flags are known:

verbose
Create verbose output during installation. This should be always the first flag, so consecutive definitions of flags will be verbosely displayed.

debug
Create debug output. No interactive installation is performed. During package installation you have to answer all questions of the postinstall scripts from the console.

sshd
Start the ssh daemon to enable remote logins.

createvt
Create two virtual terminals and execute a bash if ctrl-c is typed in the console terminal. The additional terminals can be accessed by typing Alt-F2 or Alt-F3. Otherwise no terminals are available and typing ctrl-c will reboot the install client. Useful for installation which should not be interruptible.

reboot
Reboot the install client after installation is finished without typing RETURN on the console. Only useful if you can change the boot image or boot device automatically or your assembly robot can remove the boot floppy via remote control. Currently this should only be used when booting from network card and using $TFTPLINK or changing the boot device with the command bootsector.


6.4 The class concept

The idea of using classes in general and using certain files matching a class name for a configuration is adopted from the installation scripts by Casper Dik for Solaris. This technique proved to be very useful for the SUN workstations, so I also use it for the fully automatic installation of Linux. One simple and very efficient feature of Casper's scripts is to call a command with all files, whose file names are also a class. The following loop may implement this function in a shell script:

        for class in $all_classes; do
        if [ -r $config_dir/$class ]; then
           command $config_dir/$class
           # exit, if only the first matching file is needed
        fi
        done

A variation would be to call the command only for the first file that matches a class name. Therefore it is possible to add a new file to the configuration without changing the script. This is because the loop automaticly detects new configurations files that should be used. Unfortunately cfengine does not support this nice feature, so all classes being used in cfengine need also to be specified inside the cfengine scripts. Classes are very important for the fully automatic installation. If a client belongs to class A, we say the class A is defined. A class has no value, it is just defined or undefined. Within scripts, the variable $classes holds a space separated list with the names of all defined classes. Classes determine how the installation is performed. For example, an install client is configured to become a FTP server by default. Mostly a configuration is created by only changing or appending the classes to which a client belongs, making the installation of a new client very easy. Thus no additional information needs to be added to the configuration files if the existing classes suffice your needs. There are different possibilities to define classes:

  1. Some default classes are defined for every host: DEFAULT, LAST and its hostname.
  2. Classes may listed within a file.
  3. Classes may be defined by scripts.

The last option is a very nice feature, since these scripts will define classes automatically. For example, several classes are defined only if certain hardware is identified. We use Perl and shell scripts to define classes. All names of classes, except the hostname, are written in uppercase. They must not contain a hyphen, a hash or a dot, but may contain underscores. A description of all classes can be found in /usr/share/doc/fai/classes_description.txt.

Hostnames should rarely be used for the configuration files in the configuration space. Instead, a class should defined and this class is then added to the host.


6.5 Defining classes

The default task defclass defines the classes DEFAULT, LAST, $HOSTNAME and all classes in the file /fai/class/$HOSTNAME for every hosts. Additionally, all files that are executable and match the shell regular expression S[0-9]*.{sh,pl} are called in alphabetical order. Every output from these scripts is used to define classes. Multiple classes in one line must be space separated. If a hook has written classes to the file /tmp/additional-classes, these classes are also defined. The list of all defined classes is stored in the variable $classes and saved to /tmp/FAI_CLASSES. The list of all classes is transfered to cfengine, so it can use them too. Script S01alias.sh (see below) is used to define classes for groups of hosts. All hosts with prefix ant use all classes in the file anthill. Hosts, which have an IP address in subnet 134.95.9.0 also belongs to class NET_9. All Beowulf nodes with prefix atom except atom00 (master server) will belong to the classes listed in file atoms. Finally this scripts defines the class with the name of the hardware architecture in uppercase letters.

     S01alias.sh:
     
     # all hosts named ant?? are using the classes in file anthill
     case $HOSTNAME in
         ant??) cat anthill ;;
     esac
     
     # the Beowulf cluster; all nodes except the master node atom00
     # use classes from file class/atoms
     case $HOSTNAME in
         atom00) ;;
         atom??) cat atoms ;;
     esac
     
     # if host belongs to class C subnet 134.95.9.0 use class NET_9
     case $IPADDR in
         134.95.9.*) echo NET_9 ;;
     esac
     
     # echo architecture in upper case
     dpkg --print-installation-architecture | tr /a-z/ /A-Z/

Script S07disk.pl can be used to define classes depending on the number of local disks or the size of these scripts[18]. But you can also use a range of partition size in the disk configuration file (in disk_config), so you may not need a class for every different disk size. The script S24nis.sh automatically defines classes corresponding to NIS. The name of the NIS domain (defined via BOOTP or DHCP) will also become a class (only uppercase letters and minus is replaced by underscore). Depending on several partition names, S90partitions.pl defines classes. For eg., if a partition /files/scratch exists, the install client will export this directory via NFS therefore installs a NFS server packages.

The script S05modules.sh does not define any class, but is responsible for loading kernel modules. Kernel modules are important for detecting hardware. This script calls the script $HOSTNAME.mod and all scripts that have the format <classname>.mod and those class names are already defined. Classes, that are used for loading modules must be defined before this script is called. For e.g., if class DEFAULT is defined (this class is always defined) and a file DEFAULT.mod exists, this script is executed. These scripts should contain all command for loading kernel modules:

     DEFAULT.mod:
     
     modprobe parport_probe
     modprobe serial

You can find messages from modprobe in /tmp/dmesg.log and the on the fourth console terminal by pressing Alt-F4.


6.6 Variables in class/*.var

The task defvar defines the variables for the install clients. All global variables can be set in DEFAULT.var. For certain groups of hosts use a class file or for a single host use the file $HOSTNAME.var. Also here, it's useful to study all the examples. Following variables are used in the examples and may be also useful for your installation:

hdparm
Multi line commands to tune the hard disks parameters. They are executed during installation and also create the script /etc/init.d/S61hdparm which tunes the hard disks during boot.

UTC
Set hardware clock to UTC if $UTC=yes. Otherwise set clock to local time. See clock(8) for more information.

time_zone
Is the file relative to /usr/share/zoneinfo/ which indicates your time zone.

FAI_CONSOLEFONT
Is the font, that is loaded during installation by consolechars(8).

FAI_KEYMAP
Defines the keyboard map file in /usr/share/keymaps. You need not specify the complete path, since this file will be located automatically.

kernelimage
The kernel that is installed to the new system. If a Debian package /fai/files/packages/$kernelimage exists, install this kernel package. Otherwise install the package $kernelimage from the Debian mirror. For eg., if kernelimage=kernel-image-2.2.19-idepci this kernel will be installed. To install the a special kernel for host bigfoot, set kernelimage=kernel-image-2.2.19_bigfoot1_i386.deb and this kernel will be installed from /fai/files/packages/.

liloappend
Append parameters for the kernel of the new system (written to /etc/lilo.conf).

moduleslist
Can be a multi line definition. List of modules (including kernel parameters), that are loaded during boot of the new system (written to /etc/modules).

rootpw
The root password for the new system. Additionally, FAI creates an root account with the same password called roott, which uses the tcsh(1).

TFTPLINK
Link to the TFTP kernel image, that boots using the root file system from the local disk.

hserver, bserver
The names of the NFS servers for /home and /usr.

printers
List of printers, for which a spool directory is created. The config scripts does not set up /etc/printcap.


6.7 Hard disk configuration

The format of the hard disk configuration files is described in /usr/share/doc/fai/README.disk_config.gz. The config file /fai/disk_config/CS_KOELN is a generic description for one IDE hard disk, which should fit for most installations. If you can't partition your hard disk using this script [19], use a hook instead. The hook should write the new partition table, create the file systems and create the file /tmp/fstab and /tmp/disk_var.sh, which contains definitions of boot and root partitions.


6.8 Software package configuration

The script install_packages installs the selected software packages. It uses all configuration files in /fai/package_config, which file name is also defined as a class. The syntax is very simple.

     # an example package class
     
     PRELOADRM http://www.location.org/rp8_linux20_libc6_i386_cs1_rpm /root
     
     PACKAGES taskinst
     german science german
     
     PACKAGES install
     adduser netstd ae
     less passwd
     realplayer
     
     PACKAGES remove
     gpm xdm
     
     PACKAGES dselect-upgrade
     ddd                     install
     a2ps                    install

Comments are starting with a hash (#) and are ending at the end of the line. Every command begins with the word PACKAGES followed by a command name. The command name is similar to those of apt-get. Here's the list of supported command names:

hold:
Put a package on hold. This packages will not be handled by dpkg, e.g not upgraded.

install:
Install all packages that are specified in the following lines. If a hyphen is appended to the package name (with no intervening space), the package will be removed, not installed. All package names are checked for misspelling. If a package doesn't exist, its automaticly removed from the list of packages to install.

remove:
Remove all packages that are specified in the following lines. Append a + to the package name, if the package should be installed.

taskinst:
Install all packages belonging to the task that are specified in the following lines using tasksel(1). This works only for Debian 3.0 and later.

dselect-upgrade
Set package selections using the following lines and install or remove the packages specified. These lines must be the output of the commands dpkg --get-selections.

Multiple lines with lists of space separated names of packages follows the commands install and remove. All dependencies are resolved and apt-get is used to perform the installation or removal of packages. The order of the packages is of no matter.

A line, that contains the PRELOADRM commands, downloads a file using wget(1) into a directory before installing the packages. Using the file: URL, this file is copied from $FAI_ROOT to the download directory. For examples the package realplayer needs an archive to install the software, so this archive is downloaded to the directory /root. After installing the packages this file will be removed. If the file shouldn't be removed, use the the command PRELOAD instead.

If you specify a package that does not exists (e.g. you make a typo), the the whole installation of software package will not be started. This could also happen when the command xviddetect(1) does not recognize the video card, because the configuration file SERVER contains following line:

      xserver-`xviddetect -q`

If the video card isn't detected, the software installation tries to install the package xserver-unknown. It will not start because this package doesn't exist. You can test all software package configuration files with the utility chkdebnames, which is available in /usr/share/fai/utils/.

     > chkdebnames stable /usr/local/share/fai/package_config/*


6.9 Scripts in /fai/scripts

The default set of scripts in this directory is only an example. But they should do a reasonable job for your installation. You can edit them or add new scripts to match your local needs.


6.9.1 Shell scripts

Most script are Bourne shell script. Shell scripts are useful, if the configuration task only needs to call some shell commands or create a file from scratch. In order not to write much short script, it's possible to distinguish classes within a script using the command ifclass. For copying files with classes, use the command fcopy(8). If you like to extract an archive using classes, use ftar(8). But now have a look at the scripts and see what they are doing.


6.9.2 Perl scripts

Currently no Perl scripts are used for modifying the system configuration.


6.9.3 Expect scripts

Currently no expect scripts are used for modifying the system configuration.


6.9.4 Cfengine scripts

Cfengine has a rich set of functions to edit existing configuration files, e.g LocateLineMatching, ReplaceAll, InsertLine, AppendIfNoSuchLine, HashCommentLinesContaining. But it can't handle variables, that are undefined. If a variables is undefined, the whole cfengine script will abort. More information can be found in the manual page cfengine(8) or at the cfengine homepage http://www.cfengine.org.


6.10 Changing the boot device

Changing the boot sequence is normally done in the BIOS setup. But you can't change the BIOS from a running Linux system as far as I know. If you know how to perform this, please send me an email. But there's another way of swapping the boot device of a running Linux system.

Change the boot sequence in the BIOS, so the first boot device is the local disk, where the master boot record is located. The second boot device should be set to LAN or floppy disk, depending from which media you boot when the installation process is performed.

After the installation is performed, lilo(8) will write a valid boot sector to the local disk. Since it's the first boot device, the computer will boot the new installed system. If you like to perform an installation again, you have to disable this boot sector using the command bootsector[20] . For more information use:

     # bootsector -h

This is how to set up the a 3Com network card as second boot device, even if the BIOS doesn't support this. Enable LAN as first boot device in the BIOS.

     Boot From LAN First: Enabled
     Boot Sequence      : C only

Then enter the MBA setup of the 3Com network card and change it as follows:

     Default Boot           Local
     Local Boot             Enabled
     Message Timeout        3 Seconds
     Boot Failure Prompt    Wait for timeout
     Boot Failure           Next boot device

This will enable the first IDE hard disk as first boot device. If the boot sector of the hard disk is disabled, the computer will use the network interface as second boot device and boots from it. Maybe the disk partitioning tool can't work on such a disk. So you have to enable the boot sector before you want to partition the disk.


6.11 Hooks

Hooks let you specify functions or programs, that are run at certain steps of the installation process. Before a default task is called, FAI search for existing hooks for this task and executes them. As you might expect, classes are also used when calling hooks. Hooks are executed for every defined class. You only have to create the hook with the name for the desired class and it will be used. If debug is included in $FAI_FLAG the option -d is passed to all hooks, so you can debug your own hooks. If the default task should be skipped, use the subroutine skiptask and a list of default tasks as parameters. The example partition.DISKLESS skips some default tasks.

The directory /fai/hooks/ contains all hooks. The file name of a hook consists of a hook name as a prefix and a class name, chained by a dot. The prefix describes the time when the hook is called, if the class if defined for the install client. For example, the hook partition.DISKLESS is called for every client belonging to the class DISKLESS before the local disks would be partitioned. If it should become a diskless client, this hook can mount remote filesystems via NFS and create a /tmp/fstab. After that, the installation process would not try to partition and format a local hard disk, because a file /tmp/fstab already exists.

A hook of the form hookprefix.classname can't define variables for the installation script, because it's a subprocess. But you can use any binary executable or any script you wrote. Hooks that has the suffix .sh (eg. partition.DEFAULT.sh) must be Bourne shell scripts and are sourced. So it's possible to redefine variables for the installation scripts.

After some basic initialization, all hooks with prefix confdir are called. Since the configuration directory /fai is mounted in the default task confdir, the hooks for this task are the only hooks located in $nfsroot/fai/hooks on the install server. All other hooks are found in /usr/local/share/fai/hooks on the install server. All hooks that are called before classes are defined can only use the following classes: DEFAULT $HOSTNAME LAST. If a hook for class DEFAULT should only be called if no hook for class $HOSTNAME is available, insert these lines to the default hook:

     hookexample.DEFAULT:
     
     #! /bin/sh
     
     # skip DEFAULT hook, if a hook for $HOSTNAME exists
     scriptname=$(basename $0 .DEFAULT)
     [-f /fai/hooks/$scriptname.$HOSTNAME ] && exit
     # here follows the actions for class DEFAULT
     .
     .

Some examples for what hooks could be used:


6.12 Looking for errors

If the client can't successfully boot from the network card, use tcpdump(8) to look for Ethernet packets between the install server and the client. Search also for entries in several log files made by in.tftpd(8) and bootpd(8):

     egrep "tftpd|bootpd" /var/log/*

If the installation process stops or even when it finishes, you can parse all log files for errors using:

     # egrep "no such variable|bad variable|E:|ERROR" *.log

Sometimes the installation seems to stop, but there's only a postinstall script of a software package that requires manual input from the console. Change to another virtual terminal and look which process is running with tools like top(1) and pstree(1). You can add debug to FAI_FLAGS, so the installation process will show all output from the postinst scripts on the console and get its input also from console. Don't hesitate to send an email to the mailing list or to fai@informatik.uni-koeln.de if you have any questions. Sample log files from successful installed computers are available on the FAI homepage.


[ previous ] [ Abstract ] [ Copyright Notice ] [ Contents ] [ next ]
FAI Guide (Fully Automatic Installation)
Version 1.3.1 for FAI version 2.2.3, 15 november 2001
Thomas Lange lange@informatik.uni-koeln.de