Técnicas Avanzadas de Manejo de Salida
Ahora que entendemos los conceptos básicos de la captura de la salida de scripts, exploremos algunas técnicas más avanzadas para manejar y mostrar la salida en los playbooks de Ansible.
Manejo de Errores de Script
Al ejecutar scripts, es importante manejar correctamente las condiciones de error. Ansible marca una tarea como fallida si el comando devuelve un código de salida distinto de cero. Creemos un playbook que demuestre el manejo de errores.
Cree un archivo llamado error_handling.yml en su directorio ~/project/ansible-lab:
---
- name: Handling Script Errors
hosts: localhost
gather_facts: no
tasks:
- name: Run a command that might fail
command: ls /nonexistent_directory
register: cmd_result
ignore_errors: yes
- name: Show error message if command failed
debug:
msg: "Command failed with error: {{ cmd_result.stderr }}"
when: cmd_result.rc != 0
- name: Show success message if command succeeded
debug:
msg: "Command succeeded with output: {{ cmd_result.stdout }}"
when: cmd_result.rc == 0
En este playbook:
- Intentamos listar un directorio que no existe
- Usamos
ignore_errors: yes para evitar que el playbook se detenga si el comando falla
- Verificamos el código de retorno (
cmd_result.rc) para determinar si el comando tuvo éxito o falló
- Mostramos mensajes apropiados según el resultado
Ejecutemos este playbook:
cd ~/project/ansible-lab
ansible-playbook -i inventory.ini error_handling.yml
Debería ver una salida similar a:
PLAY [Handling Script Errors] ***********************************************************
TASK [Run a command that might fail] ***************************************************
fatal: [localhost]: FAILED! => {"changed": true, "cmd": ["ls", "/nonexistent_directory"], "delta": "0:00:00.003398", "end": "2023-09-15 12:34:56.789012", "msg": "non-zero return code", "rc": 2, "start": "2023-09-15 12:34:56.785614", "stderr": "ls: cannot access '/nonexistent_directory': No such file or directory", "stderr_lines": ["ls: cannot access '/nonexistent_directory': No such file or directory"], "stdout": "", "stdout_lines": []}
...ignoring
TASK [Show error message if command failed] *********************************************
ok: [localhost] => {
"msg": "Command failed with error: ls: cannot access '/nonexistent_directory': No such file or directory"
}
TASK [Show success message if command succeeded] ****************************************
skipping: [localhost]
PLAY RECAP *******************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=1
Observe que, a pesar de que el comando falla, el playbook continúa ejecutándose y muestra el mensaje de error.
Creemos un script más complejo que genere una salida multilínea, luego formateémosla correctamente en nuestro playbook.
Cree un archivo llamado package_info.sh en su directorio ~/project/ansible-lab:
#!/bin/bash
echo "TOP 5 LARGEST INSTALLED PACKAGES"
echo "================================"
dpkg-query -W -f='${Installed-Size}\t${Package}\n' | sort -n -r | head -5
Hágalo ejecutable:
chmod +x ~/project/ansible-lab/package_info.sh
Ahora cree un playbook para ejecutar este script y formatear la salida correctamente. Cree un archivo llamado formatted_output.yml:
---
- name: Format Script Output
hosts: localhost
gather_facts: no
tasks:
- name: Run package info script
shell: ./package_info.sh
register: pkg_info
- name: Display raw output
debug:
msg: "{{ pkg_info.stdout }}"
- name: Display formatted output with a title
debug:
msg: |
Below is the package information:
--------------------------------
{% for line in pkg_info.stdout_lines %}
{{ line }}
{% endfor %}
--------------------------------
Total lines: {{ pkg_info.stdout_lines | length }}
Este playbook:
- Ejecuta nuestro script
package_info.sh
- Muestra la salida sin formato
- Usa una plantilla Jinja2 para formatear la salida con un título y un pie de página
Ejecutémoslo:
ansible-playbook -i inventory.ini formatted_output.yml
Debería ver una salida bien formateada:
PLAY [Format Script Output] ***********************************************************
TASK [Run package info script] ********************************************************
changed: [localhost]
TASK [Display raw output] *************************************************************
ok: [localhost] => {
"msg": "TOP 5 LARGEST INSTALLED PACKAGES\n================================\n112233\tsome-large-package\n99887\tanother-package\n...\n"
}
TASK [Display formatted output with a title] ******************************************
ok: [localhost] => {
"msg": "Below is the package information:\n--------------------------------\nTOP 5 LARGEST INSTALLED PACKAGES\n================================\n112233\tsome-large-package\n99887\tanother-package\n...\n--------------------------------\nTotal lines: 7"
}
PLAY RECAP ****************************************************************************
localhost : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Visualización Condicional de Salida
A veces, solo desea mostrar la salida bajo ciertas condiciones, como cuando se ejecuta en modo detallado. Veamos cómo hacer esto.
Cree un archivo llamado conditional_output.yml en su directorio ~/project/ansible-lab:
---
- name: Conditional Output Display
hosts: localhost
gather_facts: yes
tasks:
- name: Get disk usage information
shell: df -h
register: disk_info
- name: Display disk usage (always shown)
debug:
msg: "{{ disk_info.stdout_lines[0:2] }}"
- name: Display detailed disk usage (only in verbose mode)
debug:
msg: "{{ disk_info.stdout_lines }}"
verbosity: 1
En este playbook:
- Capturamos la información de uso del disco
- Siempre mostramos un resumen (las dos primeras líneas)
- Mostramos los detalles completos solo cuando se ejecuta en modo detallado (con la bandera
-v)
Ejecutémoslo primero en modo normal:
ansible-playbook -i inventory.ini conditional_output.yml
Ahora, ejecutémoslo en modo detallado:
ansible-playbook -i inventory.ini conditional_output.yml -v
Notará que en modo detallado, obtiene la información completa del uso del disco, mientras que en modo normal, solo ve el resumen.
Esta técnica es útil para ocultar la salida potencialmente sensible o abrumadora de forma predeterminada, a la vez que la hace disponible cuando es necesaria para la depuración.