¡Esta es una revisión vieja del documento!
Tabla de Contenidos
Ansible: Conceptos avanzados
Sección perteneciente al curso Ansible Automatización IT
¿Qué es YAML y por qué es importante conocerlo?
YAML es un formato de serialización de datos , legible por humanos, que está inspirado en lenguajes como XML.
YAML es un superconjunto del formato JSON, que permite añadir estructuras más complejas e incluso comentarios.
En el mundo Ansible, todos los playbooks están escritos en YAML.
Reglas generales:
- Extensión
.yaml(recomendada) o.yml - Las tabulaciones no están permitidas, solo los espacios.
- Es necesario identar (sangrar) el código uno o más espacios.
- Todas las claves/propiedades son case-sensitive (se distingue mayúsculas de minúsculas).
- Los comentarios empiezan con un símbolo
#.
Ejemplo de un playbook en YAML:
hosts: webservers sudo: yes vars: app_name: PleaseDeployMe repo_url: https://github.com/username/reponame.git repo_remote: origin repo_version: master webapps_dir: /deployed virtualenv_root: /deployed/PleaseDeployMe/mac tasks: - name: git pull project git: repo={{repo_url}} dest={{webapps_dir}}/{{app_name}} version=master
Tipos de datos
Cadenas de texto
--- foo: Esta es una cadena de texto
Los tres guiones indican el inicio del fichero.
Para meter caracteres especiales, hay que meterlos entre comillas:
--- foo: Esta es una cadena de texto "\n" estoy en una línea nueva.
Booleanos
True es lo mismo que On; False es lo mismo que Off.
--- foo: True bar: False light: On TV: Off
Números
Soporta números decimales, hexadecimales…
--- foo: 12345 bar: 0x12d4 plop: 023332
Array / listas
--- items: [1, 2, 3, 4, 5] names: ["one", "two", "three", "four", "five"]
También se podría escribir en el siguiente formato:
items: - 1 - 2 - 3 - 4 - 5
Diccionarios
--- foo: {thing1: huey, thing2: louie, thing3: dewey}
Los diccionarios se pueden anidar con otros elementos:
--- foo: bar: - bar - rgb - plob
El diccionario bar tiene dentro una lista de 3 elementos.
Variables
Permiten almacenar y reusar información. Las variables se procesan en orden, de mayor a menor preferencia:
- Variables por línea de comandos
- Variables en tareas
- Variables en roles y secciones
include - Variables creadas con la directiva
register - Variables en los inventarios
- Variables en las plays
- Host facts
- Variables por defecto en los roles
En la documentación oficial de Ansible se habla hasta de 15 niveles de prioridad.
Reglas a la hora de definir variables en Ansible:
- Deben comenzar con letra
- Pueden contener letras, números y guiones bajos.
Tareas, Plays y Playbooks I
Una tarea es la aplicación de un módulo en un playbook para realizar una acción específica sobre un equipo.
Algunas tareas:
file: un directorio debe existir.yum: un paquete tiene que estar instalado.service: un servicio tiene que estar ejecutándose.template: se quiere cargar una configuración en un template.get_url: se quiere descargar un fichero de una URL.git: se quiere clonar el código fuente desde un repositorio.
Ejemplo de la sección de tareas en un fichero YAML de Ansible:
tasks: - name: httpd package is present yum: name: httpd state: latest - name: latest index.html file is present copy: scr: files/index.html dest: /var/www/html/ - name: restart httpd service: name: httpd state: restarted
Plays y Playbooks
Una play consiste en un conjunto ordenado de tareas que se ejecutan en los hosts seleccionados sobre un inventario. Un playbook es un fichero que contiene una o más plays:
A continuación vemos un ejemplo de un Playbook con una sola play:
--- - name: install and start apache hosts: web become: yes vars: http_port: 80 tasks: - name: httpd package is present yum: name: httpd state: latest - name: latest index.html file is present copy: scr: files/index.html dest: /var/www/html/
Ansible permite importar playbooks con la palabra clave import_playbook.
Ejemplo de nuestro primer playbook (primer_playbook.yaml):
# Este es nuestro primer playbook - name: primera play hosts: all gather_facts: false # para que no traiga los facts por defecto tasks: - name: comprobar conexión ping: data: functionando
Lo ejecutamos:
ansible-playbook -i /home/pepito/inventario -u ansible_user --key-file /home/pepito/.ssh/id_rsa primer_playbook.yaml
También podríamos añadirle la opción -v para obtener más información de la salida:
ansible-playbook -i /home/pepito/inventario -u ansible_user --key-file /home/pepito/.ssh/id_rsa primer_playbook.yaml -v
Poner ejemplo de la salida del comando anterior.
Podemos revisar la sintaxis del Playbook sin ejecutarlo:
ansible-playbook primer_playbook.yaml --syntax-check
Tareas, Plays y Playbooks II
Vamos a coger el playbook de la sección anterior y complicarlo un poco más añadiéndole otra play:
# Este es nuestro primer playbook - name: primera play hosts: all gather_facts: false # para que no traiga los facts por defecto tasks: - name: comprobar conexión ping: data: funcionando - name: segunda play hosts: servidor_web gather_facts: false tasks: - name: listar directorios command: ls - name: instalar nginx apt: name=nginx state=present
Antes de ejecutar, revisamos la sintaxis del fichero:
ansible-playbook primer_playbook.yaml --syntax-check
Si todo va bien, ejecutamos el playbook:
ansible-playbook -i /home/pepito/inventario -u ansible_user --key-file /home/pepito/.ssh/id_rsa primer_playbook.yaml -v
Vemos que falla porque no el usuario no tiene permisos para instalar el paquete nginx. Podemos indicar que necesitamos elevar privilegios con become: yes:
# Este es nuestro primer playbook - name: primera play hosts: all gather_facts: false # para que no traiga los facts por defecto tasks: - name: comprobar conexión ping: data: funcionando - name: segunda play hosts: servidor_web become: yes gather_facts: false tasks: - name: listar directorios command: ls - name: instalar nginx apt: name=nginx state=present
En la máquina destino, tenemos que evitar que pida la contraseña el usar sudo. Para ello, hay que editar el fichero /etc/sudoers y la línea que comienza por %sudo dejarla de la siguiente manera:
%sudo ALL=(ALL) NOPASSWD: ALL
Modificamos más el playbook para incluir variables:
# Este es nuestro primer playbook - name: primera play hosts: all gather_facts: false # para que no traiga los facts por defecto tasks: - name: comprobar conexión ping: data: funcionando - name: segunda play hosts: servidor_web become: yes gather_facts: false vars: state: absent tasks: - name: listar directorios command: ls - name: instalar nginx apt: name=nginx state={{ state }}
Lo que añadamos entre llaves ({{}}) se sustituirá por el valor que le hayamos dado. En este caso state es absent, así que es lo mismo que si hubiéramos puesto:
apt: name=nginx state=absent
Si ejecutamos ahora ese playbook, desinstalará nginx.
Qué son los handlers y para qué se usan
Los handlers son tareas especiales que se ejecutan al final de una play si son notificadas por otra tarea cuando ocurre un cambio.
tasks: - name: httpd package is present yum: name: httpd state: latest notify: restart httpd - name: latest index.html file is present copy: src: files/index.html dest: /var/www/html handlers: - name: restart httpd service: name: httpd state: restarted
Los handlers se definen al final del Playbook
Seguimos trabajando con nuestro playbook:
# Este es nuestro primer playbook - name: primera play hosts: all gather_facts: false # para que no traiga los facts por defecto tasks: - name: comprobar conexión ping: data: funcionando - name: segunda play hosts: servidor_web become: yes gather_facts: false vars: state: present tasks: - name: listar directorios command: ls - name: instalar nginx apt: name=nginx state="{{ state }}" - name: copiar index copy: src: index.html dest: /var/www/html - name: reiniciar nginx service: name: nginx state: restarted
Lo ejecutamos:
ansible-playbook -i /home/pepito/inventario -u ansible_user --key-file /home/pepito/.ssh/id_rsa primer_playbook.yaml -vv
Si observamos el resultado, vemos que el servidor web nginx se reinicia, pero esto no nos interesa. Queremos que se reinicie solo cuando sea necesario. Aquí entran en escena los handlers:
# Este es nuestro primer playbook - name: primera play hosts: all gather_facts: false # para que no traiga los facts por defecto tasks: - name: comprobar conexión ping: data: funcionando - name: segunda play hosts: servidor_web become: yes gather_facts: false vars: state: present tasks: - name: listar directorios command: ls - name: instalar nginx apt: name=nginx state="{{ state }}" notify: reiniciar nginx # Mismo nombre que el handler - name: copiar index copy: src: index.html dest: /var/www/html handlers: - name: reiniciar nginx service: name: nginx state: restarted
Si lanzamos ahora el playbook, conseguiremos que solo se reinice nginx cuando se instale.
Vamos a pasar variables por línea de comando con la opción -e:
ansible-playbook -i /home/pepito/inventario -u ansible_user --key-file /home/pepito/.ssh/id_rsa primer_playbook.yaml -vv -e "state=absent"
Ansible, en lugar de usar la varible state definida en el playbook, aplica la que pasamos por la línea de comandos. Por tanto, se eliminará nginx.
Condicionales
Ansible permite incluir condiciones a la hora de ejecutar las tareas basándose en la evaluación de una variable, fact u otra tarea previa en tiempo de ejecución.
--- - name: install Apache webserver hosts: all tasks: - name: Install Apache on Ubuntu Server apt: name=apache2 state=present become: yes when: ansible_os_family == "Debian" and ansible_distribution_version == "18.04"
Trabajando con nuestro primer_playbook.yaml:
# Este es nuestro primer playbook - name: primera play hosts: all # gather_facts: true tasks: - name: comprobar conexión ping: data: funcionando - name: segunda play hosts: servidor_web become: yes gather_facts: false vars: state: present tasks: - name: listar directorios command: ls when: ansible_os_family == "RedHat" - name: instalar nginx apt: name=nginx state="{{ state }}" notify: reiniciar nginx # Mismo nombre que el handler - name: copiar index copy: src: index.html dest: /var/www/html handlers: - name: reiniciar nginx service: name: nginx state: restarted
Poner ejemplo de salida
Veremos ahora el uso de condicionales utilizando una variable que hemos usado como salida de una tarea:
# Este es nuestro primer playbook - name: primera play hosts: all # gather_facts: true tasks: - name: comprobar conexión ping: data: funcionando - name: segunda play hosts: servidor_web become: yes gather_facts: false vars: state: present tasks: - name: listar directorios command: ls register: contenido # registro de la salida de 'ls' - name: comprobar ficheros debug: msg: "El directorio no está vacío" when: contenido.stdout != "" - name: instalar nginx apt: name=nginx state="{{ state }}" notify: reiniciar nginx # Mismo nombre que el handler - name: copiar index copy: src: index.html dest: /var/www/html handlers: - name: reiniciar nginx service: name: nginx state: restarted
Poner ejemplo de salida de ejecución del anterior playbook
Tags
Los tags permiten ejecutar un subconjunto de tareas en un playbook.
# Este es nuestro primer playbook - name: primera play hosts: all # gather_facts: true tasks: - name: comprobar conexión ping: data: funcionando - name: segunda play hosts: servidor_web become: yes gather_facts: false vars: state: present tasks: - name: listar directorios command: ls register: contenido # registro de la salida de 'ls' tags: - listar - name: comprobar ficheros debug: msg: "El directorio no está vacío" when: contenido.stdout != "" - name: instalar nginx apt: name=nginx state="{{ state }}" notify: reiniciar nginx # Mismo nombre que el handler - name: copiar index copy: src: index.html dest: /var/www/html handlers: - name: reiniciar nginx service: name: nginx state: restarted
Lo ejecutamos añadiendo la opción %%–tags:
ansible-playbook -i /home/pepito/inventario -u ansible_user --key-file /home/pepito/.ssh/id_rsa primer_playbook.yaml -vv --tags "listar"
Poner ejemplo de salida del comando anterior.
También podríamos incluir tags en una play entera:
# Este es nuestro primer playbook - name: primera play hosts: all # gather_facts: true tasks: - name: comprobar conexión ping: data: funcionando - name: segunda play hosts: servidor_web become: yes tags: segunda_play gather_facts: false vars: state: present tasks: - name: listar directorios command: ls register: contenido # registro de la salida de 'ls' tags: - listar - name: comprobar ficheros debug: msg: "El directorio no está vacío" when: contenido.stdout != "" - name: instalar nginx apt: name=nginx state="{{ state }}" notify: reiniciar nginx # Mismo nombre que el handler - name: copiar index copy: src: index.html dest: /var/www/html handlers: - name: reiniciar nginx service: name: nginx state: restarted
ansible-playbook -i /home/pepito/inventario -u ansible_user --key-file /home/pepito/.ssh/id_rsa primer_playbook.yaml -vv --tags "segunda_play"
Poner ejemplo de salida del comando anterior.
Templates I
Ansible integra el motor de templating jinja2 para:
- Fijar y modificar variables
- Utilizar lógica condicional
- Generar ficheros de configuración utilizando variables
Insertar una variable:
INTERFACES="{{ dhcp_interface }}"
Iterar sobre una lista:
search ws.nsrc.org
{$ for host in use_dns_servers %}
nameserver {{ host }}
{% endfor %}
Se puede probar jinga online por ejemplo desde este Jinja2 live parser
Jinja2 permite utilizar filtros para transformar información almacenada en variables.
Templates II
Usaremos jinja2 con Ansible. Vamos a crear un fichero template_ejemplo.j2:
Hola!
Nginx en la versión {{ version }} se está ejecutando en {{ servidor }}
Modificamos nuestro Playbook para añadir una tercera play:
# Este es nuestro primer playbook - name: primera play hosts: all # gather_facts: true tasks: - name: comprobar conexión ping: data: funcionando - name: segunda play hosts: servidor_web become: yes tags: segunda_play gather_facts: false vars: state: present tasks: - name: listar directorios command: ls register: contenido # registro de la salida de 'ls' tags: - listar - name: comprobar ficheros debug: msg: "El directorio no está vacío" when: contenido.stdout != "" - name: instalar nginx apt: name=nginx state="{{ state }}" notify: reiniciar nginx # Mismo nombre que el handler - name: copiar index copy: src: index.html dest: /var/www/html - name: tercera play hosts: all become: no tags: tercera_play vars: version: "5.13" servidor: "Ubuntu" tasks: - name: imprimir template template: src: template_ejemplo.js # fichero con template Jinja2 dest: /home/ansible/archivo.txt handlers: - name: reiniciar nginx service: name: nginx state: restarted
Revisamos sintaxis:
ansible-playbook --syntax-check primer_playbook.yaml
Lanzamos el playbook centrándonos en la última play que hemos hecho:
ansible-playbook -i /home/pepito/inventario -u ansible_user --key-file /home/pepito/.ssh/id_rsa primer_playbook.yaml -vv --tags "tercera_play"
Si todo ha funcionado bien, se habrá creado el fichero /home/ansible/archivo.txt con el contenido:
Hola! Nginx en la versión 5.13 se está ejecutando en Ubuntu.
Vamos a añadir más variables en la tercera play:
# Este es nuestro primer playbook - name: primera play hosts: all # gather_facts: true tasks: - name: comprobar conexión ping: data: funcionando - name: segunda play hosts: servidor_web become: yes tags: segunda_play gather_facts: false vars: state: present tasks: - name: listar directorios command: ls register: contenido # registro de la salida de 'ls' tags: - listar - name: comprobar ficheros debug: msg: "El directorio no está vacío" when: contenido.stdout != "" - name: instalar nginx apt: name=nginx state="{{ state }}" notify: reiniciar nginx # Mismo nombre que el handler - name: copiar index copy: src: index.html dest: /var/www/html - name: tercera play hosts: all become: no tags: tercera_play vars: version: "5.13" servidor: "Ubuntu" coches: ["Mercedes", "Nissan", "Renault", "Ford"] tasks: - name: imprimir template template: src: template_ejemplo.j2 # fichero con template Jinja2 dest: /home/ansible/archivo.txt - name: ejemplo loop con templates template: src: template_ejemplo_2.j2 dest: /home/ansible/archivo_2.txt handlers: - name: reiniciar nginx service: name: nginx state: restarted
Creamos la plantilla template_ejemplo_2.j2:
La lista de coches contiene las siguientes marcas:
{% for item in coches %}
{{ item }}
{% endfor %}
Revisamos sintaxis:
ansible-playbook --syntax-check primer_playbook.yaml
Lanzamos el playbook centrándonos en la última play que hemos hecho:
ansible-playbook -i /home/pepito/inventario -u ansible_user --key-file /home/pepito/.ssh/id_rsa primer_playbook.yaml -vv --tags "tercera_play"
En el equipo destino tendremos un nuevo archivo /home/ansible/archivo_2.txt:
La lista de coches contiene las siguientes marcas: Mercedes Nissan Renault Ford
Si no queremos el espacio tras cada elemento, usaríamos un guion antes del cierre del foreach:
{%- endfor %}
Si queremos que se transforme el texto a todo mayúscula, podemos usar el filtro upper:
La lista de coches contiene las siguientes marcas:
{% for item in coches %}
{{ item | upper }}
{% endfor %}
Finalmente, veremos inyección de variables en código HTML. Creamos el fichero template_ejemplo_3.j2:
<html>
<h1>Nginx se está ejecutando en {{ ansible_hostname }}</h1>
</html>
En nuestro Playbook vamos a añadir una tercera tarea en la tercera play:
# Este es nuestro primer playbook - name: primera play hosts: all # gather_facts: true tasks: - name: comprobar conexión ping: data: funcionando - name: segunda play hosts: servidor_web become: yes tags: segunda_play gather_facts: false vars: state: present tasks: - name: listar directorios command: ls register: contenido # registro de la salida de 'ls' tags: - listar - name: comprobar ficheros debug: msg: "El directorio no está vacío" when: contenido.stdout != "" - name: instalar nginx apt: name=nginx state="{{ state }}" notify: reiniciar nginx # Mismo nombre que el handler - name: copiar index copy: src: index.html dest: /var/www/html - name: tercera play hosts: all become: yes # para tener permisos para escribir en la carpeta del servidor web tags: tercera_play vars: version: "5.13" servidor: "Ubuntu" coches: ["Mercedes", "Nissan", "Renault", "Ford"] tasks: - name: imprimir template template: src: template_ejemplo.j2 # fichero con template Jinja2 dest: /home/ansible/archivo.txt - name: ejemplo loop con templates template: src: template_ejemplo_2.j2 dest: /home/ansible/archivo_2.txt - name: mostrar un nuevo fichero index template: src: template_ejemplo_3.j2 dest: /var/www/html/index.html mode: 0755 handlers: - name: reiniciar nginx service: name: nginx state: restarted
Revisamos sintaxis:
ansible-playbook --syntax-check primer_playbook.yaml
Lanzamos el playbook centrándonos en la última play que hemos hecho:
ansible-playbook -i /home/pepito/inventario -u ansible_user --key-file /home/pepito/.ssh/id_rsa primer_playbook.yaml -vv --tags "tercera_play"
Bloques y gestión de errores
Los bloques crean grupos lógicos de tareas y además permiten gestionar errores.
Para ignorar errores podemos usar la etiqueta ignore_errors:
# Este es nuestro primer playbook - name: primera play hosts: all # gather_facts: true tasks: - name: comprobar conexión ping: data: funcionando - name: segunda play hosts: servidor_web become: yes tags: segunda_play gather_facts: false vars: state: present tasks: - name: listar directorios command: lz # Ponemos un comando incorrecto a propósito register: contenido # registro de la salida de 'ls' tags: - listar ignore_errors: yes - name: comprobar ficheros debug: msg: "El directorio no está vacío" when: contenido.stdout != "" - name: instalar nginx apt: name=nginx state="{{ state }}" notify: reiniciar nginx # Mismo nombre que el handler - name: copiar index copy: src: index.html dest: /var/www/html - name: tercera play hosts: all become: yes # para tener permisos para escribir en la carpeta del servidor web tags: tercera_play vars: version: "5.13" servidor: "Ubuntu" coches: ["Mercedes", "Nissan", "Renault", "Ford"] tasks: - name: imprimir template template: src: template_ejemplo.j2 # fichero con template Jinja2 dest: /home/ansible/archivo.txt - name: ejemplo loop con templates template: src: template_ejemplo_2.j2 dest: /home/ansible/archivo_2.txt - name: mostrar un nuevo fichero index template: src: template_ejemplo_3.j2 dest: /var/www/html/index.html mode: 0755 handlers: - name: reiniciar nginx service: name: nginx state: restarted
Al ejecutar, dará error cuando llegue a “listar directorios”, pero continuará la ejecución porque le hemos dicho que los ignores.
Vamos a crear dos bloques en nuestro playbook:
# Este es nuestro primer playbook - name: primera play hosts: all # gather_facts: true tasks: - name: comprobar conexión ping: data: funcionando - name: segunda play hosts: servidor_web become: yes tags: segunda_play gather_facts: false vars: state: present tasks: - name: listar directorios y comprobar ficheros block: - name: listar directorios command: lz # Ponemos un comando incorrecto a propósito register: contenido # registro de la salida de 'ls' tags: - listar - name: comprobar ficheros debug: msg: "El directorio no está vacío" when: contenido.stdout != "" - name: instalar nginx y copiar index block: - name: instalar nginx apt: name=nginx state="{{ state }}" notify: reiniciar nginx # Mismo nombre que el handler - name: copiar index copy: src: index.html dest: /var/www/html - name: tercera play hosts: all become: yes # para tener permisos para escribir en la carpeta del servidor web tags: tercera_play vars: version: "5.13" servidor: "Ubuntu" coches: ["Mercedes", "Nissan", "Renault", "Ford"] tasks: - name: imprimir template template: src: template_ejemplo.j2 # fichero con template Jinja2 dest: /home/ansible/archivo.txt - name: ejemplo loop con templates template: src: template_ejemplo_2.j2 dest: /home/ansible/archivo_2.txt - name: mostrar un nuevo fichero index template: src: template_ejemplo_3.j2 dest: /var/www/html/index.html mode: 0755 handlers: - name: reiniciar nginx service: name: nginx state: restarted
Vamos a hacer también una gestión más inteligente de los errores con la etiqueta rescue:
# Este es nuestro primer playbook - name: primera play hosts: all # gather_facts: true tasks: - name: comprobar conexión ping: data: funcionando - name: segunda play hosts: servidor_web become: yes tags: segunda_play gather_facts: false vars: state: present tasks: - name: listar directorios y comprobar ficheros block: - name: listar directorios command: lz # Ponemos un comando incorrecto a propósito register: contenido # registro de la salida de 'ls' tags: - listar - name: comprobar ficheros debug: msg: "El directorio no está vacío" when: contenido.stdout != "" rescue: - name: listar directorios commando: ls - name: instalar nginx y copiar index block: - name: instalar nginx apt: name=nginx state="{{ state }}" notify: reiniciar nginx # Mismo nombre que el handler - name: copiar index copy: src: index.html dest: /var/www/html - name: tercera play hosts: all become: yes # para tener permisos para escribir en la carpeta del servidor web tags: tercera_play vars: version: "5.13" servidor: "Ubuntu" coches: ["Mercedes", "Nissan", "Renault", "Ford"] tasks: - name: imprimir template template: src: template_ejemplo.j2 # fichero con template Jinja2 dest: /home/ansible/archivo.txt - name: ejemplo loop con templates template: src: template_ejemplo_2.j2 dest: /home/ansible/archivo_2.txt - name: mostrar un nuevo fichero index template: src: template_ejemplo_3.j2 dest: /var/www/html/index.html mode: 0755 handlers: - name: reiniciar nginx service: name: nginx state: restarted
Cuando ejecutamos el playbook, al llegar al bloque “listar directorios”, da error, entonces salta a la sección rescue y ejecuta lo que está definido ahí.
También podríamos usar la etiqueta always si queremos que algo se ejecute haya errores o no:
... tasks: - name: listar directorios y comprobar ficheros block: - name: listar directorios command: lz # Ponemos un comando incorrecto a propósito register: contenido # registro de la salida de 'ls' tags: - listar - name: comprobar ficheros debug: msg: "El directorio no está vacío" when: contenido.stdout != "" rescue: - name: listar directorios commando: ls always: - name: mensaje de always debug: msg: "Este código se ejecuta siempre"
Bucles
Los bucles se usan para realizar una tarea múltiples veces, como por ejemplo crear muchos usuarios, instalar varios paquetes, etc.
Se emplea la palabra reservada loop.
Vamos a modificar la primera play de nuestro playbook de ejemplo:
# Este es nuestro primer playbook - name: primera play hosts: all # gather_facts: true tasks: - name: comprobar conexión ping: data: funcionando - name: echo items command: echo "{{ item }}" loop: - uno - dos - name: segunda play hosts: servidor_web become: yes tags: segunda_play gather_facts: false vars: state: present tasks: - name: listar directorios y comprobar ficheros block: - name: listar directorios command: lz # Ponemos un comando incorrecto a propósito register: contenido # registro de la salida de 'ls' tags: - listar - name: comprobar ficheros debug: msg: "El directorio no está vacío" when: contenido.stdout != "" rescue: - name: listar directorios commando: ls - name: instalar nginx y copiar index block: - name: instalar nginx apt: name=nginx state="{{ state }}" notify: reiniciar nginx # Mismo nombre que el handler - name: copiar index copy: src: index.html dest: /var/www/html - name: tercera play hosts: all become: yes # para tener permisos para escribir en la carpeta del servidor web tags: tercera_play vars: version: "5.13" servidor: "Ubuntu" coches: ["Mercedes", "Nissan", "Renault", "Ford"] tasks: - name: imprimir template template: src: template_ejemplo.j2 # fichero con template Jinja2 dest: /home/ansible/archivo.txt - name: ejemplo loop con templates template: src: template_ejemplo_2.j2 dest: /home/ansible/archivo_2.txt - name: mostrar un nuevo fichero index template: src: template_ejemplo_3.j2 dest: /var/www/html/index.html mode: 0755 handlers: - name: reiniciar nginx service: name: nginx state: restarted
Al ejecutar el playbook, veremos en la salida que se muestra esos dos elementos (uno y dos) para cada uno de los equipos del inventario.
Añadimos más cosas:
(...) tasks: - name: comprobar conexión ping: data: funcionando - name: echo items command: echo "{{ item }}" loop: - uno - dos - name: listar inventario debug: msg: "{{ item }}" loop: "{{ groups['all'] }}" (...)
Mostrar salida del comando anterior
Vamos a usar ahora diccionarios:
# Este es nuestro primer playbook - name: primera play hosts: all become: yes gather_facts: true tasks: - name: comprobar conexión ping: data: funcionando - name: echo items command: echo "{{ item }}" loop: - uno - dos - name: listar inventario debug: msg: "{{ item }}" loop: "{{ groups['all'] }}" - name: crear usuarios user: name: "{{ item.name }}" state: present groups: "{{ item.groups }}" loop: - { name: 'user1', groups: 'sudo'} - { name: 'user2', groups: 'sudo'} (...)
Revisamos sintaxis:
ansible-playbook --syntax-check primer_playbook.yaml
Lanzamos el playbook centrándonos en la última play que hemos hecho:
ansible-playbook -i /home/pepito/inventario -u ansible_user --key-file /home/pepito/.ssh/id_rsa primer_playbook.yaml -vv
Si vamos al equipo/s destino, se habrían creado los usuarios user1 y user2 (en Linux podemos mirar el contenido del fichero /etc/passwd.
Si quisiéramos eliminar los usarios, cambiaríamos el valor de state a absent:
(...) - name: crear usuarios user: name: "{{ item.name }}" state: absent groups: "{{ item.groups }}" loop: - { name: 'user1', groups: 'sudo'} - { name: 'user2', groups: 'sudo'} (...)
Qué son los Roles en Ansible
Los roles permiten organizar, paquetizar y reusar nuestro código de forma más práctica.
Tendríamos una estructura de carpetas donde incluiremos los roles que queramos.
site.yamlroles/common/files/: archivos a desplegar en el equipo objetivo.templates/tasks/handlers/vars/defaults/meta/: permite incluir dependencias entre roles
apache/files/templates/tasks/handlers/vars/defaults/
