Este es uno de los capítulos del tutorial Automatización con Ansible. Una introducción.. Encontrarás los enlaces a todos los de capítulos, al final de este artículo.
Hasta el momento todo lo que has visto para Ansible no permitía hacer mas que un flujo lineal. Tenías una lista de tareas, y esta lista se ejecutaba de forma totalmente secuencial, una tarea detrás de otra. Sin embargo, esto está a punto de cambiar, porque es posible decidir si ejecutar una tarea en función del resultado de otra. Es mas, es posible ejecutar una tarea repetidas veces. Si, efectivamente, en Ansible también tienes la herramientas para controlar el flujo de las tareas que tienes que realizar, para ello, Ansible pone a tu disposición los bucles y condicionales.
Así, en este nuevo capitulo de este tutorial encontrarás como controlar ese flujo de ejecución de tareas en un playbook, y por supuesto decidir cuando ejecutar una u otra, o repetir algunas de estas tareas.
Bucles y condicionales en Ansible
Voy directo al grano, y empezaré con la parte correspondientes a los condicionales en Ansible para decidir cuando ejecutar una tarea en función, ya sea a las tareas previas o otros condicionales.
El condicional when
Existen diferentes situaciones bajo las que puedes no querer ejecutar una determinada tarea, por ejemplo, que sea una determinada distribución, o incluso una determinada versión de una determinada distribución. A modo de ejemplo sencillo,
---
- hosts: all
gather_facts: yes
tasks:
- name: lists
shell: ls -la /
when: ansible_facts.distribution == 'Ubuntu'
- name: debug
debug:
msg: "{{ ansible_facts.distribution }}"
En este caso solo se ejecuta el comando indicado en el caso de que la distribución coincida con la que le has indicado. Esto mismo, con variables podía ser algo como lo que te muestro a continuación,
---
- hosts: all
gather_facts: yes
vars:
distribution: Ubuntu
tasks:
- name: lists
shell: ls -la /
register: result
when: ansible_facts.distribution == distribution
En el caso de que quieras considerar varias condiciones, tienes diferentes opciones. Por un lado en el caso de que se tengan que cumplir todas ellas, es decir, el equivalente a un and
, la opción podría ser un listado de condiciones, utilizando para ello el formato de yaml
. Por ejemplo,
---
- hosts: all
gather_facts: yes
vars:
distribution: Ubuntu
tasks:
- name: lists
shell: ls -la /
register: result
when:
- ansible_facts.distribution == distribution
- ansible_facts.os_family == "Debian"
Esto mismo lo podrías ejecutar, pero en lugar de expresar el condicional tal y como has visto en el ejemplo anterior, sería como te muestro a continuación,
when: (ansible_facts.distribution == 'Ubuntu') and
(ansible_facts.os_family == 'Debian')
Como te puedes imaginar, igual que expresas el and
también lo puedes hacer con el or
.
Bucles
El siguiente paso para el control de flujo en Ansible mediante bucles y condicionales, ahora que ya has visto when
, son los bucles.
Ansible te da dos opciones para crear bucles. La opción mas clásica es with_<item>
, mientras que en la versión 2.5 de Ansible se incorporó loop
. Si bien, esta segunda, no es un reemplazo completo a la primera, si que la recomiendan por encima de ella. En este sentido, voy a obviar tratar la primera de las opciones, y centrarme directamente en loop
.
Vas a empezar con una lista de elementos, bien sencillita, para que veas que esto no tiene ninguna complicación, al menos a priori. Así por ejemplo,
---
- hosts: all
gather_facts: no
tasks:
- name: print result
debug:
msg: "{{ item }}"
loop:
- 1
- 2
- 3
Vamos a complicarlo con una lista de diccionarios, así, vas a definir para cada uno de los elementos de tu array un nombre de usuario y un grupo de pertenencia. Por ejemplo,
---
- hosts: all
gather_facts: no
tasks:
- name: print result
debug:
msg: "El usuario {{ item.nombre }} pertenence a {{ item.grupo }}"
loop:
- {nombre: "lorenzo", grupo: "usuarios"}
- {nombre: "jose", grupo: "usuarios"}
- {nombre: "fermin", grupo: "administradores"}
- {nombre: "alberto", grupo: "administradores"}
Otra cuestión interesante es que puedes repetir una determinada tarea hasta que se cumpla una condición concreta; incluso esperar un tiempo entre cada una de las repeticiones. Para ello tienes que utilizar until
en combinación con retries
, para indicar el número de veces que se tiene que ejecutar y junto a delay
, para marcar el tiempo entre ejecuciones.
Un poquito de control en los bucles
Una cuestión interesante de los bucles loop
es que permiten una serie de variables y opciones para mejorar el control en los bucles. Así algunas de las opciones que tienes a tu alcance son las siguientes,
index_var
, te permite definir una variable incremental, de forma que con cada ejecución del bucle se incrementará en uno.pause
, define un tiempo de espera entre una ejecución y la siguiente.
Así, por ejemplo, el ejemplo anterior, se puede convertir en lo siguiente,
---
- hosts: all
gather_facts: no
tasks:
- name: print result
debug:
msg: "{{ indice }}. El usuario {{ item.nombre }} pertenence a {{ item.grupo }}"
loop:
- {nombre: "lorenzo", grupo: "usuarios"}
- {nombre: "jose", grupo: "usuarios"}
- {nombre: "fermin", grupo: "administradores"}
- {nombre: "alberto", grupo: "administradores"}
loop_control:
index_var: indice
pause: 1
register: result
- name: echo
debug:
msg: "{{ result }}"
Combinando bucles y condicionales en Ansible
Por supuesto, lo interesante ahora es combinar bucles y condicionales en Ansible, para de esta forma sacarle algo mas de partido a todo esto. Así, puedes combinar los ejemplos anteriores,
---
- hosts: all
gather_facts: no
tasks:
- name: print result
debug:
msg: "{{ indice }}. El usuario {{ item.nombre }} pertenence a {{ item.grupo }}"
register: result
when:
- indice > 1
- indice < 4
loop:
- {nombre: "lorenzo", grupo: "usuarios"}
- {nombre: "jose", grupo: "usuarios"}
- {nombre: "fermin", grupo: "administradores"}
- {nombre: "alberto", grupo: "administradores"}
loop_control:
index_var: indice
pause: 1
label: "{{ item.nombre }}"
- name: echo
debug:
msg: "{{ result }}"
Es un ejemplo un poco simple, pero se trata de mostrarte diferentes opciones y posibilidades. Todavía nos queda un trecho por recorrer y no se trata de quemar los barcos antes de zarpar.
Conclusiones
Esto son posiblemente las opciones mas básicas a la hora de realizar bucles y condicionales en Ansible. Desde luego que esto no es mas que la punta del iceberg. Además de estos que son relativamente simples, tienes que añadir, todo el potencial de los módulos que veremos en un capítulo posterior de este mismo tutorial.
Imagen de portada de Tine Ivanič en Unsplash
Gracias por el esfuerzo y dedicación para crear y compartir los conocimientos. El saber debe ser libre y accesible a tod@s.
Muy buen tutorial.