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 install server in /usr/local/share/fai
and its
subdirectories. This will be mounted by the install clients to
/fai
. It's also possible to receive all the configuration data
from a cvs(1)
repository. Following subdirectories are present
and include several files:
debconf(8)
data. Not yet used.
nsswitch.conf
are located in
/fai/files/etc/nsswich.conf
.
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/templates
. 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
These files contain configuration for some example hosts. Examples are: a cluster of workstations (bigfoot, ant01, ant02,...) and a Beowulf cluster with a master node called nucleus and computing nodes called atom01, atom02,...
/usr
for its NFS clients. Also some daemons are installed and
activated by default.
/usr
and /home
from
bigfoot. Most of the disk space is spend for a scratch partition,
which is exported to a netgroup of hosts.
/usr/local
for its computing nodes. Also some
daemons are installed and activated by default.
/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. All scratch partitions are mounted
on all Beowulf clients via the automounter.
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 !
After the kernel has booted, it mounts the root file system via NFS from the
install server and init(8)
starts the script
/sbin/rcS_fai
. This script 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
and an operating specific file [17] . All important tasks of the
installation are called via the subroutine task 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 and its hooks can be skipped on
demand by using the subroutine skiptask().
Now follows the description of all default tasks.
/fai
or
it is checked out from the corresponding cvs(1)
repository. To
use a cvs repository, you have to set the variables $FAI_CVSROOT,
$FAI_CVSTAG, $FAI_CVSMODULE. For details look a the subroutine
get_fai_cvs()
. After that, 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.
/fai/class
and classes
from /tmp/fai/additional-classes
.
/fai/class/*.var
for every defined class. If a
hook has written some variable definitions to the file
/tmp/fai/additional.var
, this file is also sourced.
/fai/hooks/
$FAI_ACTION exists. So you can easily
define your own actions.
/tmp/target/
partitionname or with regard to a
fstab
file found inside a partition. Log files are stored to the
install server.
/tmp/fai/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.
setup_harddisk
to partition the hard disks. The task writes
variable definitions for the root and boot partition and device
($ROOT_PARTITION, $BOOT_PARTITION, $BOOT_DEVICE) to
/tmp/fai/disk_var.sh
and create a fstab file.
/tmp/fai/fstab
file relative to $FAI_ROOT.
base.tgz
, which consists of all
required packages. This is a snapshot of a basic SDebian system created by
debootstrap(8)
dpkg-divert(8)
.
/fai/packages_config
.
/fai/scripts/
and its subdirectories for every
defined class.
rmalldivert
.
After the subroutine fai_init
has done some basic initialization
(create ramdisk, read fai.conf
and all subroutines definitions,
set path, print copyright notice), the setup continues by calling the task
confdir and the task setup. When using the BOOTP
daemon, the command bootpc(8)
is called and its output is used to
define the corresponding global variables which are save in
/tmp/fai/bootp.log
. This is an example for this log file.
# cat /tmp/fai/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, that 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:
Classes determine which configuration file to choose from a list of available templates. Classes are used in all further tasks of the installation. To determine which config file to use, an install clients searches the list of defined classes and uses all configuration files that match a class name. It's also possible to use only the configuration file with the highest priority since the order of classes define the priority for low to high. There are some predefined classes (DEFAULT, LAST and the hostname), but classes can also be listed in a file or defined dynamically by scripts. So it's easy to define a class depending on the subnet information or on some hardware that is available on the install client.
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 (or ony the first one), 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
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:
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 be defined and then added for a given host.
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,source} 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/fai/additional-classes
, these classes are also defined. The
list of all defined classes is stored in the variable $classes and
saved to /tmp/fai/FAI_CLASSES
. The list of all classes is
transfered to cfengine
, so it can use them too. The 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.
# cat S01alias.sh # echo architecture in upper case dpkg --print-installation-architecture | tr /a-z/ /A-Z/ uname -s | tr '[a-z]' '[A-Z]' # 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
Script S07disk.pl
can be used to define classes depending on the
number of local disks or the size of these disks[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).
If no NIS domain is defined, then only the NONIS class is defined.
Depending on partition names defined in the first matching
disk_config
found, S90partitions.pl
defines
additional classes. For e.g., if a partition /files/scratch
exists, the install client will export this directory via NFS therefore
installs a NFS server packages.
The script S05modules.source
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/fai/dmesg.log
and the
on the fourth console terminal by pressing Alt-F4.
The task defvar defines the variables for the install clients.
Variables are defined by scripts in class/*.var[19]. 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:
/etc/init.d/S61hdparm
which tunes the hard disks during boot.
clock(8)
for more information.
/usr/share/zoneinfo/
which indicates your
time zone.
consolechars(8)
.
/usr/share/keymaps
. You need not
specify the complete path, since this file will be located automatically.
/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.20-idepci
this kernel will be installed. To install the a special kernel for host
bigfoot, set the variable
kernelimage=kernel-image-2.2.20_bigfoot1_i386.deb
and this kernel will be installed from /fai/files/packages/
.
/etc/lilo.conf
).
tcsh(1)
.
/home
and /usr
.
/etc/printcap
.
/fai/files/packages
. This can be used to install
local site specific packages, that can't be accessed using
sources.list(5)
.
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 [20], use a hook instead. The hook should write the new
partition table, create the file systems and create the file
/tmp/fai/fstab
and /tmp/fai/disk_var.sh
, which
contains definitions of boot and root partitions.
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 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:
tasksel(1)
. This works only for Debian 3.0 and later.
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 this package will be removed from
the installation list. You can also 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/*
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.
If a directory with a class name exists, all scripts matching
S[0-9]*
are executed in alphabetical order.
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.
Currently no Perl script is used for modifying the system configuration.
Currently no expect scripts are used for modifying the system configuration.
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 variable 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
.
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
[21] . 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. If booting from a FAI floppy disk, another solution can be used to skip a re-installation if the BIOS is configured to boot from the floppy disk first and you are not here to remove the floppy disk : use a
# lilo -R ...
to instruct the FAI floppy disk lilo to boot from the hard disk
only once (see lilo(8)
). Thus after this first reboot, the FAI
floppy disk can be used for another FAI installation.
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 some default tasks 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/fai/fstab. After that, the installation process would not
try to partition and format a local hard disk, because a file
/tmp/fai/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
.source (eg. partition.DEFAULT.source
) 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:
ssh
in the very beginning to verify that you mounted the
configuration from the correct server and not a possible spoofing host.
/fai/class
.
hooks/partition.DISKLESS
.
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.
lange@informatik.uni-koeln.de