Uno de los puntos más importantes que tenemos que entender cuando trabajamos con Ansible, es el uso y asignación de variables que se generan de forma dinámica durante la ejecución de un playbook.
En general, una de las maneras más habituales de trabajar con las variables consiste en registrarlas, usando el módulo ansible.builtin.register, para usarlas posteriormente en tareas posteriores. Por ejemplo, con el siguiente playbook, registramos el nombre de cada uno de los hosts e imprimimos el valor registrado:
Playbook simple para registrar una variable. |
Salida del playbook de registro de variable. |
El resultado, como podemos comprobar, es el esperado y la salida que obtenemos se corresponde con la salida del comando hostname en cada uno de los hosts remotos.
Ahora bien ¿que sucede si limito el comando a un solo host? Por ejemplo, si usamos Ansible para configurar un cluster de Kubernetes, podemos construir el comando join utilizado para unir nodos al cluster, a partir de la salida que podemos obtener de uno de los nodos master o al crear un hash de un fichero en uno de los hosts, necesitamos registrar dicho valor para luego emplearlo en el resto de hosts del playbook. De una forma similar, si modificamos nuestro playbook de la siguiente manera:
Playbook modificado limitando la primera tarea a un solo host. |
De esta manera limitamos la ejecución de la primera tarea al host cuyo hostname coincida con el indicado. Al hacer esto, el resultado de la ejecución del playbook será el siguiente:
Resultado de la ejecución del playbook limitado. |
Como era de esperar, la variable se ha registrado pero únicamente para el host en el cual se ha ejecutado la primera tarea, lo que provoca que dicha variable no esté disponible en el conjunto de variables del resto de hosts del playbook.
Este comportamiento se debe a que, durante la ejecución de un playbook, cada host tiene asociado una serie de variables, que se almacenan en un diccionario llamado hostvars. Este conjunto de variables contienen valores que son exclusivos del host, lo que incluye aquellas variables que registremos durante la ejecución del playbook. Cada host tiene asociada un diccionario hostvars que contiene todas las variables del host, incluyendo las registradas durante la ejecución del playbook. Para acceder al diccionario hostvars de un host, es necesario que utilicemos el nombre de dicho host como está registrado en el inventario.
Así, modificando el playbook de nuevo para mostrar la variable registrada nombre_host en el conjunto de variables hostvars de cada uno de los hosts, podemos comprobar que solo existe para uno de ellos:
Mostrando la variable registrada en hostvars. |
Salida resumida de ejecución del playbook anterior. |
Como podemos ver, solamente uno de los hosts tiene registrada dicha variable en su conjunto de variables hostvars. Este comportamiento se mantiene incluso aunque usemos set_fact, ya que aunque dicho módulo permite convertir variables en facts, esto solamente es así para el host que se está procesando en ese momento en el playbook. Si registramos como un fact la variable y ejecutamos el playbook:
Registramos la variable con un fact. |
Salida del playbook. |
Por tanto y en resumen, si necesito utilizar una variable registrada para un único host, lo mejor es que hagamos referencia a la misma accediendo al conjunto de variables de dicho host, mediante el empleo de hostvars:
Referenciando variables en hostvars. |
Salida del playbook anterior. |
Como referencia adicional, podemos ver que Ansible construye diccionarios para almacenar las variables. Para acceder a las variables de estos diccionarios, al igual que en Python, solo tenemos que hacer referencia a la clave cuyo valor queremos obtener. Lo recomendado por Ansible, es referenciar mediante el uso de corchetes [] para indicar los nombres de las claves cuyos valores necesitamos.