Bucles y condicionales en Ansible

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

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

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *