Probablemente ya conozcas el proyecto SYSLINUX, un cargador de arranque muy configurable y modular, que ofrece distintas utilidades en función de dónde queramos realizar su instalación: ISOLINUX (cdrom), EXTLINUX (partición ext2/3) y PXELINUX (arranque por red pxe). Como ya existe muchísima información al respecto, comentaré muy brevemente el funcionamiento de este último.
Básicamente necesitas dos cosas: un servidor dhcp y un servidor tftp. Por un lado se configurará el dhcp con las opciones adecuadas y por otro, bastará con almacenar en la raíz del tftp los binarios de pxelinux y sus módulos (aptegetea syslinux y copia los archivos de /usr/lib/syslinux/). A partir de este momento, cuando nuestra máquina realice un arranque por red, ejecutará el pxelinux.0 que irá a buscar en el directorio pxelinux.cfg del raíz tftp varios ficheros: en primer lugar comprobará si existe un fichero de configuración cuyo nombre es su mac (precedida por 01-) y en caso de no encontrarlo, continuará probando con su ip, subredes (codificadas en hexadecimal) y finalmente buscará un fichero default. Una vez obtenido, el cargador lo interpretará y cederá la ejecución al módulo o sistema operativo que corresponda.
Como vemos, es un mecanismo muy sencillo a la vez que potente, ya que podemos asignar arranques por máquina (o redes) personalizados de manera centralizada. Esto nos permitirá desde seleccionar el sistema operativo en el que arrancará la máquina hasta realizar backups completos, reparaciones del sistema, tareas de mantenimiento o despliegues de sistemas operativos de manera remota (e incluso automatizada).
Ahora bien, en su sencillez también radica su principal debilidad ¿qué ocurre si son cientos de hosts y distintos servidores tftp?, ¿sincronizamos o regeneramos?, ¿cómo puedo saber si se ha producido un arranque?, ¿cómo puedo introducir cierta lógica en la generación de la configuración basada en el momento en que se produce el arranque?…
Afortunadamente, y en respuesta a estos problemas el proyecto Gosa propuso una sencilla solución que además hizo modular para que se pudieran aprovechar otros proyectos. Y así lo hiceron FAI, LTSP y OPSI (y ahora yo
)
La solución viene en forma de un servicio “suplicante” llamado FTS. Su funcionamiento es sencillo. Básicamente monta un sistema virtual FUSE sobre el directorio pxelinux.cfg servido por el tftp, de modo que de forma transparente al servicio tftp, le provee de los ficheros solicitados. De este modo, cada solicitud de apertura de fichero al sistema fuse, se traduce en una petición que este suplicante realiza a un tercer servicio, como puede ser un ldap o un webservice.
Estuve mirando los módulos y ninguno hacía lo más sencillo: traducir la petición en una llamada a una url que pudieramos configurar y a la que le pasáramos por parámetro la dirección mac. Por ello, creé este simple modulito el perl (fts está escrito en este lenguaje). Básicamente hará lo siguiente:
CLIENTE (pxelinux.0) -> petición tftp 00-01-02-03-04-05-07 -> SERVIDOR TFTP -> fileopen(00-01-02-03-04-05-06) -> FTS -> petición web http://servidor/pxe.php?mac=01-01-02-03-04-05-07 -> SERVIDOR WEB
Casi me ha costado más escribir este post que programarlo. Ahí va el código:
package FTSWebServer;
# Autor: Luis Guillén Civera
# Fecha: 2010/11/19
use Exporter;
@ISA = ("Exporter");
use strict;
use warnings;
use Switch;
use LWP::Simple;
sub get_module_info {
return "Web Server provider";
};
my $protocol;
my $admin;
my $password;
my $port;
my $server;
my $script;
my $cfg_defaults = {
'protocol' => [ \$protocol, 'http' ],
'admin' => [ \$admin, '' ],
'password' => [ \$password, '' ],
'port' => [ \$port, '80' ],
'server' => [ \$server, 'localhost' ],
'script' => [ \$script, 'prueba.php?mac=' ]
};
sub get_config_sections {
return $cfg_defaults;
}
sub get_pxe_config {
my ($filename) = shift || return undef;
my $base_url;
if($admin) {
$base_url = "$protocol://$admin:$password\@$server:$port/$script";
} else {
$base_url = "$protocol://$server:$port/$script";
}
my $web_url=$base_url.$filename;
my $file_content=&LWP::Simple::get($web_url);
&main::daemon_log("Getting $web_url...\n");
if(!defined $file_content) {
&main::daemon_log("Warning: url doesn't exist $web_url\n");
return 1;
}
$main::filesystem->{'root'}->{'content'}->{$filename}->{'type'}='file';
$main::filesystem->{'root'}->{'content'}->{$filename}->{'content'}=$file_content;
return 0;
}
1;
¿Cómo lo instalamos y configuramos? muy fácil, basta aptegetear fts, libwww-perl y libcrypt-ssleay-perl (si deseamos https) (son paquetes de Ubuntu 10.04), copiamos el módulo con nombre FTSWebServer.pm en /usr/lib/fts/modules y configuraremos el /etc/fts/fts.conf del siguiente modo:
- comentar las opciones de ldap
- configurar pxelinux_cfg y pxelinux_cfg_static (mirar la documentación de fts. Básicamente es un directorio “real” paralelo en el que el servicio mirará en caso de no encontrarse disponible)
- agregar una sección:
[FTSWebServer]
protocol = http
port = 80
server = localhost
script = pxe.php?mac=
Bastará entonces con relanzar el servicio o si se quiere lanzar en primer plano para ver las peticiones, usar el comando
# fts -c /etc/fts/fts.conf -f -s -v
Con un poco de imaginación puede verse la potencia de esta herramienta. Así lo vi yo y por ello actualmente estoy escribiendo un sistema simple de gestión de arranques y tareas centralizado para gestionar clusters y redes de workstations que espero tener listo en breves y publicar en unas semanas.