**Cette page a été importée automatiquement de notre ancien wiki mais n'a pas encore été révisée.**

# How to FAI

Cette page décrit une des utilisations possible de FAI, Fully Automated Install, un système d'installation de Linux non-interactif.

L'utilité de FAI est qu'il permet d'installer en quelques minutes un système Debian complet sans aucune interaction humaine. Evolix n'utilise pas l'ensemble des fonctionnalités de FAI.

La documentation de FAI est très complète et peut être consultée ["ici (anglais)"](http://fai-project.org/fai-guide/index.html).

## FAI server vs FAI "serverless"

Il existe deux moyens principaux d'installer des machines à l'aide de FAI. Le premier implique l'utilisation d'un serveur FAI qui va fournir les services suivants:

* DHCP (pour configurer le réseau)
* TFTP (sert l'initrd et le kernel lors de l'installation) 
* NFS (sert l'ensemble des autre fichiers nécessaires)

Ce serveur contient l'ensemble de la configuration des clients. 

La seconde manière d'installer une machine avec FAI est de monter une image complète de l'installation et de l'utiliser comme on le ferait avec une image ISO standard.

L'avantage de cette méthode est que le client n'a pas besoin d'avoir accès à internet (au serveur FAI) pour effectuer l'installation. Il est ainsi possible de mettre l'image sur une clef USB ou un CD.

Pour créer cette image disque, il est cependant nécessaire d'avoir une machine qui roule les programmes fournis par le package Debian `fai-server`. Nous appellerons cette méthode du nom de l'utilitaire qui sert à générer les images: fai-cd.

# fai-server

La première étape pour monter le serveur FAI est d'installer les packages nécessaires à son bon fonctionnement. Pour simplifier la tâche, Debian fournit un package virtuel qui installe l'ensemble des choses requises:

~~~
# apt install fai-quickstart
~~~

Lors de l'installation, plusieurs fichiers de configuration sont créés. Ceux qui nous intéressent pour l'instant se trouvent dans `/etc/fai`.

Par exemple, lors des installations FAI utilise d'autres sources que celles configurées dans `/etc/apt`. Par défaut FAI utilise [<httpredir>](http://<httpredir.debian.org/).>

Si vous disposez d'un miroir local et que ce miroir est disponible pour les machines que vous comptez installer avec FAI, il est intéressant de changer ce paramètre. Les fichiers à modifier sont `/etc/fai/apt/sources.list` et `/etc/fai/nfsroot.conf`. Par exemple, chez Évolix nous avons:

~~~
# cat /etc/fai/nfsroot.conf

# For a detailed description see nfsroot.conf(5)

# "<suite> <mirror>" for debootstrap
FAI_DEBOOTSTRAP="jessie <http://mirror.evolix.org/debian">
FAI_ROOTPW='XXXXXXXXX'

NFSROOT=/srv/fai/nfsroot
TFTPROOT=/srv/tftp/fai
NFSROOT_HOOKS=/etc/fai/nfsroot-hooks/
FAI_DEBOOTSTRAP_OPTS="--exclude=info --include=aptitude"

# Configuration space
FAI_CONFIGDIR=/srv/fai/config
~~~

et

~~~
# cat /etc/fai/apt/sources.list

deb <http://mirror.evolix.net/debian> jessie main contrib non-free
deb <http://security.debian.org/debian-security> jessie/updates main contrib non-free
~~~

Il est cependant bon de noter que si `debootstrap` n'arrive pas à se connecter au miroir correctement, le processus de création du NFSROOT continue comme si de rien n'était. Il est ainsi peut être plus prudent d'utiliser un miroir officiel pour cette partie.

Pour pouvoir continuer, on active l'utilisateur principal qui va être utilisé par FAI et on spécifie la configuration à utiliser pour une installation via NFS:

~~~
# vim /etc/fai/fai.conf

# See fai.conf(5) for detailed information.

# Account for saving log files and calling fai-chboot.
LOGUSER=fai

# URL to access the fai config space
FAI_CONFIG_SRC=nfs://faiserver/srv/fai/config
~~~

Une fois que les packages sont installés et que l'on a modifié la configuration initiale comme on le souhaitait, on roule la commande suivante pour terminer l'installation. Attention! il est nécessaire d'avoir `aptitude` pour que `fai-setup` et les commandes qui suivent fonctionnent comme il se doit:

~~~
$ fai-setup -v
~~~

Cette commande fait plusieurs choses:
1. Elle crée un nouvel utilisateur, `fai`
1. Elle génère une paire de clefs ssh pour cet utilisateur dans `/var/log/fai/.ssh`
1. Elle crée le NFSROOT dans `/srv/fai/nfsroot` et le peuple avec un debootstrap en vue des installations.

Si vous souhaitez utiliser FAI sans serveur PXE (méthode fai-cd), vous pouvez passez à la [#Configuration "section Configurations] tout de suite. Pour avoir un fai-server complet, il faut continuer et configurer le DHCP, le PXE et le NFS.

## DHCP

Par défaut l'installation du package `fai-quickstart` a déjà installé les packages nécessaires pour monter un serveur DHCP. Il ne nous reste qu'à le configurer. On remplace donc `/etc/dhcp/dhcpd.conf` par la configuration suivante:

~~~
deny unknown-clients;
option dhcp-max-message-size 2048;
use-host-decl-names on;

subnet <SUBNET> netmask <NETMASK> {
   option routers <ROUTER>;
   option domain-name "<DOMAIN>";
   option domain-name-servers <DNS>;
   server-name faiserver
   next-server faiserver;
   filename "fai/pxelinux.0";

#	 host <FAI HOSTNAME> { # the hostname associated to FAI classes
#			hardware ethernet <MAC ADDRESS>;
#			fixed-address <STATIC IP>;  # optional. Should be set in /etc/hosts
#	 }
}
~~~

Cette configuration attribue une adresse IP fixe à une machine seulement si son adresse MAC y a été configuré. Vous pouvez ajouter des nouvelles machines manuellement en copiant le bloc commenté, mais une solution plus simple existe également. En effet, FAI utilise un programme nommé `dhcp-edit` qui fait tout le travail pour nous.

Il faut tout d'abord ajouter la nouvelle machine au `/etc/hosts`:

~~~
# echo '<STATIC IP> evodemo' >> /etc/hosts
~~~

On ajoute ensuite la machine au DHCP:

~~~
# dhcp-edit evodemo <MAC ADDRESS>
~~~

Et voilà! `dhcp-edit` redémarre même le DHCP pour nous.

## NFS

En théorie, votre serveur NFS fonctionne déjà et ne nécessite aucune modification pour fonctionner. Il existe cependant un bug dans le fichier d'init de `nfs-kernel-server` sur Jessie qui l'empêche de fonctionner comme il se doit. On modifie donc `/etc/init.d/nfs-kernel-server` pour ajouter un commande `sleep` au démarrage:

~~~
[...]
# See how we were called.
case "$1" in
  start)
    sleep 10
	export_files="/etc/exports"
[...]
~~~

Vous devriez maintenant pouvoir lancer `nfs-kernel-server` avec succès:

~~~
# service nfs-kernel-server restart
# systemctl daemon-reload
~~~

Il faut de plus vous assurer que votre firewall ne bloque pas les ports nécessaires au NFS:

* TCP 111
* TCP 2049
* UDP 111
* UDP 2049

Si vous avez des problèmes avec votre NFSROOT lors de l'installation, le plus simple est de supprimer le dossier `/srv/fai/nfsroot` et de relancer `fai-setup -v`.

## PXE

Il ne nous reste plus qu'à générer les fichiers de configuration PXE pour la nouvelle machine que l'on souhaite installer. Encore une fois, FAI dispose d'un utilitaire pour nous simplifier la vie:

~~~
# fai-chboot -IFv -u nfs://faiserver/srv/fai/config evodemo
~~~

On s'assurer finalement que tous les fichiers de PXE on les bonnes permissions:

~~~
# chmod -R u+rwX,go+rX,go-w /srv/tftp
~~~

# Configuration

Avant de commencer à décrire le "language FAI", il est bon de savoir que le package Debian viens avec des exemples concrêts et fonctionnels de configuration. On peut les utiliser comme base de départ:

~~~
# mkdir /srv/fai/config
# cp -a /usr/share/doc/fai-doc/examples/simple/* /srv/fai/config
~~~

FAI utilise une méthode basée sur des classes pour savoir quelles configurations utiliser lors d'une installation. Par exemple, la configuration pour une machine Debian de base roulant XFCE fournie avec le package `fai-quickstart` utilise les classes suivantes:

`FAIBASE GRUB DHCPC DEMO XORG XFCE`

Ces classes sont entièrement configurables. Elles sont liées au hostname (nom de domaine) de la machine qui va être installée. Avant l'installation, il est donc nécessaire soit:

* de modifier la configuration pour spécifier les classes à utiliser pour le hostname
* de choisir le hostname en fonction de l'installation que l'on souhaite effectuer

Ainsi, pour une machine roulant XFCE, on utiliserait le hostname `xfcehost` lors de l'installation. 

Dans la partie qui suit, nous allons passer en revue les différents dossiers de configuration et leurs fonction dans la configuration d'une machine:

## class

Tous les noms des classes sont en majuscules, à l'exception des classes définies pour un hostname seulement. Le nom des classes ne peuvent pas contenir les caractères suivants:

* trait d'union (`-`)
* dièse (`#`)
* point-virgule (`;`)
* point (`.`)

Les barres de soulignement (`_`) et les numéros sont cependant acceptés.

Les fichiers dans le dossier `class` sont utilisés pour lier des hostnames à des classes. Le nom des fichiers dans ce dossier suit la convention suivante: `^[0-9][0-9]*`.

Ainsi, le fichier `10-important-class` est lu avant le fichier `99-less-than-important`. Des fichiers nommés `mysuperclass` ou `1-thiswillnotrun` ne seraient tout simplement pas lu.

Il est également possible d'avoir un fichier de définition de classe pour une seule machine. En quel cas, on utilise le hostname comme nom du fichier de définition (i.e. `kvm4`).

L'ordre des classes est important car il est parfois nécessaire d'effectuer certaines étapes de configuration avant d'autres.

Voici un exemple de définition de classe:

~~~
#! /bin/bash

# assign classes for kvm machines

case $HOSTNAME in
   kvm?.evolix.net|othermachine*)
		echo "FAIBASE KVM" ;;
esac

case $HOSTNAME in
   othermachine*) 
   		echo ""MYSUPERCLASS ;; # a comment here
esac
~~~

En plus des classes définies dans le dossier `class`, les classes DEFAULT et LAST s'appliquent à l'ensemble des machines.

Pour chaque classe ou hostname, il est possible de créer un fichier `*.var` (i.e. `DEBIAN.var`) qui regroupe des variables à utiliser dans les scripts:

~~~
# cat class/DEBIAN.var
PARTY_HARD=1
MYSUPERVAR="foobar"
~~~

Plus de détails sur la ["page du projet FAI"](http://fai-project.org/fai-guide/#_a_id_classvariables_a_defining_variables).

## files

Le dossier `files` est peut-être le plus simple des dossiers de configuration. Il contient l'ensemble des fichiers que l'on souhaite transférer lors d'une installation. Ainsi, un `tree` du dossier `files` pourrait ressembler à:

~~~
files/
|-- etc
|   |-- apt
|   |   |-- apt.conf.d
|   |   |   `-- force_confdef
|   |   |       |-- DEBIAN
|   |   |       `-- kvm4
|   |   `-- sources.list
|   |       `-- GNOME
|   |-- dhcp
|   |   `-- dhcpd.conf
|   |       `-- FAISERVER
|   |-- fai
|   |   |-- apt
|   |   |   `-- sources.list
|   |   |       `-- FAISERVER
|   |   |-- fai.conf
|   |   |   `-- FAISERVER
|   |   `-- nfsroot.conf
|   |       `-- FAISERVER
|   |-- motd
|   |   `-- FAIBASE
|   |-- rc.local
|   |   `-- FAISERVER
|   `-- selinux
|       `-- config
|           `-- CENTOS
`-- usr
    `-- local
        `-- sbin
            `-- make_a_party
                `-- DEFAULT
~~~

La seule différence avec un dossier régulier est que plutôt que de créer un fichier directement, on crée un dossier du nom de ce fichier et l'on spécifie la version à utiliser en fonction d'une classe ou d'un hostname. Par exemple:

~~~
# ls files/etc/postfix/main.cf/
DEFAULT MYCLASS1 kvm4
~~~

Ici, les trois fichiers dans le dossier `files/etc/postfix/main.cf/` sont en fait des versions différentes du fichier de configuration `main.cf`. Le fichier `DEFAULT` va être installé par la classe `DEFAULT`, le fichier `MYCLASS1` va être installé par la classe `MYCLASS1` et le fichier `kvm4` va être installé seulement si le hostname de la machine est `kvm4`.

## scripts

Le dossier `scripts` rassemble les scripts qui vont faire des actions sur les machines. Par exemple le script suivant copie un fichier de configuration à partir des fichiers dans le dossier `files` avec les droits (root,root,0644):

~~~
#!/bin/bash

fcopy -M etc/postfix/main.cf
~~~

Les scripts sont regroupés par classe. Ainsi, tous les scripts dans `scripts/POSTFIX` vont être exécutés pour la classe POSTFIX. Le nom des scripts suit la même convention que le nom des fichiers dans [#class `class`].

Il est possible d'écrire des scripts dans de multiples langages, dont shell, cfengine, Perl, Python, Ruby, expect, etc.

FAI installe certaines commandes qui peuvent être très utiles:

* [`fcopy`](http://fai-project.org/doc/man/fcopy.html) pour copier des fichiers sur la machine
* [`ftar`](http://fai-project.org/doc/man/ftar.html) pour copier et extraire une archive tar
* ["`ainsl` (append if no such line)"](http://fai-project.org/doc/man/ainsl.html) pour ajouter une ligne dans un fichier

Il est également possible de tester si une classe est définie en shell script grâce à la commande `ifclass`:

~~~
ifclass -o A B C # retourne 0 si A, B ou C est défini
ifclass -a A B C # retourne 0 si A, B et C est défini
~~~

## package_config

Le dossier `package_config` regroupe les définitions de packages à installer pour chaque classe. Une classe installe les packages dans un fichier si ce dernier a le nom de la classe en question. Ainsi, la classe DEBIAN installe les packages dans `package_config/DEBIAN`.

Voici un exemple d'un fichier dans `packages_config`:

~~~
PACKAGES taskinst
german

PACKAGES aptitude
adduser netstd ae
less passwd

PACKAGES remove
gpm xdm
~~~

Une ligne commence toujours par `PACKAGES`. Elle est par la suite suivie de la commande à exécuter. Sur la ligne suivante, on liste les packages sur lesquels effectuer l'action. Voici les actions qui sont valides:

* hold
* install
* remove
* taskinst
* aptitude
* aptitude-r
* unpack

Le détail de ces actions est disponible avec la commande [install_packages -H](http://fai-project.org/doc/man/install_packages.html).

Avant d'installer les packages pour une classe ou un hostname, FAI ajoute le contenu de tous les fichiers nommées $CLASS.asc à la liste des clefs autorisées de `apt`. Cela est très pratique pour un miroir local contenant des packages non officiels.

## disk_config

FAI gère la partition des disques lors de l'installation grâce aux fichiers dans le dossier `disk_config`. Ces fichiers doivent être nommés selon le nom d'une classe. Bien évidemment, il n'est pas recommandé d'avoir plusieurs fichiers disk_config pour un même ensemble de classes!

La syntaxe utilisée pour les fichiers peut être retrouvée dans la page de manuel de l'outil utilisé pour la partition [setup-storage](http://fai-project.org/doc/man/setup-storage.html).

Voici un exemple de configuration utilisant la partition typique d'Évolix sur ses machines:

~~~
disk_config sda disklabel:msdos bootable:1

primary /boot 200 ext4 rw
primary / 500 ext4 rw
primary /var 10G ext4 rw
logical /tmp 500 ext4 rw,nosuid
logical /usr 5G ext4 rw
logical swap 500 swap sw
logical swap 500 swap sw
logical /home 15G ext4 rw
~~~

## debconf

Si l'on souhaite effectuer un preseed du package `debconf`, il est possible de créer un dossier nommé `debconf` et d'y ajouter des fichiers du nom d'une classe.

## hooks

Pour bien comprendre les `hooks` de FAI, il faut expliquer les `tasks`. Quand une installation est lancée (que ce soit par NFSROOT ou par fai-cd), FAI lance une série d'action que l'on nomme des tasks. Ainsi, pendant le processus d'installation, FAI va éventuellement lancer le task `partition`, qui partitionne les disques.

Voici tous les `tasks` que FAI lance, dans l'ordre de leur exécution. Une description complète de chaque task peut être trouvée dans la [section tasks](http://fai-project.org/fai-guide/#tasks) du guide FAI.

* confdir
* setup
* defclass
* defvar
* action
* sysinfo
* inventory
* install
* dirinstall
* softupdate
* partition
* mountdisks
* extrbase
* debconf
* repository
* updatebase
* instsoft
* configure
* tests
* finish
* chboot
* savelog
* faiend

Les `hooks` servent à lancer des script avant l'exécution d'un `task`. Cela donne très grande liberté sur le processus d'installation. 

Pour être valides, les `hooks` doivent être des scripts en Bourne Shell (`/bin/sh`) placés dans le dossier `hooks` en suivant la convention suivante: `task.CLASS[.sh]`

Ainsi, `partition.DEBIAN` roule avant la partition des disques pour les machines qui ont la classe DEBIAN. `partition.DEBIAN.sh` aurait été tout aussi valide.

Attention! Certaines restrictions s'appliquent:

* Il n'est pas possible de lancer un `hook` avec une autre classe que `DEFAULT`, `$HOSTNAME` ou LAST avant la fin du `task` `defclass`
* Tous les `hooks` lancés avant le `task` `confdir` doivent être placés dans $nfsroot/$FAI/hooks

# fai-cd

Maintenant que nous avons mis en place un fai-server minimal et que nous avons créé la configuration des clients que nous allons installer, nous allons créer des images ISO complètes.

Par défaut FAI utilise `dracut` pour les images ISO. La version de dracut dans Debian Jessie n'est cependant pas à même de faire ce dont FAI a besoin. Il est donc nécessaire soit d'utiliser la version de `dracut` de stretch, ou alors d'utiliser les packages dans le repository de FAI.

Plutôt que d'utiliser `dracut`, nous allons utiliser `live-boot`. Cela nécessite de commenter les lignes concernant `dracut` et d'activer celles pour `live-boot` dans `/etc/fai/NFSROOT`:

~~~
# dracut can replace live-boot
#dracut-network live-boot- initramfs-tools-

# choose if you like live-boot or dracut inside the nfsroot
live-boot live-boot-doc
~~~

La première étape pour obtenir un fai-cd est de créer un miroir complet des packages dont nous allons avoir besoin. De cette manière nous pourrons faire notre installation sans avoir besoin du réseau ou d'une connexion au fai-server.

On commence donc par créer un dossier où nous allons générer le miroir:

~~~
# mkdir /srv/fai/mirror
~~~

Pour que `fai-mirror` puisse télécharger les packages nécessaires, il a besoin d'une copie du dossier `/etc/apt/trusted.gpg.d`:

~~~
# mkdir -p /srv/fai/mirror/aptcache/etc/apt/
# cp -R /etc/apt/trusted.gpg.d/ /srv/fai/mirror/aptcache/etc/apt/
~~~

On peut par la suite rouler l'utilitaire `fai-mirror`:

~~~
# fai-mirror -v /srv/fai/mirror
~~~

Cette étape prends un peu de temps (la machine télécharge l'ensemble des packages qui vont être utilisés, etc.) et peut créer un miroir d'une taille substantielle, tout dépendant de nos configurations. Par exemple, un miroir de toutes les classes dans la configuration donnée en exemple crée un dossier d'environ 1G.

Si l'on connaît à l'avance les classes que l'on souhaite utiliser lors pour notre image ISO, on peut également construire un miroir partiel:

~~~
# fai-mirror -v -cCLASS1,CLASS2,CLASS3 /srv/fai/mirror
~~~

Une fois que l'on a un miroir qui correspond à nos besoins, on peut créer notre image ISO:

~~~
# fai-cd -m /srv/fai/mirror /srv/fai/myfai.iso
~~~

Il se peut que `fai-cd` se termine avec un message d'erreur à propos du NFSROOT non-compatible avec une image live. En quel cas, il est nécessaire de recréer le NFSROOT avec l'option `live`:

~~~
# rm -R /srv/fai/nfsroot
# fai-make-nfsroot -lv
~~~

Et voilà! Il ne reste plus qu'à installer une nouvelles machine avec l'image que l'on viens de créer. Lors du processus d'installation, il est bien important de spécifier un hostname lié à un ensemble de classe pour installer la bonne configuration!