Upstart es el sistema que muchas distribuciones Linux utilizan para gestionar las tareas a realizar en el arranque. Para los más veteranos del lugar, Upstart tiene como objetivo reemplazar los daemons tradicionales de SystemV que gestionan las tareas a ejecutar en el arranque, la parada y puesta en marcha de servicios.
Upstart busca sustituir al daemon init, el primer proceso que se lanza en Linux tras cargar el kernel y que se encarga de arrancar el resto. init es el proceso padre de todos aquellos procesos que hayan perdido a su padre (es el padre de todos los daemons). El comando pstree permite ver esto gráficamente.
Por qué Upstart
init es un proceso síncrono que bloquea la ejecución de tareas hasta terminar con la actual. Las tareas que init debe ejecutar han de ser definidas con antelación y éstas sólo se ejecutan cuando init cambia su estado (generalmente porque la máquina se ha encendido, se está apagando o se está reiniciando). El daemon init decide qué tareas ejecutar al cambiar su estado (RUNLEVEL) mirando en el directorio /etc/rcX.d/, donde X indica el RUNLEVEL actual.
Este hecho impide que init gestione correctamente otras tareas que son necesarias ejecutar NO al cambiar de RUNLEVEL sino cuando se generan ciertos eventos, como por ejemplo, las siguientes:
* se quiere ejecutar un backup del servidor de la base de datos en cuanto se detecte que dicho servicio se ha parado
* se conecta en caliente un dispositivo USB o disco externo
* se quiere realizar un sondeo de los dispositivos de almacenamiento disponibles sin que se bloquee el sistema (especialmente cuando el disco a sondear está en estado stand-by y se enciende al detectar el sondeo)
* se quiere ejecutar un script cada hora pero sólo si la ejecución anterior ya ha terminado
Hay más ejemplos y casos de uso en la discusión para reemplazar init en Ubuntu.
El modelo basado en eventos de Upstart permite responder de forma asíncrona a eventos como los mencionados, en cuanto éstos ocurren. La asincronía permite poder ejecutar en paralelo distintas tareas con el objetivo de minimizar el tiempo de arranque.
Evolución de Upstart
Desde su introducción en Ubuntu 6.10 (2006) Upstart ha ido paulatinamente reemplazando a SystemV (la migración por pasos siempre fue un objetivo). Los scripts de arranque y parada de servicios han sido migrados, si no todos, si una buena parte. El fichero /etc/inittab que indicaba al proceso init qué RUNLEVEL arrancar por defecto y cuáles eran los scripts rc que había que arrancar en cada nivel, ha sido eliminado.
En las primeras versiones de Upstart, la definición de jobs (trabajos a realizar cuando se detecten ciertos eventos) se hacía en el directorio /etc/event.d. En Karmic Koala (9.10), Canonical decidió cambiar esa localización a /etc/init.
En Agosto de 2011, Red Hat decidió también adoptar Upstart, dejando de lado SystemV init.
Trabajos, eventos, tareas y servicios
Los trabajos (o jobs, en terminología Upstart) pueden ser tareas o servicios. Las tareas son simples scripts que se ejecutan y terminan su trabajo en un breve lapso de tiempo. Los servicios son procesos que se quedan en ejecución (daemons). Para que un job pueda ponerse en marcha o pararse, deben darse ciertas condiciones. Normalmente estas condiciones vienen dadas por la detección o no de ciertos eventos. Por poner un ejemplo gráfico, veamos el job /etc/init/mysql.conf que permite lanzar o parar mysql en función de la detección de ciertos eventos.
# MySQL Service description "MySQL Server" author "Mario Limonciello <superm1@ubuntu.com>" start on (net-device-up and local-filesystems and runlevel [2345]) stop on runlevel [016] [...] exec /usr/sbin/mysqld [...] |
En resumidas cuentas, el job mysql viene a decir que el daemon mysqld se pondrá en marcha cuando se detecte red (net-device-up), el sistema de ficheros haya sido montado (local-filesystems) y el nivel de ejecución sea uno entre 2 y 5 (Ubuntu en modo gráfico arranca por defecto en el nivel 2). Si se detecta un evento runlevel 0 ó 1 ó 6 entonces el daemon mysqld se parará.
En Ubuntu Natty, Upstart introdujo el comando initctl2dot, que permite ver gráficamente estas dependencias (además de ayudarnos a detectar quién emite cada evento en cuestión).
Por ejemplo, tecleando:
initctl2dot -r mysql -o - | dot -Tpng -o upstart.png
Obtenemos la siguiente imagen:
Los jobs se muestran en cajas grises. Las líneas azules apuntan a los eventos cuya emisión arrancarían el job. Las líneas rojas indican qué eventos provocarían la parada de mysql. Las líneas verdes unen un evento con el job que lo emite.
Si te preguntas quién emite net-device-up (en el diagrama no hay ningún job que lo emita), puedes realizar una búsqueda desde /etc así:
/etc/$ grep -irn "net-device-up" * |
y verás que lo hace el script if-up cada vez que se activa una tarjeta de red.
Emitir manualmente un evento
Tal y como se aprecia en la imagen anterior, es posible forzar la emisión de un evento. Para ello, desde la línea de comandos, basta con ejecutar:
$ sudo initctl emit nombre_del_evento |
Curiosidades
El primer evento que Upstart genera es startup.
Upstart tiene como uno de sus objetivos ser compatible con SysV init. Por ello, simula eventos runlevel y establece un DEFAULT_RUNLEVEL a través del job /etc/init/rc-sysinit.conf.