The configuration is the collection of information about 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. The following subdirectories are
present and include several files:
debconf(8)
data. The format is the same
that is used by debconf-set-selections(8)
.
nsswitch.conf
are located in
/fai/files/etc/nsswitch.conf
. Note that the contents of the files
directory are not automatically copied to the target machine, rather they must
be explicitly copied by customization scripts using the fcopy(8)
command.
/files/packages/
which can contain local Debian packages. This
directory is referenced by default in
/etc/fai/make-fai-nfsroot.conf
as FAI_LOCAL_REPOSITORY
and will be added to the nfsroot's apt sources by
make-fai-nfsroot(8)
. Note that these packages will not be
automatically installed, but will be available for installation in your
customization scripts using install_packages
or apt-get. For
example, .../DEFAULT/S01
uses the variable $addpackages
and apt-get for installing any packages specified in this variable. In order
to create a valid Packages.gz, which is needed for using this simple
repository, first place all desired .deb files in files/packages
on the install server, then from the files directory execute the following
command:
# cd /usr/local/share/fai/files # dpkg-scanpackages packages /dev/null | \ gzip -9 > packages/Packages.gz
The main installation command fai(8)
uses all these subdirectories
in the order listed except for hooks. The FAI package contains examples for
all these configuration scripts and files in
/usr/share/doc/fai/examples
. Copy the configuration examples 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/doc/fai/examples/simple/* /usr/local/share/fai # chown -R fai /usr/local/share/fai
These files contain simple configuration for some example hosts. Depending on the hostname used, your computer will be configured as follows:
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
/usr/sbin/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 system specific file
[12]. All important tasks of the
installation are called via the subroutine task appended by the
name of the task as an option (e.g. 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(1)
to define classes using scripts and files in
/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 at all files in /tmp/fai/
. You can find
examples of the log files for some hosts in the download directory of the FAI
homepage.
fai(8)
command
line interface, performs a softupdate. See chapter Using FAI for online updates, Section
9.2 for details.
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 creates an 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 Debian system created by
debootstrap(8)
fai-debconf(8)
to set the values for the debconf database.
dpkg-divert(8)
.
/fai/package_config
.
/fai/scripts/
and its subdirectories for every
defined class.
fai-divert
.
error.log
will not be copied to the log server.
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. The command
get-boot-info
is called to get all information from the BOOTP or
DHCP server. This command writes the file /tmp/fai/boot.log
,
which then is sourced to define the corresponding global variables. This is an
example for this log file when using a DHCP server.
# cat /tmp/fai/boot.log netdevices_all="eth0 eth0 eth0" netdevices_up="eth0" netdevices="eth0" BROADCAST='192.168.1.255' DOMAIN='localdomain' DNSSRVS='192.168.1.1' DNSSRVS_1='192.168.1.1' HOSTNAME='demohost' IPADDR='192.168.1.12' NETWORK='192.168.1.0' GATEWAYS='192.168.1.250' GATEWAYS_1='192.168.1.250' SERVER='faiserver' NETMASK='255.255.255.0'
Additional information is passed via the kernel command line or read from
/etc/fai/fai.conf
. When booting with PXE, command line parameters
are created using fai-chboot(8)
. The variable
$FAI_FLAGS contains a space separated list of flags. The 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 client 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 from 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 on the first one) whose file names are also a class. The following loop implements this function in pseudo shell code:
for class in $all_classes; do if [ -r $config_dir/$class ]; then your_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 automatically detects new configuration files that should be used. Unfortunately cfengine does not support this nice feature, so all classes being used in cfengine also need 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 can be configured to become an FTP server by just adding the class FTP to it. 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 for 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. This is because most of the time the configuration data is not specific for one host, but can be shared among several hosts.
The task defclass calls the script fai-class(1)
to define
classes. Therefore, scripts matching [0-9][0-9]* in
/fai/class are executed. Additionally, a file with the hostname
may contain a list of classes. For more information on defining class, read
the manual pages for fai-class(1)
.
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
10-base-classes
(below is a stripped version) is used to define
classes depending on the host name. First this script defines the class with
the name of the hardware architecture in uppercase letters.
# cat 10-base-classes # echo architecture and OS name in upper case. Do NOT remove these two lines uname -s | tr '[:lower:]' '[:upper:]' dpkg --print-installation-architecture | tr /a-z/ /A-Z/ [ -f /boot/RUNNING_FROM_FAICD ] && echo "FAICD" # use a list of classes for our demo machine case $HOSTNAME in demohost) echo "FAIBASE GRUB DHCPC DEMO" ;; gnomehost) echo "FAIBASE GRUB DHCPC DEMO XFREE GNOME";; *) echo "FAIBASE GRUB DHCPC" ;; esac
The script 20-hwdetect.source uses the default Debian commands to
detect hardware and to load some kernel modules. If some specific hardware is
found, it can also define a new class for it. You can find messages from
modprobe in /tmp/fai/kernel.log
and on the fourth console terminal
by pressing Alt-F4.
The task defvar defines the variables for the install client.
Variables are defined by scripts in class/*.var. 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. The following variables are used in the examples and may also be
useful for your installation:
fai-chboot(8)
. If you can't use this command and are not using a
BOOTP server, define it in the script LAST.var
.
consolechars(8)
.
/usr/share/keymaps
and
$FAI/files
. You need not specify the complete path, since this
file will be located automatically.
clock(8)
for more information.
/usr/share/zoneinfo/
which indicates your
time zone.
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/FAIBASE
is a generic description for one hard
disk (IDE or SCSI), which should fit for most installations. If you can't
partition your hard disk using this script [13], use a hook instead. The hook should write the new
partition table, create the file systems and create the files
/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
whose file name matches a defined class. The syntax is very simple.
# an example package class PACKAGES taskinst german PACKAGES aptitude adduser netstd ae less passwd PACKAGES remove gpm xdm PACKAGES aptitude GRUB lilo- grub 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)
. You can also use aptitude
for installing tasks.
aptitude
. This will be the
default in the future and may replace apt-get and taskinst. Aptitude can also
install task packages.
Multiple lines with lists of space separated names of packages follow the PACKAGES lines. All dependencies are resolved. Packages with suffix - (eg. lilo-)will be removed instead of installed. The order of the packages is of no matter.
A line which 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 example 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 command
PRELOAD instead.
It's possible to append a list of class names after the command for apt-get. So this PACKAGE command will only be executed when the corresponding class is defined. So you can combine many small files into the file DEFAULT. WARNING! Use this feature only in the file DEFAULT to keep everything simple. See this file for some examples.
If you specify a package that does not exist 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/doc/fai/examples/utils/
.
> chkdebnames stable /usr/local/share/fai/package_config/*
The default set of scripts in /fai/scripts
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.
The command fai-do-scripts(1)
is called to execute all scripts in
this directory. If a directory with a class name exists, all scripts matching
[0-9][0-9]*
are executed in alphabetical order. So it's possible
to use scripts of different lanuages (shell, cfengine, Perl,..) for one class.
Most scripts are Bourne shell scripts. 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 many short scripts, 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
want 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 which are
undefined. If a variable is undefined, the whole cfengine script will abort.
Study the examples that are included in the fai package. More information can
be found in the manual page cfengine(8)
or at the cfengine
homepage 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.
So, normally the boot sequence of the BIOS will remain unchanged and your
computer should always boot first from its network card and the second boot
device should be the local disk. Then, it will get an install kernel image
from the install server, when an installation should be performed, or we can
tell pxelinux to boot from local disk. This is done using
fai-chboot(8)
. Here is how to set up a 3Com network card as first
boot device. 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 second boot device after the network card. 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 there to remove the floppy disk:
# lilo -R ...
will instruct the FAI floppy 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 which are run at certain steps of
the installation process. Before a default task is called, FAI searches 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 task name as a prefix and a class name, separated by a dot.
The prefix describes the time when the hook is called, if the class is 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 will 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 have the suffix
.source (e.g. partition.DEFAULT.source
) must be
Bourne shell scripts and are sourced. So it's possible to redefine variables
for the installation scripts.
In the first part of fai, 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
.
parted(8)
. See
hooks/partition.IA64
.
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
tftpd(8)
, dhcpd3(8)
or bootpd(8)
:
egrep "tftpd|bootpd|dhcpd" /var/log/*
If the installation process finishes, the hook faiend.LAST
searches all log files for common errors and writes them to the file
error.log
. So, you should first look into this file for errors.
Also the file status.log
give you the exit code of the last
command executed in a script. To be sure, you should look for errors in all
log files.
Sometimes the installation seems to stop, but often 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 to make the installation process
show all output from the postinst scripts on the console and get its input also
from the 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 successfully installed
computers are available on the FAI homepage.
FAI Guide (Fully Automatic Installation)
FAI Guide version 2.5.2, 19 may 2005 for FAI package version 2.8lange@informatik.uni-koeln.de