Sirin: una herramienta para lanzar playbooks de Ansible bajo demanda.
En el centro llevamos años utilizando Ansible para gestionar los ordenadores del instituto y sin esta herramienta difícilmente los ordenadores se encontrarían en un estado adecuado para desempeñar su función.
Los playbooks
que utilizamos este curso se pueden consultar en:
Estos playbooks
definen toda la configuración que hay que realizar en los equipos a partir de una instalación desatendida. Así se encargan de gestionar el software (ya sea en formato .deb
, flatpak
o snap
), configurar las herramientas y los servicios que se van a utilizar o declarar los usuarios de la máquina.
En un ordenador con disco SSD la ejecución del playbook
justo después de la instalación puede tardar unos 30 minutos —y en alguno de los pocos equipos que quedan con disco mecánico la tarea puede alargarse durante un par de horas—.
Pero Ansible no solo debe ejecutar un playbook
cuando se ha reinstalado un equipo. La configuración de los equipos no es inamovible y con frecuencia se decide instalar alguna nueva herramienta, cambiar la configuración de algún servicio o modificar, por ejemplo, las cuentas de usuario. Todas estas tareas necesitan una nueva ejecución del playbook
actualizado para aplicar los cambios.
Además no siempre que se lanza un playbook
se encuentran encendidos todos los ordenadores a los que afecta. Así que conviene lanzarlo de nuevo cada cierto tiempo para que los cambios se apliquen en los ordenadores cuando los encuentre conectados. Por todo esto hasta ahora se han utilizado un par de tareas de crontab
para para lanzar los playbooks
de Ansible dos veces al día: a las 10h y a las 16h.
Como las tareas de los módulos de Ansible son idempotentes no provocan cambios si no son necesarios. Ejecutar un playbook
en un ordenador que ya está en el estado deseado no provoca ningún cambio y lleva poco más de 1 minuto.
Problema con la ejecución periódica de playbooks.
Sin embargo la ejecución periódica de playbooks
también tiene sus limitaciones:
- No siempre están encendidos (o con red) todos los equipos a los que va dirigido el
playbook
. Esto no es un problema demasiado grave pues Ansible descarta a todos aquellos equipos con los que no puede conectar y continúa con el resto. Pero en herramientas como ARA Records Ansible aparecerán todos loshosts
incluidos aquellos con los que no se ha podido conectar. - Hay equipos esquivos como los portátiles de los carros que se utilizan en el aula. Estos portátiles se sacan del carro y se encienden dependiendo de la materia que se imparte en clase. Evidentemente convendría lanzar el
playbook
cuando estén encendidos, el problema es que cada grupo tiene su propio horario y además este horario puede variar a lo largo del curso.
Por último, ejecutar playbooks
de manera continua para intentar pillar a todos los equipos en algún momento tampoco parece una opción muy eficiente pues consume recursos de manera indiscriminada. Aunque para un equipo que ya está en el estado deseado ejecutar un playbook
no supone mucho trabajo sí que supone algo de trabajo y para el equipo en el que está instalado Ansible y ARA Records Ansible supone un trabajo inútil.
La solución pasa por ejecutar los playbooks
con cierta frecuencia —por ejemplo una vez al día para propagar las nuevas configuraciones con cierta agilidad— pero no en ejecutarlos de manera excesiva. Y además hay que tener en cuenta que no todos los ordenadores estarán encendidos a la vez, especialmente los portátiles tienden a tener un horario de uso irregular.
Al pensar en todo esto he valorado utilizar una herramienta como ansible-pull
que invierte la arquitectura típica de Ansible (push). Con esta herramienta cada equipo descarga de un repositorio git
los playbooks
y después los ejecuta. Quizás la herramienta podría haber sido de utilidad en nuestro caso pero es una opción que no he llegado a valorar demasiado porque me encuentro cómodo con el modo de funcionamiento habitual de Ansible en el que un ordenador conecta con el parque de equipos que gestiona y ejecuta en ellos los playbooks
. Además en ese equipo en nuestro caso se está ejecutando ARA Records Ansible para poder revisar la actividad de todos los equipos de manera centralizada. Y no quiero renunciar a esto.
Сирин / Sirin
Pensando en todo esto la idea que ha ido germinando en mi cabeza es:
- Conviene que los equipos puedan solicitar la ejecución de un
playbook
cuando arrancan. - Alguien debe tomar nota de estas notificaciones o peticiones de los equipos.
- A partir de las peticiones (y en función de cuándo se lanzó en ese equipo por última vez un
playbook
) se pueden lanzar playbooks bajo demanda.
Y esto es básicamente lo que hace Сирин / Sirin: https://github.com/vcarceler/sirin
Sirin es una pequeña aplicación web implementada con Django que:
- Recibe las peticiones de los clientes cada vez que arrancan.
- Proporciona una lista de equipos para utilizar con el parámetro
--limit
del comandoansible-playbook
.
De esta manera se pueden lanzar playbooks
cuando hay ordenadores encendidos para ellos y sin ejecutarlos de manera innecesaria, pues si Sirin recibe una nueva petición de un equipo antes de que transcurra el periodo definido (por defecto EXCLUSION_TIME
son 24h) desde que se tramitó la última simplemente ignora la petición.
Además un timer
de systemd
o una tarea crontab
pueden ir consultando a Sirin cada 15 o 20 minutos para lanzar un playbook
que incluya a todos los equipos con solicitudes pendientes. Y todo esto se puede hacer con gran sencillez para cada grupo de ordenadores que tiene su propio playbook
.
Peticiones de los equipos
En los ordenadores del centro Vasilisa se encarga de realizar una petición web a Sirin 1 minuto después de arrancar.
La petición se puede realizar con el comando wget
. Por ejemplo los ordenadores del aula Torvalds realizan la siguiente petición:
wget http://192.168.10.18:8000/launcher/?label=torvalds-u1804.yml
Sirin recibe:
- La IP del equipo que hace la solicitud
- El parámetro
label
La lógica de Sirin es muy sencilla:
- Si no existe en la BBDD una solicitud previa de este equipo se registra como pendiente de procesar.
- Si existe en la BBDD una solicitud previa de este equipo únicamente se actualiza la petición (como pendiende de procesar) si ha transcurrido
EXCLUSION_TIME
desde la solicitud anterior.
Esto permite registrar la solicitud de un equipo tan pronto como arranca pero ignorarla si recientemente ya se había recibido la petición de este equipo.
El parámetro label
facilita agrupar los equipos por playbook
. Así a la hora de obtener la lista de equipos con peticiones pendientes de procesar se puede filtrar utilizando este parámetro.
Consulta de las peticiones pendientes
Sirin considera pendientes todas aquellas peticiones que se han registrado en su BBDD y para las que todavía no ha devuelto las direcciones de sus hosts para que sean procesados.
Se puede consultar la lista de peticiones pendientes utilizando un navegador web en la dirección http://<IP>:<PORT>/launcher/listpendingrequests
.
Por ejemplo:
Y también desde la línea de comandos ejecutando: python manage.py listpendingrequests
Por ejemplo:
python manage.py listpendingrequests
ID LABEL ADDRESS DATETIME
9 label2 192.168.1.1 2020-12-01 10:42:26
10 label2 192.168.1.2 2020-12-02 00:00:00
11 label1 10.118.10.23 2020-12-27 20:43:46
23 label1 192.168.1.144 2020-12-30 09:31:23
Desde la línea de comandos también se puede obtener el número de peticiones pendientes para una determinada etiqueta ejecutando: python manage.py getnumberofrequests <etiqueta>
Por ejemplo:
python manage.py getnumberofrequests label1
2
De esta manera es posible comprobar si para una etiqueta hay peticiones pendientes y si las hay (o si superan el umbral establecido) lanzar el playbook.
Es importante notar que todas estas operaciones de consulta no modifican la BBDD de Sirin.
Obtención del listado de hosts
para el parámetro --limit
Al lanzar un playbook
con el comando ansible-playbook
es posible utilizar el parámetro --limit
para limitar los equipos afectados.
El comando python manage.py gethosts <label>
permite obtener la lista de equipos con peticiones pendientes para la etiqueta indicada.
Una posible salida del comando es:
python manage.py gethosts label1
10.118.10.23,192.168.1.144,
Es importante notar que cuando Sirin devuelve la IP de una petición pasa a considerarla procesada.
Shell script para procesar las peticiones a Sirin
De tanto en tanto será menester consultar si hay peticiones pendientes de procesar en Sirin y, si es el caso, procesarlas con un playbook
de Ansible.
En el instituto y de manera provisional se utiliza el script procesa_peticiones
:
#!/bin/bash # # Procesa las peticiones pendientes para cada una de las etiquetas. # # venv's python PYTHON="/home/vcarceler/sirin/venv/bin/python" # Sirin's manage.py MANAGE="/home/vcarceler/sirin/sirin/manage.py" # ARA playbooks="/home/vcarceler/playbooks-ubuntu2004" export ANSIBLE_CALLBACK_PLUGINS="$(python3 -m ara.setup.callback_plugins)" for x in esobatx-u2004.yml esobatx_dept-u2004.yml esobatx_wifi-u2004.yml do # Comprobamos si hay peticiones pendientes n=`$PYTHON $MANAGE getnumberofrequests $x` echo "Para la etiqueta $x hay $n peticiones pendientes." if [ $n -gt 0 ] then hosts=`$PYTHON $MANAGE gethosts $x` echo "Lanzo ansible-playbook -i $playbooks/hosts $playbooks/$x --limit=$hosts" ansible-playbook -i $playbooks/hosts $playbooks/$x --limit=$hosts & else echo No hay nada que hacer fi done echo "Esperando que acaben las tareas ansible-playbook..." wait echo "Todos los playbooks de ansible se han completado."
De momento únicamente se ha implementado el nuevo sistema para los equipos de la ESO/BATX pero pronto se hará para el resto de equipos.
Para cada etiqueta se consulta a Sirin por el número de peticiones pendientes y si es superior a 0 se lanza ansible-playbook
con la lista de hosts
proporcionada por Sirin.
Los comandos ansible-playbook
se lanzan como subprocesos (en paralelo) y finalmente se espera con wait
a que todos concluyan. La actividad queda registrada en ARA Records Ansible y en el fichero de registro.
Un timer
para lanzar procesa_peticiones
Para activar el shell script que procesa las peticiones he decidido utilizar un timer
de systemd
con su correspondiente servicio para que cada 15 minutos se compruebe si hay peticiones pendientes.
Fichero: /etc/systemd/system/sirin-ansible.timer
[Unit] Description=Procesa con ansible-playbook las peticiones pendientes [Timer] OnCalendar=*:0/15 [Install] WantedBy=timers.target
Fichero: /etc/systemd/system/sirin-ansible.service
[Unit] Description=Procesa con ansible-playbook las peticiones pendientes [Service] User=vcarceler Group=vcarceler ExecStart=/home/vcarceler/playbooks-ubuntu2004/tools/sirin/procesa_peticiones
Todos los playbooks sin incidencias en ARA Records Ansible
Hasta ahora al lanzar un playbook de Ansible se intentaba conectar con todos los hosts definidos en el playbook y con frecuencia, por no decir siempre, había algún host que no contestaba lo que marcaba el estado del playbook en ARA Records Ansible como un error (por contener hosts con los que no se había podido conectar).
Pero desde que se utiliza Sirin para lanzar los playbooks únicamente se intenta conectar con aquellos hosts que han dado señales de vida, así que en la interfaz de ARA Records Ansible todos los playbooks aparecen con estado OK.
De esta manera resultará mucho más sencillo comprobar de un vistazo que todo ha ido хорошо y prestar atención a los playbooks en los que realmente algún host ha encontrado algún problema.
Aún seguirá siendo posible que un host se apague, o desconecte, después de haber hecho la petición a Sirin y antes de que se lance el playbook o bien durante su ejecución. En este caso sí que aparecerá el playbook con el marcador de estado con problemas, pero supongo que esta no será una situación muy frecuente.