%commondata; ]> FAI Guide (Fully Automatic Installation) <author>Thomas Lange <email>lange@informatik.uni-koeln.de</email> <version>Version &version for FAI version 2.2, &date <abstract> This manual describes the fully automatic installation package for &dgl;. This includes the installation of the package, the planing and creating of the configuration and how to deal with errors. <copyright> <copyrightsummary> Copyright © 2000-2001 Thomas Lange </copyrightsummary> <p> This manual is free software; you may redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. <p> This is distributed in the hope that it will be useful, but <em>without any warranty</em>; without even the implied warranty of merchantability or fitness for a particular purpose. See the GNU General Public License for more details. <p> A copy of the GNU General Public License is available as &file-GPL; in the &dgl distribution or on the World Wide Web at <url id="&url-gpl;" name="the GNU website">. You can also obtain it by writing to the &fsf-addr;. <toc detail="sect2"> <chapt id="intro">Introduction<p> The homepage of FAI is <httpsite>http://www.informatik.uni-koeln.de</httpsite><httppath>/fai</httppath>. There you will find any information about FAI, for e.g. the mailing list archive. The FAI package is available as a Debian package from &faidownload;. It's an official Debian package and is available from all Debian mirrors. Send any bug or comment to <email>fai@informatik.uni-koeln.de</email>. You can also use the Debian bug tracking system (BTS) <httpsite>http://www.debian.org</httpsite><httppath>/Bugs</httppath> for reporting errors. <p> You can access the CVS repository from a bourne shell using the following commands. The login password is empty, so only press return. <example> > CVSROOT=:pserver:anonymous@cvs.debian.org:/cvs/debian-boot > cvs login > cvs co -P fai-kernels > cvs co -P fai </example> You can also use the web interface for the CVS repository at: <httpsite>http://cvs.debian.org/</httpsite><httppath>fai/</httppath> (and <package>fai-kernels</package>). <p> Now read this manual, then enjoy the fully automatic installation and your saved time. <sect id="motivation">Motivation<p> Have you ever performed identical installations of an operating system several times? Would you like to be able to install a Linux cluster with dozens of nodes single handedly? <p> Repeating the same task time and again is boring -- and will surely lead to mistakes. Also a whole lot of time could be saved, if the installation were done automatically. An installation process with manual interaction does not scale. But clusters have the habit of growing over the years. Think long-term rather than plan only just a few months into the future. <p> In 1999, I had to organize an installation of a Linux cluster with one server and 16 clients. Since I had much experience doing automatic installation of Solaris operating system on SUN SPARC hardware, the idea to build an automatic installation for Debian was born. Solaris has an automatic installation feature called JumpStart<footnote> <p> Solaris 8 Advanced Installation Guide at <httpsite>docs.sun.com</httpsite></p> </footnote>. In conjunction with the auto-install scripts from Casper Dik<footnote><p><url id="ftp://ftp.wins.uva.nl:/pub/solaris/auto-install/"></p> </footnote>, I could save a lot of time not only for every new SUN computer, but also for reinstallation of existing workstations. For example, I had to build a temporary LAN with four SUN workstations for a conference, lasting only a few days. I took these workstations out of our normal research network and set up a new installation for the conference. When it was over, I simply integrated the workstation back into the research network, rebooted just once, and after half an hour, everything was up and running as before. The configuration of all workstations was exactly the same as before the conference, because everything was performed by the same installation process. I also use the automatic installation for reinstalling a workstation after a damaged hard disk had been replaced. It took two weeks until I received the new hard disk but only a few minutes after the new disk was installed, the workstation was running as before. And this is why I chose to adapt this technique to a PC cluster running Linux. <sect id="overview">Overview and concepts<p> <p> FAI is a non interactive system to install a &dgl operating system on a single computer or a whole cluster. You can take one or more virgin PC's, turn on the power and after a few minutes Linux is installed, configured and running on the whole cluster, without any interaction necessary. Thus, it's a scalable method for installing and updating a cluster unattended with little effort involved. FAI uses the &dgl; distribution and a collection of shell and perl scripts for the installation process. Changes to the configuration files of the operating system can be made by cfengine, shell, perl and expect scripts. <p> FAI's target group are system administrators how have to install Debian onto one or even hundreds of computers. Because it's a general purpose installation tool, it can be used for installing a Beowulf cluster, a rendering farm or a linux laboratory or a classroom. Also large-scale linux networks with different hardware or different installation requirements are easy to establish using FAI. But don't forget to plan your installation. <ref id="plan"> has some useful hints for this topic. <p> First, some terms used in this manual are described. <taglist> <tag> install server : <item> <p>The host, where the package FAI is installed. It provides several services for all install clients. In the examples of this manual this host is called <tt>kueppers</tt>. <tag>install client : <item> A host, which will be installed using FAI and a configuration from the install server. Also called client for short. In this manual the example hosts are called <tt>bigfoot, ant01, ant02,...</tt></p> </item> <tag> configuration : <item> The details, how the installation of the clients should be performed. This includes information about: <list> <item> <p>Hard disk layout</p> </item> <item> <p>Local filesystems</p> </item> <item> <p>Software packages</p> </item> <item> <p>Keyboard layout, time zone, NIS, X11 configuration, remote filesystems, user accounts, printers ...</p> </item> </list> <tag> nfsroot : <item> A filesystem located on the install server. It's the complete filesystem for the install clients during the installation process. All clients share the same nfsroot, which they mount read only.</item> </taglist> <sect id="work">How does FAI work ?<p> The install client which will be installed using FAI, is booted from floppy disk or via network card. It gets an IP address and boots a linux kernel which mounts its root filesystem via NFS from the install server. After the operating system is running, the FAI startup script performs the automatic installation which doesn't need any interaction. First, the hard disks will be partitioned, filesystems are created and then software packages are installed. After that, the new installed operating system is configured to your local needs using some scripts. Finally the new operating system will be booted from the local disk. <p> The details, of how to install the computer (the configuration), are stored in the configuration space on the install server. Configuration files are shared among groups of computers if they are similar using the class concept. So you need not to create a configuration for every new host. Hence, FAI is a scalable method to install a big cluster with a great number of nodes. <p> FAI can also be used as an network rescue system. You can boot your computer, but it will not perform an installation. Instead it will run a fully functional &dgl without using the local hard disks. Then you can do a remote login and backup or restore a disk partition, check a filesystem, inspect the hardware or do any other task. <sect id="features">Features<p> <list> <item> <p> </p> </item> <item> <p>A fully automated installation can be perfomed</p> </item> <item> <p>Very quick unattended installation</p> </item> <item> <p>Hosts can boot from floppy or from network card </p> </item> <item> <p>BOOTP and DHCP protocol are supported</p> </item> <item> <p>No initial ramdisk is needed, 8MB RAM suffice</p> </item> <item> <p>Runs even on a 386 CPU </p> </item> <item> <p>The installation kernel can use modules</p> </item> <item> <p>Remote login via ssh during installation process possible</p> </item> <item> <p>Two additional virtual terminals available during installation</p> </item> <item> <p>All similar configuration are shared among all install clients</p> </item> <item> <p>Log files are saved on to the installation server</p> </item> <item> <p>Shell, perl, expect and cfengine scripts are supported for the configuration setup</p> </item> <item> <p>Access to a Debian mirror via NFS, FTP or HTTP</p> </item> <item> <p>Easy creation of the common boot floppy</p> </item> <item> <p>Keyboard layout selectable</p> </item> <item> <p>Can be used as a rescue system</p> </item> <item> <p>Tested on SUN SPARC hardware</p> </item> <item> <p>Diskless client support</p> </item> <item> <p>Easily add your own functions via hooks</p> </item> <item> <p>Easily change the default behavior via hooks</p> </item> <item> <p>Lilo and grub support</p> </item> </list> <chapt id="inst">Installing FAI <sect id="requirements">Requirements<p> Following items are required for an installation via FAI. <taglist> <tag>A computer: </tag><item> The computer must have a network interface card and a local harddisk. No floppy disk, CD-ROM, keyboard or graphic card is needed.</item> <tag>BOOTP or DHCP server: </tag><item> <p> The clients need one of these daemons to obtain boot information.<footnote> <p>It's also possible without a server, if all information is put on the boot disk.</p> </footnote> </p> </item> <tag>TFTP server:<item> The TFTP daemon is used for transfering the kernel to the clients. Only needed when booting from network card with a boot PROM.</item> <tag>Client root:<item> A mountable directory which contains the whole filesystem for the install clients during installation. It will be created during setup of the FAI package and is also called <strong>nfsroot</strong>.</item> <tag>Debian mirror:<item> Access to a Debian mirror is needed. A local mirror of all Debian packages is recommended if you install several computers.</item> <tag>Install kernel: <item> A kernel image that supports the network card and mounts its root filesystem via NFS. </item> <tag>Configuration space:<item> A mountable directory which contains the configuration data. </item> </taglist> <p> The TFTP daemon and a NFS server will be enabled automatically when installing the FAI package. Different install kernel images for BOOTP and DHCP are available within the package <package>fai-kernels</package>. All clients must have a network card, which is recognized by the install kernel. <p> <sect id="debian-mirror">How to create a local Debian mirror<p> The script <prgn>mkdebmirror</prgn> <footnote> Available in <p><file>/usr/share/doc/fai/utils/</file>.</p> </footnote> can be used for creating your own local Debian mirror. This script uses the script <prgn>debmirror</prgn><footnote> Available at <httpsite>http://cvs.kitenet.net/</httpsite><httppath>joey-cvs/bin/debmirror</httppath> or at the FAI homepage.</footnote> and <manref name="rsync" section="1">. A partitial Debian mirror only for i386 architecture for Debian 2.2r3 (aka potato) without the source packages needs about 2.4 GB of disk space. <sect id=faisetup> Setting up FAI <p> Before installing FAI, you have to install the package <package>fai-kernels</package>, which contains the install kernels for FAI. <footnote> <p><tt># apt-get install fai</tt> should also work.</p></footnote> <example> kueppers[~]# dpkg -i fai-kernels_&faikernelver;_i386.deb Selecting previously deselected package fai-kernels. (Reading database ... 40562 files and directories currently installed.) Unpacking fai-kernels (from .../lange/fai-kernels_&faikernelver;_i386.deb) ... Setting up fai-kernels (&faikernelver;) ... </example> Get the newest version of FAI and install it using the <prgn>dpkg</prgn> command: <example> kueppers[~]# dpkg -i fai_&faiver;_all.deb Selecting previously deselected package fai. (Reading database ... 39564 files and directories currently installed.) Unpacking fai (from fai_&faiver;_all.deb) ... Setting up fai (&faiver;) ... To set up FAI edit /etc/fai.conf and call fai-setup </example> <p> All definitions for the FAI package (not the configuration data) are defined in &fc;. Since FAI doesn't use <prgn>debconf</prgn> yet, edit this file before calling <prgn>fai-setup</prgn>. These are important variables in &fc;: <taglist> <tag><var>FAI_DEBOOTSTRAP</var></tag> <item> <p>For building the nfsroot there's a new command called <manref name="debootstrap" section="8">, which replaces the use of the <var>FAI_BASETGZ</var> variable. It needs the location of a Debian mirror and the distribution (potato,woody,stable,unstable) for which the basic Debian system should be build. </p> </item> <tag><var>FAI_BASETGZ</var></tag> <item> <p>The location, where the the base file is fetched from. For building the nfsroot, the Debian base system is needed. It's a big tar file (&basetgzsize for &basetgz), which is a minimal collection of all required packages for Debian. If a file &basetgz is already available in <file>/tmp</file> this file will be used instead and no file will be fetched from the defined location. Fetching via ftp or http could take much time, if you do not have a fast connection to your Debian mirror. You can find the current version of this archive in the directory <tt>debian/dists/stable/main/disks-i386/current/</tt> of a Debian mirror.</p> </item> <tag><var>FAI_SOURCES_LIST</var></tag> <item> <p>This multi line string is the definition for <file>sources.list</file> (used by <manref name="apt-get" section="8">), which defines the location and access method of the Debian mirror. If this variable is undefined, the definitions of <file>/etc/apt/sources.list</file> will be used. For more information on the file format see <manref name="sources.list" section="5">. </p> </item> <tag><var>FAI_DEBMIRROR</var></tag> <item> <p> If you have NFS access to your local Debian mirror, specify the remote filesystem. It will be mounted to <var>$MNTPOINT</var> (defined in &fc;). It's not needed if you use acces via FTP or HTTP.</p> </item> <tag><var>KERNELPACKAGE</var></tag> <item> <p> You must specify the software package - build with <manref name="make-kpkg" section="8"> - which includes the default kernel for booting the install clients. The Debian package <package>fai-kernels</package> contains the default install kernels with BOOTP and DHCP support. Do not use the kernel with BOOTP support when you have a DHCP server running in your network and vice versa. This could lead to missing information.</p></item> <tag> <var>NFSROOT_PACKAGES</var></tag> <item> <p> Contains a list of additional software package, that will be added to nfsroot.</p></item> </taglist> <p> The variables <var>FAI_SOURCES_LIST</var> and <var>FAI_DEBMIRROR</var> are used by the install server and also by the clients. If your install server has multiple network card and different host names for each card (as for a Beowulf server), use the install server name which is known by the install clients.<p> FAI uses <manref name="apt-get" section="8"> to create the nfsroot filesystem in <file>/usr/lib/fai/nfsroot</file>, which needs about &nfsrootsize of free disk space. Before setting up FAI, you should get the program <prgn>imggen</prgn>,<footnote>Available at the download page <httpsite>http://www.ltsp.org</httpsite> or from the FAI download page &faidownload;.</footnote> if you like to boot from a 3Com network card. This executable converts netboot images created by <manref name="mknbi-linux" section="8">, so they can be booted by network cards from 3Com. Put that executable in your path (e.g. <file>/usr/local/bin</file>). After editing &fc; call <prgn>fai-setup</prgn>. <example> kueppers[~]# fai-setup Adding system user fai... Stopping Name Service Cache Daemon: nscd. Adding new user fai (100) with group nogroup. Starting Name Service Cache Daemon: nscd. Creating home directory /home/fai. /home/fai/.rhosts created. User account fai created. Creating FAI nfsroot can take a long time and will need more than 100MB disk space in /usr/lib/fai/nfsroot. Unpacking /tmp/base2_2.tgz Upgrading /usr/lib/fai/nfsroot Adding additional packages to /usr/lib/fai/nfsroot: perl-5.005 dhcp-client file rdate cfengine bootpc wget rsh-client less dump ext2resize raidtools2 strace expect5.31 hdparm parted dnsutils grub ssh grep: /etc/ssh/sshd_config: No such file or directory grep: /etc/ssh/sshd_config: No such file or directory Not starting OpenBSD Secure Shell server (/etc/ssh/NOSERVER) make-fai-nfsroot finished. Stopping NFS kernel daemon: mountd nfsd. Unexporting directories for NFS kernel daemon...done. Starting NFS kernel daemon: nfsd mountd. Exporting directories for NFS kernel daemon...done. Kernel image file name = /usr/lib/fai/nfsroot/boot/vmlinuz-&kver; Output file name = /boot/fai/installimage Kernel command line = "auto rw root=/dev/nfs nfsroot=kernel nfsaddrs=kernel" Image Creator for MBA ROMs v1.00 Usage: imggen [OPTION] inputfile outputfile -a, Add 3Com MBA/BootWare support -r, Remove 3Com MBA/BootWare support from image file -i, Show information on an image -h, Help screen In filename: /boot/fai/installimage Out filename: /boot/fai/installimage_3com Adding MBA support... MBA support has been succesfully added You have no FAI configuration. Copy FAI template files with: cp -a /usr/share/fai/templates/* /usr/local/share/fai Then change the configuration files to meet your local needs. FAI setup finished. </example> <p> The setup routine adds lines to <file>/etc/exports</file> to export some directories to all hosts that belong to the netgroup <em>faiclients</em>. All install clients must belog to this netgroup, in order to mount these directories succesfully. Netgroups are defined in <file>/etc/netgroup</file> or in the corresponding NIS map. An example for the netgroup file can be found in <file>/usr/share/doc/fai/examples/etc/netgroup</file>. For more information, read the manual pages <manref name="netgroup" section="5"> and the NIS HOWTO. After changing the netgroups , the NFS server has to reload its configuration. Use one of the following commands, depending on which NFS server you are using: <example> kueppers[~]# /etc/init.d/nfs-kernel-server reload kueppers[~]# /etc/init.d/nfs-server reload </example> <p> The setup also creates the account <tt>fai</tt> ($LOGUSER). The log files of all install clients are saved to the home directory of this account. If you boot from network card, you should change the primary group of this account, so this account has write permissions to <file>/boot/fai</file> in order to change symbolic links to the kernel image, that is booted by a client. See also variable <var>TFTPLINK</var> in <file>class/DEFAULT.var</file>. <p> After that, FAI is installed successfully on your server, but has no configuration for the install clients. Start with the templates from <tt> /usr/share/fai/templates</tt> using the copy command above and read <ref id="config">. Before you can set up a DHCP or BOOTP daemon, you should collect some network information of all your install clients. This is described in section <ref id="bootfloppy">. <p> When you make changes to &fc; or want to install a new kernel to nfsroot, the nfsroot has to be rebuild by calling <prgn>make-fai-nfsroot</prgn>. <sect1 id=troublefaisetup> Troubleshooting set up<p> The set up of FAI adds the FAI account, exports file systems and calls <prgn>make-fai-nfsroot</prgn>. If you call <tt>make-fai-nfsroot -v</tt> you will see more messages. When using a local Debian mirror it's important, that the install server can mounted this directory via NFS. If this mount fails, check <file>/etc/exports</file> and <file>/etc/netgroup</file>. An example can be found in <file>/usr/share/doc/fai/examples/etc/netgroup</file>. <chapt id="booting">Preparing booting <p> Before booting for the first time, you have to choose which medium you use for booting. You can use the boot floppy or configure the computer to boot via network card using a boot PROM, which is much smarter. <sect id="nicboot">Booting from 3Com network card with boot PROM <p> If you have a 3Com network card that is equipped with a boot ROM by Lanworks Technologie or already includes the DynamicAccess Managed PC Boot Agent (MBA) software<footnote> <p><httpsite>http://support.3com.com/</httpsite> <httppath>infodeli/tools/nic/mba.htm</httppath></p></footnote>, you can enter the MBA setup by typing <tt>Ctrl+Alt+B</tt> during boot. The setup will look like this: <example> Managed PC Boot Agent (MBA) v4.00 (C) Copyright 1999 Lanworks Technologies Co. a subsidiary of 3Com Corporation All rights reserved. =============================================================================== Configuration Boot Method: TCP/IP Protocol: BOOTP Default Boot: Network Local Boot: Enabled Config Message: Enabled Message Timeout: 3 Seconds Boot Failure Prompt: Wait for key =============================================================================== Use cursor keys to edit: Up/Down change field, Left/Right change value ESC to quit, F9 restore previous settings, F10 to save </example> Set the boot method to <tt>TCP/IP</tt> and the protocol to either <tt>BOOTP</tt> or <tt>DHCP</tt>. I prefer BOOTP because the daemon automaticly reloads its configuration when it's changed. Make a symbolic link from the hostname of your client to the appropriate kernel image in <file>/boot/fai</file>. In the following example the host is called <tt>bigfoot</tt>. The file <file>installimage_3com</file> is created by <prgn>imggen</prgn> and suitable for booting 3Com network cards. <example> kueppers[~]# cd /boot/fai kueppers[~]# ln -s installimage_3com bigfoot </example> <sect id="pxeboot">Booting from network card with a PXE conforming boot ROM <p> Some network cards (e.g. Intel EtherExpress PRO 100) have a fixed configuration for booting using the PXE protocol. This requires a PXE Linux boot loader an a special version of the <tt>TFTP</tt> daemon. See <file>/usr/share/doc/syslinux/pxelinux.doc.gz</file> for more information, how to boot such an environment. There are also some mails in the FAI mailing list archive concerning this topic. <sect id="bootfloppy">Creating a boot floppy <p> If your network card can't boot itself, you have to boot via floppy. Use the command <prgn>make-fai-bootfloppy</prgn> to create the boot floppy. Since there's no client specific information on this floppy, it's suitable for all your install clients. You can also specify additional kernel parameters for this boot floppy, if desired. There's more help available. <example># make-fai-bootfloppy -h</example> If you have no BOOTP or DHCP server, supply the network configuration as kernel parameters. <footnote> The format is: <example>ip=<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf> </example>For additional information see <file>/usr/src/linux/Documentation/nfsroot.txt</file> in the kernel sources. </footnote> <sect id="mac">Collecting Ethernet addresses<p> Now it's time to boot your install clients for the first time. They will fail to boot completely, because no BOOTP or DHCP daemon is running yet or recognizes the hosts. But you can use this first boot attempt to easily collect all Ethernet addresses of the network cards. <p> You have to collect all Ethernet (MAC) addresses of the install clients and assign a hostname and IP address to each client. To collect all MAC addresses, now boot all your install clients. While the install clients are booting, they send broadcast packets to the LAN. You can log the MAC addresses of these hosts, if following command is running simultaneously on the server: <example># tcpdump -qte broadcast and port bootpc >/tmp/mac.lis</example> <p> After the hosts has been sent some broadcast packets (they will fail to boot because <prgn>bootpd</prgn> isn't running or does not recognize the MAC address yet) abort <prgn>tcpdump</prgn> by typing <tt>ctrl-c</tt>. You get a list of all unique MAC addresses with these commands: <example># perl -ane 'print "\U$F[0]\n"' /tmp/mac.lis|sort|uniq</example> After that, you only have to assign these MAC addresses to hostnames and IP addresses (<file>/etc/ethers</file> and <file>/etc/hosts</file> or corresponding NIS maps). With these information you can configure your <prgn>BOOTP</prgn> or <prgn>DHCP</prgn> daemon (see the section <ref id="bootptab">). I recommend to write the MAC addresses (last three bytes will suffice if you have network cards from the same vendor) and the hostname in the front of each chassis. <sect id=bootptab>Configuration of the BOOTP daemon<p> An example configuration for the BOOTP daemon is included in FAI. If you have no <file>/etc/bootptab</file> file you can use <file>/usr/share/doc/fai/examples/etc/bootptab</file> as template. <example> # /etc/bootptab example for FAI # replace FAISERVER with the name of your install server .faiglobal:\ :ms=1024:\ :hd=/boot/fai:\ :hn:bs=auto:\ :rp=/usr/lib/fai/nfsroot: # rp: $NFSROOT # your local values # # sa: your tftp server (install server) # ts: your timeserver (time enabled in inetd.conf) # these are optional # ys: NIS server # yd: NIS domainname # nt: list of NTP servers .failocal:\ :tc=.faiglobal:\ :sa=FAISERVER:\ :ts=FAISERVER:\ :T170="FAISERVER:/usr/local/share/fai":\ :T171="sysinfo":\ :sm=255.255.255.0:\ :gw=134.95.9.254:\ :dn=informatik.uni-koeln.de:\ :ds=134.95.9.136,134.95.100.209,134.95.100.208,134.95.140.208:\ :ys=rubens:yd=informatik4711.YP:\ :nt=time.rrz.uni-koeln.de,time2.rrz.uni-koeln.de: # now one entry for each install client bigfoot:ha=0x00105A240012:bf=bigfoot:tc=.failocal:T171="sysinfo":T172="verbose sshd createvt debug ": ant01:ha=0x00105A000000:bf=ant01:tc=.failocal:T172="sshd": </example> Insert one line for each install client at the end of this file as done for <em>bigfoot</em> and <em>ant01</em>. Replace the string <tt>FAISERVER</tt> with the name of your install server. If the install server has multiple network cards and host names, use the host name of the network card to which the install clients are connected. Then adjust the other network tags (<tt>sm, gw, dn, ds</tt>) to your local needs. <taglist> <tag>sm</tag> <item> <p>: Subnet mask</p> </item> <tag>gw</tag> <item> <p>: Default gateway / router</p> </item> <tag>dn</tag> <item> <p>: Domain name</p> </item> <tag>ds</tag> <item> <p>: List of DNS server </p> </item> <tag>T170</tag> <item> <p>Location of the FAI configuration directory </p> </item> <tag>T171</tag> <item> <p>FAI_ACTION</p> </item> <tag>T172</tag> <item> <p>List of FAI_FLAGS; e.g. verbose, debug, reboot, createvt, sshd</p> </item> <tag>T173</tag> <item> <p>Reserved for future use</p> </item> <tag>T174</tag> <item> <p>Reserved for backup devices and backup options; NOT YET USED </p> </item> </taglist> The tags for NIS and time servers (<tt>yp, yd, nt</tt>) are optional. Tags with prefix <tt>T</tt> (starting from T170) are generic tags which are used to transfer some FAI specific data to the clients. <strong> It is important, that T171 (equivalent to variable <var>FAI_ACTION</var><footnote> <p>Theses names are used in the main installation script <file>rcS_fai</file>. The configuration files for DHCP and BOOTP daemons use other names. Example: <var>FAI_ACTION</var> is equal to <tt>T171</tt> in bootptab or <tt>option-171</tt> in dhcp.conf. </p> </footnote>. is set to <tt>sysinfo</tt> !</strong> Later you can set it to <tt>install</tt>, in order to start the automatic installation. For more information on all tags see <manref name="bootptab" section="5">. <p> When you have created your <file>bootptab</file> file, you have to enable the BOOTP daemon once. It's installed but Debian does not enable it by default. Edit <file>/etc/inetd.conf</file> and remove the comment (the hash) in the line containing <tt>#bootps</tt>. Then tell <prgn>inetd</prgn> to reload its configuration. <example># /etc/init.d/inetd reload</example> I recommend to use the BOOTP daemon and protocol for booting because it automatically reloads the configuration file if any changes are made to it. The daemon for DHCP must always be manually restarted after changes to the configuration file are made <footnote> <p>If you can't use one of these, there's also the possibility to supply all information via a file or compile them into the kernel, but it's easier to use a daemon. </p> </footnote>. Now it's time to boot all install clients again! FAI can perform several actions when the client is booting. This action is defined in the variable <var>FAI_ACTION</var> Be very carefully if you set <var>FAI_ACTION </var> to <em>install</em>. This can destroy all your data on the install client, indeed most time it should do this ;-). It's recommended to change this only on a per client base in the BOOTP configuration. Do not change it in the section <tt>.failocal</tt> in <file>/etc/bootptab</file>, which is a definition for all clients. <sect1 id=troublebootp>Troubleshooting BOOTP daemon<p> The BOOTP daemon can also be started in debug modus: <example># bootpd -d7</example> <sect id="bootdhcp">Configuration of the DHCP daemon <p> An example for <manref name="dhcp.conf" section="5"> is available in <file>/usr/share/doc/fai/examples/etc</file>. Start using this example and look at all options used therein. If you make any changes to this configuration, you must restart the daemon. <sect id="bootmesg">Boot messages <p> These are the messages, when booting from floppy. <example> LILO Loading FAI-BOOTP. Uncompressing Linux... OK, booting the Kernel. Linux version &kver; (root@kueppers) (gcc version 2.95.2 20000220 . . . </example> The rest of the boot message will be equal to those when booting from network card. When booting from network card you will see: <example> BOOTP. TFTP.... Linux Net Boot Image Loader Version 0.8.1 (netboot) . Uncompressing Linux... OK, booting the Kernel. Linux version &kver; (root@kueppers) (gcc version 2.95.2 20000220 . . . Sending BOOTP requests ..... OK IP-Config: Got BOOTP answer from 134.95.9.149 IP-Config: Complete: device=eth0, addr=134.95.9.200, mask=255.255.255.0, gw=134.95.9.254, host=ant01, domain=informatik.uni-koeln.de, nis-domain=informatik4711.YP, bootserver=134.95.9.149, rootserver=134.95.9.149, rootpath=/usr/lib/fai/nfsroot . . ------------------------------------------------------ FAI &faiver;, &faiverdate; Fully Automatic Installation for Debian GNU/Linux Copyright (c) 1999-2001, Thomas Lange lange@informatik.uni-koeln.de ------------------------------------------------------ . . /fai mounted from kueppers:/usr/local/share/fai FAI_ACTION: sysinfo . . Press <RETURN> to reboot or ctrl-c to execute a shell </example> When the copyright message is shown, the install client has mounted the nfsroot<footnote> <p><file>/usr/lib/fai/nfsroot</file> from the install server</p> </footnote> to the clients root directory <file>/</file>. This is the whole filesystem for the client at this moment. When <file>/fai</file> is mounted, the configuration data from the install server is available on the client. <p> Following error message indicates, that your install client doesn't get an answer from a BOOTP server. Check your cables or start the <manref name="bootpd" section="8"> daemon with the debug flag enabled. <example> Sending BOOTP requests ........ timed out! IP-Config: Retrying forever (NFS root)... </example> If you get the following error message, the install kernel has no driver compiled in for your network card. <example> IP-Config: No network devices available Partition check: hda: hda1 hda2 < hda5 hda6 hda7 hda8 > Root-NFS: No NFS server available, giving up. VFS: Unable to mount root fs via NFS, trying floppy. VFS: Insert root floppy and press ENTER </example> Then you have to compile a new kernel has a driver compiled in, which supports your network card. This driver must no be a kernel module. To compile the new kernel, start using the default kernel configuration of FAI. <example> kueppers# cd /usr/src/kernel-source-&kver; kueppers# cp /usr/lib/fai/nfsroot/boot/config-&kver; .config kueppers# make menuconfig </example> Call <prgn>make menuconfig</prgn> and add the driver in menu <tt>Network device support/Ethernet</tt> which supports your network card. Then create a Debian package using <manref name="make-kpkg" section="8">: <example> kueppers# make-kpkg clean kueppers# make-kpkg --revision BOOTP2 kernel-image </example> This command creates the file <file>/usr/src/kernel-image-&kver;_BOOTP2_i386.deb</file>. Adjust the variable <var>KERNELPACKAGE</var> in &fc; and rebuild the nfsroot. <example> kueppers# make-fai-nfsroot </example> After that, you have to create a new boot floppy. Now your network card should be recognized and the install kernel should mount the nfsroot successfully. More information how to compile an install kernel can be found in the <file>README</file> of the package <tt>fai-kernels</tt>. <sect id="sysinfo">Collecting other system information <p> Now the clients have booted with <var>FAI_ACTION</var> set to <em>sysinfo</em>. Type <tt>ctrl-c</tt> to get a shell or use <tt>Alt-F2</tt> or <tt>Alt-F3</tt> and you will get another console terminal, if you have added <tt>createvt</tt> to <var>FAI_FLAGS</var>. Remote login is available via the secure shell, if <tt>sshd</tt> if added to <var>FAI_FLAGS</var>. The encrypted password is set with variable <var>FAI_ROOTPW</var> in &fc; and is default to "fai". You can also log in without a password when using <var> SSH_IDENTITY</var>. To log in from your server to the install client (for eg. named ant01) use: <example>> ssh -l root ant01 Warning: Permanently added 'ant01,134.95.9.200' to the list of known hosts. root@ant01's password: </example> You have now a running Linux system on the install client without using the local hard disk. Use this as a rescue system, if your local disk is damaged or the computer can't boot properly from hard disk. You will get a shell and can execute various commands (dmesg, lsmod, df, lspci, ...). Look at the log file in <file>/tmp</file>. There you can find much information about the boot process. All log files from <file>/tmp </file> are also written to the install server into the directory <tt>~fai/ant01/sysinfo/</tt><footnote>More general: <tt>~$LOGUSER/$HOSTNAME/$FAI_ACTION/</tt>. Examples of log files can be found on the FAI homepage. </footnote> <p> A very nice feature is, that FAI mounts all filesystems it finds on the local disks read only. It also tells you on which partition a file <file>/etc/fstab</file> exists. When only one file is found, the partitions are mounted according to this information. Here's an example: <example> ant01:~# df Filesystem 1k-blocks Used Available Use% Mounted on /dev/root 1249132 855648 330032 72% / /dev/ram0 3963 36 3927 1% /tmp kueppers:/usr/local/share/fai 1249132 855648 330032 72% /fai /dev/hda1 54447 9859 41777 19% /tmp/target /dev/hda10 1153576 20 1141992 0% /tmp/target/files/install /dev/hda9 711540 20 711520 0% /tmp/target/home /dev/hda8 303336 13 300191 0% /tmp/target/tmp /dev/hda7 1517948 98252 1342588 7% /tmp/target/usr /dev/hda6 202225 8834 182949 5% /tmp/target/var </example> <strong>This method can be used as an rescue environment !</strong> In future it will be possible to make backups or restore data to existing filesystems. If you need a filesystem with read-write access use the <prgn>rwmount</prgn> command: <example>ant01:~# rwmount /tmp/target/home</example> <sect id=checkbootp>Checking parameters from BOOTP and DHCP servers<p> If the install client boots with action <em>sysinfo</em>, you can also check if all information from the BOOTP or DHCP daemons are received correctly. If the kernel uses BOOTP requests to receive data, these information will be written to <file>/tmp/bootp.log</file>. If the kernel support the DHCP protocol all is written to <file>/tmp/dhcp.log</file>. And example for the result of a BOOTP requests can be found in <ref id="s1">. <sect id=reboot>Rebooting the computer<p> At any time you can reboot the computer using the command <prgn>faireboot</prgn>, also if logged in from remote. If the installation hasn't finished, use <tt>faireboot -s</tt>, so the log files are also copied to the install server. <chapt id=instprocess>Overview of the installation sequence<p> Following steps are performed during an installation after the linux kernel has booted on the install clients. <enumlist> <item> <p>Set up FAI </p> </item> <item> <p>Load kernel modules</p> </item> <item> <p>Define classes</p> </item> <item> <p>Define variables</p> </item> <item> <p>Partition local disks</p> </item> <item> <p>Create and mount local filesystems</p> </item> <item> <p>Install software packages</p> </item> <item> <p>Call site specific configuration scripts</p> </item> <item> <p>Save log files</p> </item> <item> <p>Reboot the new installed system</p> </item> </enumlist> You can also define additional programs or scripts, that will be run on particular occasions. They are called <tt>hooks</tt>. Hooks can add aditional functions to the installation process or replace the default subtasks of FAI. So it's very easy to customize the whole installation process. Hooks are explained in detail in <ref id="hooks">. <p> The installation time is mainly determined by the amount of software that will be installed. A dual Pentium II, 400 MHZ with 128 MB RAM and a 10 Mbit network card needs about 11 min when installing 520 MB of software to local disk. An installation with 90 MB software (a dataless client) only needs two minutes. The checking for bad blocks on a 4 GB partition needs additional 6 minutes. Using a 100 Mbit LAN does not decrease the installation time considerable, so the network will not be the bottleneck when installing several clients simultaneously. <sect id=isetup>Set up FAI<p> After the install client has booted, only the script <file>/sbin/rcS_fai</file><footnote><p>Since the root filesystem on the clients is mounted via NFS, <prgn>rcS_fai</prgn> is located in <file>/usr/lib/fai/nfsroot/sbin</file> on the install server.</p> </footnote> is executed. This is the main script, that controls the sequence of tasks for FAI. No other scripts in <file>/etc/init.d/</file> are executed. <p> A ramdisk is created and mounted to <file>/tmp</file>, which is the only writable directory, until local filesystems are mounted. Additional parameters are received from the BOOTP or DHCP daemon and the configuration space if mounted via NFS from the install server to <file>/fai</file>. The setup is finished after additional virtual terminals are created and the secure shell daemon for remote access is started on demand. <sect id=iclass>Defining classes, variables and loading kernel modules<p> Now scripts in <file>/fai/class/</file> are executed to define classes and variables that are later used in the site specific configuration scripts. All scripts matching <tt>S[0-9]*.{sh,pl}</tt> are executed in alphabetical order. Every word that these scripts print to the standard output are interpreted as class names. These classes are defined for this install client. You can also say this client belongs to these classes. A class is defined or undefined and has no value. Only defined classes are of interest for an install client. A description of all classes can be found in <file>/usr/share/doc/fai/classes_description.txt</file>. It is advisable to document the job a new class performs. Then, this documentation is the base for composing a configuration from classes. <p> The scripts <prgn>S05modules.sh</prgn> loads kernel modules on demand. So you can use classes when loading modules and also define more classes after the kernel has loaded modules and recognized new hardware. A complete description of all these scripts can be found in <ref id="cscripts">. <p> After defining the classes, every file matching <tt>*.var</tt>, which prefix is a defined class, is executed to define variables. <sect id=ipartition>Partitioning local disks, creating filesystems<p> Then exactly one disk configuration file from <file>/fai/disk_config</file> is selected using classes. It's the description how all the local disks will be partitioned, which filesystems should be created and how they are mounted. It's also possible to preserve the disk layout or to preserve the data on a partition. It's done by the command <prgn>setup_harddisks</prgn>, which uses <prgn>sfdisk</prgn> for partitioning. The format of the configuration file is described in <file>/usr/share/doc/fai/README.disk_config</file>. <p> During the installation process all local filesystems are mounted relative to <file>/tmp/target</file> . So, for e.g. <file>/tmp/target/home</file> will become <file>/home</file> in the new installed system. <sect id=ipackages>Installing software packages<p> When local filesystems are created, they are all empty (except for preserved partitions). Now the Debian base system and all requested software packages are installed on the new filesystems. First the base archive is unpacked, then the command <prgn>install_packages</prgn> installs all packages using <manref name="apt-get" section="8"> without any manually interaction needed. If a packages requires an other packages it resolves this dependency by installing the required package. <p> Classes are also used when selecting the configuration files in <file>/fai/package_config/</file> for software installation. The format of the configuration files is described in <ref id="packageconfig">. <sect id=icscripts>Site specific configuration<p> After all requested software packages are installed, the system is nearly ready to go. But not all default configurations of the software packages will meet your site specific needs. So you can call arbitrary scripts, which adjust the system configuration. Therefore scripts, that match a class name in <file>/fai/scripts</file><footnote> <p><file>/usr/local/share/fai/scripts</file> on the install server.</p> </footnote> will be executed. FAI comes with some templates for these scripts, but you can write your own bourne, bash, perl, cfengine or expect scripts. <p> These important scripts are described in detail in <ref id="cscripts">. <sect id=isavelog>Save log files<p> When all installation tasks are finished, the log files are written to <tt>/var/log/fai/$HOSTNAME/install/</tt> <footnote> <p><file>/var/log/fai/localhost/install/</file> is a link to this directory.</p> </footnote> on the new system and to the a account on the install server, if <var>$LOGUSER</var> is defined in &fc;. <sect id=ireboot>Reboot the new installed system<p> At least the system is automatically rebooted if the flag <var>reboot</var> is set <footnote><p>Add "reboot" to <var>FAI_FLAGS</var> (= T172).</p> </footnote>. This is only useful if booting from network card or if you can change the boot device using the command <prgn>bootsector</prgn>. Otherwise, you have to remove the floppy disk and type return or call <prgn>faireboot</prgn> from a remote login. You must change the boot device, to boot the new installed system otherwise the installation would be performed again. Read <ref id="changeboot"> how to change the boot device. <chapt id=plan>How to plan your installation<p> <em>Plan your installation, and FAI installs your plans.</em> <p> Before starting your installation, you should spend much time in planing your installation. When you're happy with your installation concept, FAI can do all the boring, repeating tasks to put your plans into practice. FAI can't do good installations, if your concept is imperfect or lacks some important details. Start planing the installations by answering yourself following questions: <taglist> <tag></tag> <item> <p>Will I create a Beowulf cluster, or do I have multiple workstations, each only used by a single user ?</p> </item> <tag></tag> <item> <p>How does my LAN topology looks like ?</p> </item> <tag></tag> <item> <p>Do I have uniform hardware ?</p> </item> <tag></tag> <item> <p>Will the hardware stay uniform in the future ?</p> </item> <tag></tag> <item> <p>How should the hosts be named ?</p> </item> <tag></tag> <item> <p>How should the local harddisks be partitioned ?</p> </item> <tag></tag> <item> <p>Which software should be installed ?</p> </item> <tag></tag> <item> <p>Which daemons should be started, and how should the configuration for these looks like ?</p> </item> <tag></tag> <item> <p>Which remote filesystems should be mounted ?</p> </item> <tag></tag> <item> <p>Does the hardware needs a special kernel ?</p> </item> <tag></tag> <item> <p></p> </item> </taglist> You have also to think about user accounts, printing, mail, cron jobs, graphic cards, dual boot, NIS, NTP, timezone, keyboard layout, exporting and mounting directories via NFS and many other things. So, there's a lot to do before starting an installation. And remember that knowledge is power, and it's up to you to use it. Installation and administration is a process, not a product. FAI can't do things you don't tell it to do. <p> But you need not to start from scratch. Look at all files and scripts in the configuration space. There are a lot of things you can use for your own installation. A good paper with more aspects of building an infrastructure is <url id="http://www.infrastructures.org/papers/bootstrap/"> "Bootstrapping an Infrastructure". <chapt id=config>Installation details<p> <sect id=c3>The configuration space<p> 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 <file>/usr/local/share/fai</file> and its subdirectories. This will be mounted by the install clients to <file>/fai</file>. Following subdirectories are available: <taglist> <tag><tt>class/</tt></tag> <item> <p>Scripts and files to define classes and variables and to load kernel modules.</p> </item> <tag><tt>disk_config/</tt></tag> <item> <p>Configuration files for disk partitioning and file system creation.</p> </item> <tag><tt>package_config/</tt></tag> <item> <p>File with lists of software packages to be installed or removed.</p> </item> <tag><tt>scripts/</tt></tag> <item> <p>Script for customization.</p> </item> <tag><tt>files/</tt></tag> <item> <p>Files used by customization scripts, eg. user created kernel packages.</p> </item> <tag><tt>hooks/</tt></tag> <item> <p>Hooks are user defined programs or scripts, which are called during the installation process. </taglist> The main installation script <prgn>rcS_fai</prgn> uses these subdirectories in the order listed. 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. <example> # cp -a /usr/share/fai/templates/* /usr/local/share/fai # chown -R fai /usr/local/share/fai </example> All these files contain configuration for some example hosts. A cluster of workstations (<em>bigfoot, ant01, ant02,...</em>) and a Beowulf cluster with a master node called <em>nucleus</em> and computing nodes <em>atom01, atom02,...</em> are included. <taglist> <tag>bigfoot</tag> <item> <p>This is a server with much software. It provides the home directory <file>/usr</file> for its NFS clients. Also some daemons are installed and activated by default.</p> </item> <tag>ant01,...</tag> <item> <p>These dataless clients mount <file>/usr</file> and <file>/home</file> from <em>bigfoot</em>. Most of the disk space is spend for a scratch partition, which is exported to a netgroup of hosts.</p> </item> <tag>nucleus</tag> <item> <p>This Beowulf master node is a server with much software. It provides the home directory <file>/usr/local</file> for its computing nodes. Also some daemons are installed and activated by default.</p> </item> <tag>atom01,...</tag> <item> <p>These clients mount <file>/usr/local</file> and <file>/home</file> from <em>nucleus</em>. Most of the disk space is spend for a scratch partition, which is exported to a netgroup of hosts.</p> </item> </taglist> 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 ! <sect id=tasks>The default tasks<p> After the kernel has booted, it mounts the root file system via NFS from the install server and init starts the script <file>/sbin/rcS_fai</file>. This is the script which controls the whole sequence of the installation. No other scripts in <file>/etc/init.d</file> are used. <p> The installation script <file>rcS_fai</file> uses many subroutines, which are defined in <file>/usr/share/fai/subroutines</file>. All important tasks of the installation are called via the call <tt>task <em>name</em></tt>. The subroutine <tt>task</tt> calls hooks with prefix <em>name</em> if available and then calls the default task (defined as <tt>task_<em>name</em></tt> in <file>subroutines</file>). The default task can be skiped on demand. This is the description of all default tasks. <taglist> <tag>confdir</tag> <item><p>The kernel append parameters define variables, the syslog and kernel log daemon are started. The list of network devices is stored in <var>$netdevices</var>. 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 <file>/fai</file>. The file <file>/fai/hooks/subroutines</file> is sourced, if it exists. Using this file, you can define your own subroutines or override the definition of FAI's subroutines. <tag>setup</tag> <item><p>This task sets the system time, all <tt>FAI_FLAGS</tt> 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 <var>$disklist</var> and <var>$device_size</var> contains a list of devices and their size. <tag>action</tag> <item><p>Depending on the value of <var>$FAI_ACTION</var> this subroutine decides which action FAI should perform. The default actions are: <tt>sysinfo, install, backup</tt>. A user defined action is called, if a file <file>/fai/hooks/</file><tt>$FAI_ACTION</tt> exists. <tag>sysinfo</tag> <item><p>Called when no installation is performed but the action is <tt>sysinfo</tt>. It shows information about the detected hardware and mounts the local hard disks read only to <file>/tmp/target/partitionname</file> or with regard to a <file>fstab</file> file. Log files are stored to the install server.</p> </item> <tag>backup</tag> <item><p>Called when action is <tt>backup</tt>. Currently no default backup subroutine is defined.</p> </item> <tag>install</tag> <item><p>This task controls the installation sequence. The major work is to call other tasks and to save the output to <file>/tmp/rcS.log</file>. 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.</p> </item> <tag>defclass</tag> <item><p>Defines classes using scripts and files in <file>/fai/class</file>.</p> </item> <tag>defvar</tag> <item><p>Sources all files <file>/fai/class/*.var</file> for every defined class. If a hook has written some variable definitions to the file <file>/tmp/additional.var</file>, this file is also sourced.</p></item> <tag>partition</tag> <item><p>Calls <prgn>setup_harddisk</prgn> to partition the hard disks. Defines variables for the root and boot device (<var>$ROOT_PARTITION, $BOOT_PARTITION</var>) using <file>/tmp/disk_var.sh</file>.</p></item> <tag>mountdisks</tag> <item><p>Mounts the created partitions according to the created <file>/tmp/fstab</file> file relativ to <var>$FAI_ROOT</var>.</p> </item> <tag>extrbase</tag> <item><p>Extracts the base tar file <file>base.tgz</file>.</p> </item> <tag>mirror</tag> <item><p>If a local mirror is accessed via NFS (if <var>$FAI_DEBMIRROR</var> is defined), this directory will be mounted.</p> </item> <tag>updatebase</tag> <item><p>Prepares the extracted base system for futher 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 <manref name="dpkg-divert" section="8">.</p> </item> <tag>instsoft</tag> <item><p>Installs the desired software packages using class files in <file>/fai/packages_config</file>.</p> </item> <tag>configure</tag> <item><p>Calls scripts in <file>/fai/scripts/</file> for every defined class.</p> </item> <tag>finish</tag> <item><p>Umounts the proc filesystem in the new installed system and removes diversions of files (<prgn>rmdivert</prgn>).</p> </item> <tag>faiend</tag> <item><p>Automaticly reboots the install clients or waits for manual input before reboot.</p> </item> <tag>chboot</tag> <item><p>Changes symbolic link on the install server, which indicates which kernel image to load on next boot from network card.</p> </item> <tag>savelog</tag> <item><p>Saves log files to local disk and to the install server.</p> </item> </taglist> <sect id=s1>The setup routines of the install clients<p> After the subroutine <prgn>fai_init</prgn> has done some basic initialization, the setup continues by callinf the task <tt>confdir</tt> and <tt>setup</tt>. The command <manref name="bootpc" section="8"> is called and its output is used to define the corresponding global variables which are save in <file>/tmp/bootp.log</file>. <example> /tmp/bootp.log: 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_2='134.95.100.209' DNSSRVS_3='134.95.100.208' DNSSRVS_4='134.95.140.208' DNSSRVS='134.95.9.136 134.95.100.209 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' </example> It's not a bug, if a variable (T171 in the example above) is defined twice. The second definition supersedes the first. <p> <var>FAI_FLAGS</var> (T172) contains a space separated list of flags. Following flags are known: <taglist> <tag>verbose</tag> <item> <p>Create verbose output during installation. This should be alsway the first flag, so consecutive definitions of flags will be verbosely displayed.</p> </item> <tag>debug</tag> <item> <p>Create debug output. No interactive installation is performed. During package installation you have to answer all questions of the postinstall scripts from the console. </p> </item> <tag>sshd</tag> <item> <p>Start ssh daemon to enable remote logins.</p> </item> <tag>createvt</tag> <item> <p>Create two virtual terminals and execute a bash if <tt>ctrl-c</tt> it typed. The terminals can be accessed by typing <tt>Alt-F2</tt> or <tt>Alt-F3</tt>. Otherwiese no terminals are available and typing <tt>ctrl-c</tt> will reboot the install client. Useful for installation which should not be interruptible.</p> </item> <tag>reboot</tag> <item> <p>Reboot after installation is finished without typing RETURN on the console. Only useful if you can change the boot image or boot device automatically (Can your assembly robot remove the boot floppy via remote control ?). Currently useful if you boot from network card and use <var>$TFTPLINK</var>. or change the boot device with the command <prgn>bootsector</prgn>.</p> </item> </taglist> <sect id=classc> The class concept<p> 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: <example> 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 </example> 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 <tt>A</tt>, we say the class <tt>A</tt> is defined. A class has no value, it is just defined or undefined. Within scripts, the variable <var>$classes</var> 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: <enumlist> <item><p>Some default classes are defined for every host: DEFAULT, LAST and its hostname.</p> </item> <item><p>Classes may listed within a file.</p> </item> <item><p>Classes may be defined by scripts.</p> </item> </enumlist> 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 <file>/usr/share/doc/fai/classes_description.txt</file>. <p> 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. <sect id=s2> Defining classes<p> The default task <em>defclass</em> defines the classes <tt>DEFAULT, LAST, $HOSTNAME</tt> and all classes in the file <file>/fai/class/</file><tt>$HOSTNAME</tt> for every hosts. Additionally, all files that are executable and match the shell regular expression <tt>S[0-9]*.{sh,pl}</tt> 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 <file>/tmp/additional-classes</file>, these classes are also defined. The list of all defined classes is stored in the variable <var>$classes</var> and in <file>/tmp/FAI_CLASSES</file>. The list of all classes is transfered to <prgn>cfengine</prgn>, so it can use them too. Script <file>S01alias.sh</file> (see below) is used to define classes for groups of hosts. All hosts with prefix <var>ant</var> use all classes in the file <file>anthill</file>. Hosts, which have an IP address in subnet <var>134.95.9.0</var> also belongs to class <tt>NET_9</tt>. Finally this scripts defines the class with the name of the hardware architecture in uppercase letters. <example> 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/ </example> Script <file>S07disk.pl</file> can be used to define classes depending on the number of local disks or the size of these scripts<footnote> <p>It uses the library <file>Fai.pm</file>, which includes some useful subroutines, e.g. <tt>class</tt>, <tt>classes</tt>, <tt>read_memory_info</tt>, <tt>read_ethernet_info</tt>.</p> </footnote>. But you can also use a range of partition size in the disk configuration file (in <file>disk_config</file>), so you may not need a class for every different disk size. The script <file>S24nis.sh</file> 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, <file>S90partitions.pl</file> defines classes. For eg., if a partition <file>/files/scratch</file> exists, the install client will export this directory via NFS therefore installs a NFS server packages. <p> The script <prgn>S05modules.sh</prgn> does not define any class, but is responsible for loading kernel modules. Kernel modules are important for detecting hardware. The script calls the script <tt>$HOSTNAME.mod</tt> and all scripts that have the format <tt><classname>.mod</tt> 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 <tt>DEFAULT</tt> is defined (this class is always defined) and a file <file>DEFAULT.mod</file> exists, this script is executed. These scripts should contain all command for loading kernel modules: <example> DEFAULT.mod: modprobe parport_probe modprobe serial </example> You can find messages from modprobe in <file>/tmp/dmesg.log</file> and the on the fourth console terminal (pressing <tt>Alt-F4</tt>).<p> <sect id=classvariables> Variables in <tt>class/*.var</tt><p> The task <em>defvar</em> defines the variables for the install clients. All global variables can be set in <file>DEFAULT.var</file>. For certain groups of hosts use a class file or for a single host use the file <tt>$HOSTNAME</tt><file>.var</file>. 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: <taglist> <tag>hdparm</tag> <item> <p>Multi line commands to tune the harddisks. They are executed during installation and also creates the script <file>/etc/init.d/S61hdparm</file>.</p> </item> <tag>UTC</tag> <item> <p>Set hardware clock to UTC if <tt>$UTC=yes</tt>. Otherwise set clock to locatime. See <manref name="clock" section="8"> for more information.</p> </item> <tag>time_zone</tag> <item> <p>File relative to <file>/usr/share/zoneinfo/</file> which indicates your time zone.</p> </item> <tag>FAI_CONSOLEFONT</tag> <item> <p>Font, that is loaded during installation by <manref name="consolechars" section="8">.</p> </item> <tag>FAI_KEYMAP</tag> <item> <p>Keyboard map file in <file>/usr/share/keymaps</file>. You need not specify the complete path, since this file will be located automatically.</p> </item> <tag>kernelimage</tag> <item> <p>The kernel that is installed to the new system. If a Debian package <file>/fai/files/packages/</file><tt>$kernelimage</tt> exists, isntall this kernel package. Otherwise install the package <tt>$kernelimage</tt> from the Debian mirror. For eg., if <tt>kernelimage=kernel-image-&kver;-idepci</tt> this kernel will be installed. To install the a special kernel for host bigfoot, set <tt>kernelimage=kernel-image-&kver;_bigfoot1_i386.deb</tt> and this kernel will be installed from <file>/fai/files/packages/</file>.</p></item> <tag>liloappend</tag> <item> <p>Append parameters for the kernel of the new system (written to <file>/etc/lilo.conf</file>).</p> </item> <tag>moduleslist</tag> <item> <p>Multi line definition. List of modules (including kernel parameters), that are loaded during boot of the new system (written to /etc/modules).</p> </item> <tag>rootpw</tag> <item> <p>The root password for the new system. Additionally, FAI creates an root account with the same password called <tt>roott</tt>, which uses the <manref name="tcsh" section="1">.</p> </item> <tag>TFTPLINK</tag> <item> <p>Link to the TFTP kernel image, that boots using the root file system from the local disk. </p> </item> <tag>hserver, bserver</tag> <item> <p>Name of NFS servers for <file>/home</file> and <file>/usr</file>.</p> </item> <tag>printers</tag> <item> <p>List of printer, for which a spool directory is created. Does not set up <file>/etc/printcap</file>.</p> </item> <tag></tag> <item> <p></p> </item> </taglist> <sect id=diskconfig>Hard disk configuration<p> The format of the hard disk configuration files is described in <file>/usr/share/doc/fai/README.disk_config.gz</file>. The config file <file>/fai/disk_config/CS_KOELN</file> is a generic description for one IDE hard disk, which should fit for most installations. If you can't partition your harddisk using this script <footnote><p>Currently this script uses the command <tt>sfdisk(8)</tt>, which isn't available on SUN SPARC.</p> </footnote>, use a hook instead. The hook should write the new partition table, create the file systems and create the file <file>/tmp/fstab</file> and <file>/tmp/disk_var.sh</file>, which contains definitions of boot and root partitions. <sect id=packageconfig>Software package configuration<p> The script <prgn>install_packages</prgn> installs the selected software packages. It uses all configuration files in <file>/fai/package_config/</file>, which file name is also defined as a class. The syntax is very simple. <example> # 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 </example> Comments are starting with a hash (#) and are ending at the end of the line. Every command begins with the word <tt>PACKAGES</tt> followed by a command name. The command name is similar to those of <prgn>apt-get</prgn>. Here's the list of supported command names: <taglist> <tag>install:</tag> <item> <p>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.</p> </item> <tag>remove:</tag> <item> <p>Remove all packages that are specified in the following lines. Append a + to the package name, if the package should be installed.</p> </item> <tag>taskinst:</tag> <item> <p>Install all packages belonging to the task that are specified in the following lines. This works only for Debian 3.0 and later.</p> </item> <tag>dselect-upgrade</tag> <item> <p> Set package selections using the following lines. The following lines must be the output of the commands <prgn>dpkg --get-selections</prgn>. </taglist> Multiple lines with lists of space separated names of packages follows the commands install and remove. All dependencies are resolved and <prgn>apt-get</prgn> is used to perform the installation or removal of packages. The order of the packages is of no matter. <p> A line, that contains the <tt>PRELOADRM</tt> commands, loads a file into a directory before installing the packages. For examples the package <prgn>realplayer</prgn> needs an archive to install the software, so this archive is downloaded to the directory <file>/root</file>. After installing the packages this file will be removed. If the file shouldn't be removed, use the the command <tt>PRELOAD</tt> instead. <p> If you specify a package that does not exists (e.g. you made a typo), the the whole installation of software package will not be started. This could happen when the command <manref name="xviddetect" section="1"> does not recognize the video card, because the configuration file <file>SERVER</file> contains following line: <example> xserver-`xviddetect -q` </example> If the video card isn't detected, the software installation tries to install the package <tt>xserver-unknown</tt>. It will not start because this package doesn't exist. You can test all software package configuration files with the utility <prgn>chkdebnames</prgn>, which is available in <file>/usr/share/doc/fai/utils/</file>. <example> > chkdebnames stable /usr/local/share/fai/package_config/* </example> <sect id=cscripts>Scripts in <tt>/fai/scripts</tt><p> The default set of scripts in this directory is only an example. But they should do a reasonable jobs for your installation. You can edit them or add new scripts to match your local needs. <sect1 id=shell>Shell scripts<p> Most script are Bourne shell script. Shell scripts are good, 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 <tt>ifclass</tt>. For copying files with classes, use the command <manref name="fcopy" section="8">. If you like to extract an archive using classes, use <manref name="ftar" section="8">. But now have a look at the scripts and see what they are doing. <sect1 id=perl>Perl scripts<p> Currently no Perl scripts are used for modifying the system configuration. <sect1 id=expect>Expect scripts<p> Currently no expect scripts are used for modifying the system configuration. <sect1 id=cfengine>Cfengine scripts<p> Cfengine has a rich set of functions to edit existing configuration files, e.g <tt>LocateLineMatching, ReplaceAll, InsertLine, AppendIfNoSuchLine, HashCommentLinesContaining</tt>. 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 at in the manual page <manref name="cfengine" section="8"> or at the homepage for cfengine <httpsite>http://www.iu.hioslo.no</httpsite><httppath>/cfengine</httppath>. <sect id=changeboot>Changing the boot device<p> Changing the boot sequence is normally done in your BIOS setup. But you can't change the BIOS from a running Linux system (If you know how to perform this, send me an email). But there's another way of swapping the boot device of a running Linux system. <p> Change the boot sequence in your 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. <p> After the installation is performed, <manref name="lilo" section="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 <prgn>bootsector</prgn><footnote><p>The command <tt>bootsector</tt> is part of the package <package>fai</package> and will be installed to <file>/usr/local/sbin</file> on the install clients.</p></footnote> . For more information use: <example># bootsector -h </example> 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. <example> Boot From LAN First: Enabled Boot Sequence : C only </example> Then enter the MBA setup of the 3Com network card and change it as follows: <example> Default Boot Local Local Boot Enabled Message Timeout 3 Seconds Boot Failure Prompt Wait for timeout Boot Failure Next boot device </example> 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 p[artitioning tool can't work on such a disk. So you have to enable the boot sector before you want to partition the disk. <sect id=hooks>Hooks<p> Hooks let you specify functions or programs, that are run at certain steps of the installation process. FAI provides many locations where hooks can be called. 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 <tt>debug</tt> is included in <var>$FAI_FLAG</var> the option <tt>-d</tt> is passed to all hooks, so you can debug your own hooks. <p> The directory <file>/fai/hooks/</file> 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 <file>partition.DISKLESS</file> is called for every client belonging to the class <tt>DISKLESS</tt> 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 <tt>/tmp/fstab</tt>. After that, the installation process would not try to partition and format a local hard disk, because a file <file>/tmp/fstab</file> already exists. <p> A hook of the form <tt>hookprefix.classname</tt> 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 <tt>.sh</tt> (eg. <file>partition.DEFAULT.sh</file>) must be bourne shell scripts and are sourced. So it's possible to redefine variables for the installation scripts. <p> This is the complete list of hooks and when they will be called. XXXXXXXXXXXXX After some basic initialization, all hooks with prefix <tt>confdir</tt> are called. Since the configuration directory <file>/fai</file> is not yet mount on the install client, these are the only hooks located in <tt>$</tt><file>nfsroot/fai/hooks</file> on the install server. All other hooks are found in <file>/usr/local/share/fai/hooks</file>. FAI has default jobs for following values of <var>FAI_ACTION</var>. <list> <item> <p>sysinfo</p> </item> <item> <p>install</p> </item> <item> <p>backup</p> </item> </list> If another value is defined, FAI will look for a hook <file>/fai/hooks/$FAI_ACTION</file> and executes this hook. So you can easily define your own actions.<p> All hooks that are called before classes are defined can only use the following classes: <tt>DEFAULT $HOSTNAME LAST</tt>. If a hook for class <tt>DEFAULT</tt> should only be called if no hook for class <tt>$HOSTNAME</tt> is available, insert these lines to the default hook: <example> 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 . . </example> <p> Some examples what hooks could be used for: <list> <item> <p>Use <prgn>ssh</prgn> in the very beginning to verify that you mounted the configuration from the correct server and not a possible spoofing host.</p></item> <item> <p>Pop up a little menu and ask the user, which kind of installation should be performed (eg. CAD workstation, scientific workstation, workgroup server, Gnome desktop...). Keep in mind that this won't lead to a fully automatic installation ;-) </p></item> <item> <p>Do not mount the configuration directory, instead get a compressed archive via HTTP or from floppy disk and extract it into a new ram disk, then redefine <var>$FAI_LOCATION</var>.</p></item> <item> <p>Load kernel modules before classes are defined in <file>/fai/class</file>. </p></item> <item> <p>Send an email to the administrator, if the installation is finished.</p></item> <item> <p></p></item> </list> <sect id=errors>Looking for errors<p> If the client can't succsessfully boot from the network card, use <manref name="tcpdump" section="8"> to look for ethernet packets between the install server and the client. Search also for entries in several log files made by <manref name="in.tftpd" section="8"> and <manref name="bootpd" section="8">: <example>egrep "tftpd|bootpd" /var/log/*</example> If the installation process stops or even it finishes, parse all log files for errors using: <example> # egrep "no such variable|bad variable|E:|ERROR" *.log </example> 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 (<manref name="top" section="1">, <manref name="pstree" section="1">). You can add <tt>debug</tt> to <tt>FAI_FLAGS</tt>, so the installation process will show all output from the postinst scripts on the console. Don't hesitate to send an email to the mailing list or to <email>fai@informatik.uni-koeln.de</email> if you have any questions. Sample log files from successful installed computers are available on the FAI homepage. <chapt id=beowulf>How to build a Beowulf cluster using FAI<p> This chapter describes the particularities about building a beowuld cluster. For maore information about the Beowulf concept, look at <httpsite>http://www.beowulf.org/</httpsite>. The master node (in my examples I call it <em>nucleus</em>) has two network cards. One for the connection to the external Internet, one for the connection to the internal cluster network. If connected from the external Internet, it's called <em>nucleus</em>, but the cluster nodes accesses the master node with name <em>atom00</em>, which is a name for the second network interface. <p> All computing nodes (called <em>atom01</em> to <em>atom99</em>) are connected via a switch with the second interface card of the master node. They can only connect to the other nodes or the master, but can't communicate to any host outside their cluster network. So, all services (time server, DNS, ...) must be available on the master server. <p> I choose the class C network address <em>192.168.49.</em> for building the local cluster network. You can replace the subnet 49 with any other number you like. I you have more that 253 computing nodes, choose a class A network address (10.X.X.X). </p> <sect id=master> Set up the master server<p> The master server will be installed by hand, cause it could be your first computer installed with Debian. It you have already a Debian host running, you can also install it via FAI. After the normal Debian system is installed to the master server you have to add some software packages and The master server is also the install server for the computing nodes. It has Create a local Debian mirror on <file>/files/scratch/</file> using <prgn>mkdebmirror</prgn>. This will need about 2.6GB disk space for Debian 2.2 (aka potato). Add following lines for the second network card to <file>/etc/network/interfaces</file>: <example> # Beowulf cluster connection iface eth1 inet static address 192.168.49.200 netmask 255.255.255.0 broadcast 192.168.49.255 </example> <file>/etc/hosts</file>: <example> # Beowulf nodes # atom00 is the master server 192.168.49.200 atom00 192.168.49.1 atom01 192.168.49.2 atom02 </example> Add following packages to the install server <example>nucleus:/# apt-get install task-dns-server ntp</example> It's very important to use the network name of the cluster network for the master node in <file>/etc/bootptab</file> and <file>/etc/fai.conf</file>. Adjust this file in <file>/etc/fai.conf</file> so the Beowulf nodes can use the name for connecting their master server. <example> NFSROOT_ETC_HOSTS="192.168.42.250 atom00" </example> <file>/etc/bootptab:</file> <example> .failocal:\ :tc=.faiglobal:\ :sa=atom00:\ :ts=atom00:\ :T170="atom00:/usr/local/share/fai":\ :T171="sysinfo":\ :T172="verbose createvt sshd":\ :sm=255.255.255.0:\ :gw=192.168.49.200:\ :dn=pc.uni-koeln.de:\ :ds=192.168.49.200:\ :ys=atom00:yd=nisnucleus:\ :nt=atom00: </example> <chapt id=sparc>FAI on SUN SPARC<p> Even FAI is architecture independent, there are some packages, that are only available for certain architectures (eg. silo, sparc-utils). SUN can boot from their boot prompt and don't need a boot floppy. To boot a SUN you must use: <example>boot net</example> Read the FAQ at <httpsite>http://www.ultralinux.org</httpsite> for more information. You have to convert the kernel image from ELF format to a.out format. Therefore use the program <prgn>elftoaout</prgn> (mentioned in the FAQ). The symlink to the kernel image to be booted is not the host name. Look at the FAQ for more information. <chapt id=hints>Various Hints<p> This chapter has various hints which may not be explained in very detail. <p> Use <prgn>mkdivert</prgn> if a postinst script calls a configuration programm (eg. the postinst script for package apache calls apacheconfig) needs manual input. You can fake the configuration programm so the installation can be fully automatic. But don't forget to use<prgn>rmdivert</prgn> to remove the faking. <p> During the installation of when it's finished, you can execute commans inside the newly installed system by using <example>chroot /tmp/target</example> or just <example>$ROOTCMD</example> followed by the command you want to call. <p> The only task, which has to be done manually for new hardware, is to assign the MAC address to a hostname and to an IP address and define classes for this host. <p> There's a tradeoff between writing a few large configuration scripts, or many short scripts. Large scripts can distinguish classes by using case statements or the ifclass test. <p> If your computer can't boot from network card you need not always boot from floppy. Define a partition <file>/fai-boot</file> in your <file>disk_config</file> configuration file. Then the class <tt>FAI_BOOTPART</tt> will automaticly defined and will create a lilo entry for booting the FAI bootfloppy from this partition. So you can start the reinstallation without a boot floppy. This will also make the test phase shorter, since booting from harddisk is faster. </book> </debiandoc> <!-- buy a switch box for monitor and keyboard rdev vmlinuz-2.2.19 /dev/hda1 if your server does not have /dev/hda1 as root device. The call imggen chown -R fai /boot/fai # install pine cd /tmp dpkg-source -x /usr/src/pine4/pine4_4.21-1.dsc cd /tmp/pine4-4.21 dpkg-buildpackage cd /tmp dpkg -i *.deb --> <!-- Keep this comment at the end of the file Local variables: mode: sgml sgml-omittag:t sgml-shorttag:t sgml-minimize-attributes:nil sgml-always-quote-attributes:t sgml-indent-step:2 sgml-indent-data:nil sgml-parent-document:nil sgml-exposed-tags:nil sgml-declaration:nil sgml-local-catalogs:nil sgml-local-ecat-files:nil End: -->