Plantilla que se rellena, handler que espera
Una plantilla de Ansible es un archivo de texto con huecos que se rellenan con variables, escrito en el lenguaje Jinja2. Un handler es una tarea que solo se ejecuta cuando otra avisa de que cambió algo.
Juntos reescriben un archivo de configuración y avisan a un servicio solo cuando el archivo ha cambiado de verdad. Aquí el archivo es el recibo de una librería.
Al final de esta lección
Nota
Puedo rellenar una plantilla con variables y explicar cuántas veces se ejecuta un handler.
Palabras clave
| Palabra | Qué significa | Ejemplo |
|---|---|---|
| Plantilla | un archivo de texto con huecos para variables | recibo.txt.j2 |
| Jinja2 | el lenguaje de las plantillas de Ansible | |
| Bucle for | repite un trozo de la plantilla por cada elemento | {% for l in lineas %} |
| Condición if | escribe un trozo solo si algo es cierto | {% if envio %} |
| Handler | una tarea que espera un aviso y corre una sola vez | |
| notify | la palabra con que una tarea avisa a un handler |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Jinja2 rellena huecos, repite y decide
En una plantilla, {{ tienda }} es un hueco que se sustituye por el valor de la variable. {% for l in lineas %} repite lo que sigue, hasta {% endfor %}, una vez por elemento.
{% if envio %} escribe el trozo hasta {% endif %} solo si la variable es cierta. Las etiquetas con {% no escriben nada: el módulo template quita su línea.
Crea una carpeta de trabajo
mkdir -p ~/recibosSe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Entra en ella
cd ~/recibosSe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Escribe la plantilla del recibo
printf '%s\n' 'Recibo de {{ tienda }}' '{% for l in lineas %}' '{{ l.nombre }}: {{ l.precio }} {{ moneda }}' '{% endfor %}' '{% if envio %}' 'Incluye envio' '{% endif %}' > recibo.txt.j2Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Lee la plantilla
cat recibo.txt.j2Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Ejemplo: de la plantilla al recibo
| Línea de la plantilla | Con los datos de la tienda | Resultado |
|---|---|---|
| Recibo de {{ tienda }} | tienda = Libreria Sol | Recibo de Libreria Sol |
| {{ l.nombre }}: {{ l.precio }} {{ moneda }} | Cuaderno, 3 y EUR | Cuaderno: 3 EUR |
| Lo mismo, otra vuelta del for | Boligrafo, 2 y EUR | Boligrafo: 2 EUR |
| Incluye envio, dentro del if | envio = false | No se escribe |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Una ejecución en seco muestra los cambios
El playbook guarda las variables en su play y usa la plantilla con el módulo template. La tarea avisa con notify a un handler llamado Avisar a caja. Otra tarea escribe un sello y avisa al mismo.
La opción --check --diff hace una ejecución en seco: no escribe nada y muestra qué cambiaría. El grep deja solo las líneas que se añadirían.
Escribe el playbook con su handler
printf -- '---\n- hosts: all\n gather_facts: false\n vars:\n tienda: Libreria Sol\n moneda: EUR\n lineas:\n - {nombre: Cuaderno, precio: 3}\n - {nombre: Boligrafo, precio: 2}\n envio: false\n tasks:\n - name: Escribir el recibo\n ansible.builtin.template:\n src: recibo.txt.j2\n dest: /tmp/iac-recibo.txt\n mode: "0644"\n notify: Avisar a caja\n - name: Poner un sello\n ansible.builtin.copy:\n content: "sello\\n"\n dest: /tmp/iac-sello.txt\n mode: "0644"\n notify: Avisar a caja\n handlers:\n - name: Avisar a caja\n ansible.builtin.debug:\n msg: caja avisada\n' > site.ymlSe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Haz una ejecución en seco
ansible-playbook -i localhost, -c local site.yml --check --diff | grep -E "^\+[A-Za-z]"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Un handler corre una sola vez, al final
Un handler no corre cuando se le avisa, sino al final del play, una sola vez aunque varias tareas hayan avisado. Y solo corre si alguna de ellas cambió algo.
Si una tarea necesita antes el trabajo del handler, la tarea especial meta: flush_handlers lo ejecuta en ese punto. Las órdenes siguientes ejecutan el playbook y cuentan.
Ejecuta el playbook por primera vez
ansible-playbook -i localhost, -c local site.yml | grep -E "RUNNING HANDLER|changed="Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Lee el recibo que escribió
cat /tmp/iac-recibo.txtSe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Ejecútalo otra vez
ansible-playbook -i localhost, -c local site.yml | grep -E "RUNNING HANDLER|changed="Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Un error frecuente
Advertencia
Mucha gente cree que un handler corre cada vez que una tarea le avisa. No es así. Corre una vez al final, y solo si algo cambió. Si ejecutas el playbook por segunda vez y nada cambia, el handler no corre ninguna vez.
Cambia una variable desde la orden
ansible-playbook -i localhost, -c local site.yml -e envio=true | grep -E "RUNNING HANDLER|changed="Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Ejemplo: tres ejecuciones y sus handlers
| Ejecución | Tareas que cambian | Veces que corre el handler |
|---|---|---|
| La primera | Las dos: el recibo y el sello | 1 |
| La segunda, igual | Ninguna | 0 |
| Con -e envio=true | Una: el recibo, con la línea nueva | 1 |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Para ir más lejos
Cambia en site.yml la línea envio: false por envio: true y ejecuta el playbook. Antes de pulsar, di cuántos handlers correrán.
Después añade una tercera tarea que avise al mismo handler y comprueba que sigue corriendo una sola vez.