Ejecución Condicional Basada en la Salida del Shell
Una de las capacidades más poderosas de Ansible es la capacidad de tomar decisiones basadas en la salida de los comandos de shell. En este paso, aprenderemos a usar condiciones y filtros para procesar la salida de los comandos de shell y hacer que los playbooks sean más dinámicos.
Uso de Condiciones con la Salida del Shell
Creemos un playbook que tome decisiones basadas en la salida del comando de shell:
- Cree un nuevo archivo llamado
conditional_playbook.yml en el directorio /home/labex/project.
- Agregue el siguiente contenido:
---
- name: Conditional Tasks Based on Command Output
hosts: local
gather_facts: no
tasks:
- name: Check disk space
shell: df -h / | grep -v Filesystem | awk '{print $5}' | sed 's/%//'
register: disk_usage
- name: Display disk usage
debug:
msg: "Current disk usage: {{ disk_usage.stdout }}%"
- name: Disk usage warning
debug:
msg: "WARNING: Disk usage is high"
when: disk_usage.stdout|int > 50
- name: Disk usage normal
debug:
msg: "Disk usage is normal"
when: disk_usage.stdout|int <= 50
Este playbook:
- Ejecuta un comando de shell para verificar el porcentaje de uso del disco en el sistema de archivos raíz
- Utiliza la condición
when basada en la salida del comando
- Utiliza el filtro
int para convertir la salida de la cadena en un entero para la comparación
Ejecute el playbook:
ansible-playbook -i inventory.ini conditional_playbook.yml
La salida variará según el uso real de su disco, pero se verá algo como esto:
PLAY [Conditional Tasks Based on Command Output] ******************************
TASK [Check disk space] *******************************************************
changed: [localhost]
TASK [Display disk usage] *****************************************************
ok: [localhost] => {
"msg": "Current disk usage: 38%"
}
TASK [Disk usage warning] *****************************************************
skipped: [localhost]
TASK [Disk usage normal] ******************************************************
ok: [localhost] => {
"msg": "Disk usage is normal"
}
PLAY RECAP ********************************************************************
localhost : ok=3 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
Observe cómo Ansible ejecutó solo una de las tareas condicionales en función del valor real del uso del disco.
Manejo de la Salida JSON de los Comandos
Muchas herramientas CLI modernas devuelven datos en formato JSON. Ansible tiene capacidades integradas para manejar la salida JSON:
- Cree un nuevo archivo llamado
json_output.yml en el directorio /home/labex/project.
- Agregue el siguiente contenido:
---
- name: Handling JSON Output
hosts: local
gather_facts: no
tasks:
- name: Create a JSON file for testing
copy:
dest: /tmp/services.json
content: |
{
"services": [
{
"name": "web",
"status": "running",
"port": 80
},
{
"name": "database",
"status": "stopped",
"port": 5432
},
{
"name": "cache",
"status": "running",
"port": 6379
}
]
}
- name: Read JSON file with shell
shell: cat /tmp/services.json
register: json_output
- name: Parse and display JSON content
debug:
msg: "{{ json_output.stdout | from_json }}"
- name: Extract and display service information
debug:
msg: "Service: {{ item.name }}, Status: {{ item.status }}, Port: {{ item.port }}"
loop: "{{ (json_output.stdout | from_json).services }}"
- name: Show only running services
debug:
msg: "Running service: {{ item.name }} on port {{ item.port }}"
loop: "{{ (json_output.stdout | from_json).services }}"
when: item.status == "running"
Este playbook:
- Crea un archivo JSON de muestra para la demostración
- Lee el archivo JSON con un comando de shell
- Utiliza el filtro
from_json para analizar la cadena JSON en una estructura de datos
- Itera a través de la estructura de datos para mostrar información
- Utiliza la lógica condicional para filtrar solo los servicios en ejecución
Ejecute el playbook:
ansible-playbook -i inventory.ini json_output.yml
Debería ver una salida similar a esta:
PLAY [Handling JSON Output] ***************************************************
TASK [Create a JSON file for testing] *****************************************
changed: [localhost]
TASK [Read JSON file with shell] **********************************************
changed: [localhost]
TASK [Parse and display JSON content] *****************************************
ok: [localhost] => {
"msg": {
"services": [
{
"name": "web",
"port": 80,
"status": "running"
},
{
"name": "database",
"port": 5432,
"status": "stopped"
},
{
"name": "cache",
"port": 6379,
"status": "running"
}
]
}
}
TASK [Extract and display service information] ********************************
ok: [localhost] => (item={'name': 'web', 'status': 'running', 'port': 80}) => {
"msg": "Service: web, Status: running, Port: 80"
}
ok: [localhost] => (item={'name': 'database', 'status': 'stopped', 'port': 5432}) => {
"msg": "Service: database, Status: stopped, Port: 5432"
}
ok: [localhost] => (item={'name': 'cache', 'status': 'running', 'port': 6379}) => {
"msg": "Service: cache, Status: running, Port: 6379"
}
TASK [Show only running services] *********************************************
ok: [localhost] => (item={'name': 'web', 'status': 'running', 'port': 80}) => {
"msg": "Running service: web on port 80"
}
skipped: [localhost] => (item={'name': 'database', 'status': 'stopped', 'port': 5432})
ok: [localhost] => (item={'name': 'cache', 'status': 'running', 'port': 6379}) => {
"msg": "Running service: cache on port 6379"
}
PLAY RECAP ********************************************************************
localhost : ok=5 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Observe cómo el playbook analiza el JSON, extrae información específica y filtra los datos en función de las condiciones.
Manejo de Errores con Comandos de Shell
Al ejecutar comandos de shell, es importante manejar los posibles errores con elegancia:
- Cree un nuevo archivo llamado
error_handling.yml en el directorio /home/labex/project.
- Agregue el siguiente contenido:
---
- name: Error Handling with Shell Commands
hosts: local
gather_facts: no
tasks:
- name: Run a potentially failing command
shell: grep "nonexistent_pattern" /etc/passwd
register: command_result
ignore_errors: yes
- name: Display success or failure
debug:
msg: "Command {{ 'succeeded' if command_result.rc == 0 else 'failed with return code ' + command_result.rc|string }}"
- name: Run a custom failing command
shell: exit 3
register: exit_command
ignore_errors: yes
- name: Display detailed error information
debug:
msg: |
Return code: {{ exit_command.rc }}
Error message: {{ exit_command.stderr if exit_command.stderr else 'No error message' }}
Este playbook:
- Ejecuta comandos que se espera que fallen
- Utiliza
ignore_errors: yes para continuar la ejecución del playbook incluso cuando los comandos fallan
- Muestra diferentes métodos para manejar y mostrar información de error
Ejecute el playbook:
ansible-playbook -i inventory.ini error_handling.yml
Debería ver una salida similar a esta:
PLAY [Error Handling with Shell Commands] *************************************
TASK [Run a potentially failing command] **************************************
fatal: [localhost]: FAILED! => {"changed": true, "cmd": "grep \"nonexistent_pattern\" /etc/passwd", "delta": "0:00:00.002916", "end": "2023-07-14 16:10:23.671519", "msg": "non-zero return code", "rc": 1, "start": "2023-07-14 16:10:23.668603", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
...ignoring
TASK [Display success or failure] *********************************************
ok: [localhost] => {
"msg": "Command failed with return code 1"
}
TASK [Run a custom failing command] *******************************************
fatal: [localhost]: FAILED! => {"changed": true, "cmd": "exit 3", "delta": "0:00:00.002447", "end": "2023-07-14 16:10:23.906121", "msg": "non-zero return code", "rc": 3, "start": "2023-07-14 16:10:23.903674", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
...ignoring
TASK [Display detailed error information] *************************************
ok: [localhost] => {
"msg": "Return code: 3\nError message: No error message\n"
}
PLAY RECAP ********************************************************************
localhost : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=2
Esto demuestra cómo capturar y responder a diferentes condiciones de error al ejecutar comandos de shell.