¿Cómo Capturar la Salida de un Script Ejecutado por Ansible?

AnsibleBeginner
Practicar Ahora

Introducción

Ansible es una herramienta de automatización de TI ampliamente utilizada que simplifica la gestión de infraestructuras complejas y la implementación de aplicaciones. En este tutorial, exploraremos cómo capturar la salida de scripts ejecutados a través de playbooks de Ansible. Esta capacidad es esencial para monitorear, depurar y analizar los resultados de sus tareas de automatización. Al final de este laboratorio, comprenderá varias técnicas para capturar y utilizar la salida de scripts en sus flujos de trabajo de Ansible.

Configuración del Entorno Ansible

Antes de que podamos comenzar a capturar la salida de scripts con Ansible, necesitamos configurar un entorno Ansible básico. Esto incluye la creación de la estructura de directorios y los archivos de configuración necesarios.

Comprensión de los Conceptos Básicos de Ansible

Ansible funciona conectándose a hosts de destino y enviando pequeños programas llamados módulos. Estos módulos se ejecutan en los hosts de destino y se eliminan cuando se completan. Ansible no requiere agentes (agent-less), lo que significa que no necesita instalar ningún software especial en los nodos administrados.

Comencemos creando un directorio de proyecto y los archivos de Ansible necesarios:

mkdir -p ~/project/ansible-output-demo/scripts
cd ~/project/ansible-output-demo

Ahora, creemos un archivo de inventario simple. En Ansible, el archivo de inventario define los hosts y grupos de hosts en los que operan los comandos, módulos y tareas en un playbook.

Cree un archivo de inventario usando el editor de código:

  1. Haga clic en el menú "Archivo" en la esquina superior izquierda del IDE
  2. Seleccione "Nuevo archivo"
  3. Guárdelo como inventory en el directorio ~/project/ansible-output-demo

Agregue el siguiente contenido al archivo inventory:

[local]
localhost ansible_connection=local

Este archivo de inventario especifica que ejecutaremos Ansible en la máquina local.

A continuación, creemos un script simple que generará alguna salida para que podamos capturarla. Este script:

  1. Imprimirá información del sistema
  2. Generará alguna salida estándar
  3. Generará alguna salida de error estándar

Cree un nuevo archivo en el directorio scripts llamado info.sh:

  1. Haga clic en el menú "Archivo"
  2. Seleccione "Nuevo archivo"
  3. Guárdelo como scripts/info.sh en el directorio ~/project/ansible-output-demo

Agregue el siguiente contenido al archivo info.sh:

#!/bin/bash

## Print system information
echo "=== System Information ==="
echo "Hostname: $(hostname)"
echo "Date: $(date)"
echo "Kernel: $(uname -r)"
echo "Memory:"
free -h

## Generate some standard output
echo "=== Standard Output ==="
echo "This is standard output"
echo "Hello from the script!"

## Generate some standard error
echo "=== Standard Error ===" >&2
echo "This is standard error" >&2
echo "An example error message" >&2

## Exit with a specific code
exit 0

Ahora, hagamos que el script sea ejecutable:

chmod +x ~/project/ansible-output-demo/scripts/info.sh

Ejecutemos el script directamente para ver qué salida produce:

~/project/ansible-output-demo/scripts/info.sh

Debería ver una salida que contenga información del sistema, mensajes de salida estándar y mensajes de error estándar.

Ahora tenemos nuestro entorno básico configurado. En el siguiente paso, crearemos un playbook de Ansible para ejecutar este script y capturar su salida.

Captura Básica de Salida con Ansible

Ahora que hemos configurado nuestro entorno, creemos un playbook de Ansible simple que ejecute nuestro script y capture su salida.

Creación de un Playbook Básico

En Ansible, los playbooks son archivos YAML que definen un conjunto de tareas a ejecutar en hosts remotos. Creemos un playbook que ejecute nuestro script info.sh y capture su salida utilizando la palabra clave register.

Cree un nuevo archivo llamado capture_output.yml en el directorio ~/project/ansible-output-demo:

  1. Haga clic en el menú "Archivo"
  2. Seleccione "Nuevo archivo"
  3. Guárdelo como capture_output.yml en el directorio ~/project/ansible-output-demo

Agregue el siguiente contenido al archivo capture_output.yml:

---
- name: Capture Script Output
  hosts: local
  gather_facts: no

  tasks:
    - name: Execute the info.sh script
      command: "{{ playbook_dir }}/scripts/info.sh"
      register: script_output

    - name: Display the script output
      debug:
        var: script_output.stdout

Examinemos este playbook:

  1. El playbook se dirige al grupo local definido en nuestro inventario.
  2. La primera tarea ejecuta nuestro script info.sh utilizando el módulo command.
  3. La palabra clave register almacena la salida del comando en una variable llamada script_output.
  4. La segunda tarea utiliza el módulo debug para mostrar la salida estándar (stdout) del script.

Ejecución del Playbook

Ahora ejecutemos el playbook para ver cómo captura y muestra la salida del script:

cd ~/project/ansible-output-demo
ansible-playbook -i inventory capture_output.yml

Debería ver una salida similar a la siguiente:

PLAY [Capture Script Output] *******************************************

TASK [Execute the info.sh script] **************************************
changed: [localhost]

TASK [Display the script output] ***************************************
ok: [localhost] => {
    "script_output.stdout": "=== System Information ===\nHostname: ubuntu\nDate: Tue Oct 17 12:34:56 UTC 2023\nKernel: 5.15.0-1031-aws\nMemory:\n              total        used        free      shared  buff/cache   available\nMem:          7.7Gi       1.2Gi       5.2Gi        12Mi       1.3Gi       6.3Gi\nSwap:            0B          0B          0B\n=== Standard Output ===\nThis is standard output\nHello from the script!"
}

PLAY RECAP ************************************************************
localhost                  : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Observe que solo se muestra la salida estándar. La salida de error estándar (stderr) no se muestra porque solo pedimos mostrar script_output.stdout.

Mejora de la Legibilidad de la Salida

La salida es un poco difícil de leer como una sola cadena. Modifiquemos nuestro playbook para mostrar la salida en un formato más legible utilizando el atributo stdout_lines, que presenta la salida como una lista de líneas.

Edite el archivo capture_output.yml y modifique la segunda tarea de la siguiente manera:

- name: Display the script output
  debug:
    var: script_output.stdout_lines

Ejecute el playbook de nuevo:

ansible-playbook -i inventory capture_output.yml

Ahora la salida debería ser más legible, con cada línea mostrada por separado:

TASK [Display the script output] ***************************************
ok: [localhost] => {
    "script_output.stdout_lines": [
        "=== System Information ===",
        "Hostname: ubuntu",
        "Date: Tue Oct 17 12:34:56 UTC 2023",
        "Kernel: 5.15.0-1031-aws",
        "Memory:",
        "              total        used        free      shared  buff/cache   available",
        "Mem:          7.7Gi       1.2Gi       5.2Gi        12Mi       1.3Gi       6.3Gi",
        "Swap:            0B          0B          0B",
        "=== Standard Output ===",
        "This is standard output",
        "Hello from the script!"
    ]
}

Este formato hace que la salida sea mucho más fácil de leer y trabajar. En el siguiente paso, exploraremos cómo capturar y mostrar diferentes tipos de salida.

Captura de Diferentes Tipos de Salida

En el paso anterior, capturamos y mostramos la salida estándar de nuestro script. Sin embargo, al ejecutar scripts, hay varios tipos de salida que podríamos querer capturar:

  1. Salida Estándar (stdout): La salida normal del script
  2. Error Estándar (stderr): Mensajes de error y advertencias
  3. Código de Retorno (rc): El estado de salida del script (0 normalmente significa éxito, los valores distintos de cero indican errores)

Creemos un nuevo playbook que capture y muestre los tres tipos de salida.

Cree un nuevo archivo llamado capture_all_output.yml en el directorio ~/project/ansible-output-demo:

  1. Haga clic en el menú "Archivo"
  2. Seleccione "Nuevo archivo"
  3. Guárdelo como capture_all_output.yml en el directorio ~/project/ansible-output-demo

Agregue el siguiente contenido al archivo capture_all_output.yml:

---
- name: Capture All Types of Script Output
  hosts: local
  gather_facts: no

  tasks:
    - name: Execute the info.sh script
      command: "{{ playbook_dir }}/scripts/info.sh"
      register: script_output

    - name: Display standard output
      debug:
        msg: "Standard Output (stdout):"

    - name: Display stdout content
      debug:
        var: script_output.stdout_lines

    - name: Display standard error
      debug:
        msg: "Standard Error (stderr):"

    - name: Display stderr content
      debug:
        var: script_output.stderr_lines

    - name: Display return code
      debug:
        msg: "Return Code: {{ script_output.rc }}"

Este playbook ejecuta nuestro script y luego muestra:

  1. La salida estándar usando script_output.stdout_lines
  2. El error estándar usando script_output.stderr_lines
  3. El código de retorno usando script_output.rc

Ejecución del Playbook Mejorado

Ejecutemos nuestro nuevo playbook:

cd ~/project/ansible-output-demo
ansible-playbook -i inventory capture_all_output.yml

Debería ver una visualización completa de los tres tipos de salida:

PLAY [Capture All Types of Script Output] *****************************

TASK [Execute the info.sh script] *************************************
changed: [localhost]

TASK [Display standard output] ****************************************
ok: [localhost] => {
    "msg": "Standard Output (stdout):"
}

TASK [Display stdout content] *****************************************
ok: [localhost] => {
    "script_output.stdout_lines": [
        "=== System Information ===",
        "Hostname: ubuntu",
        "Date: Tue Oct 17 12:40:22 UTC 2023",
        "Kernel: 5.15.0-1031-aws",
        "Memory:",
        "              total        used        free      shared  buff/cache   available",
        "Mem:          7.7Gi       1.2Gi       5.2Gi        12Mi       1.3Gi       6.3Gi",
        "Swap:            0B          0B          0B",
        "=== Standard Output ===",
        "This is standard output",
        "Hello from the script!"
    ]
}

TASK [Display standard error] *****************************************
ok: [localhost] => {
    "msg": "Standard Error (stderr):"
}

TASK [Display stderr content] *****************************************
ok: [localhost] => {
    "script_output.stderr_lines": [
        "=== Standard Error ===",
        "This is standard error",
        "An example error message"
    ]
}

TASK [Display return code] ********************************************
ok: [localhost] => {
    "msg": "Return Code: 0"
}

PLAY RECAP **********************************************************
localhost                  : ok=6    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Ahora podemos ver todos los tipos de salida de nuestro script:

  • La salida estándar muestra información del sistema y nuestros mensajes regulares
  • El error estándar muestra nuestros mensajes de error
  • El código de retorno es 0, lo que indica una ejecución exitosa

Creación de un Script con Errores

Creemos un script que producirá un error y devolverá un código de salida distinto de cero para ver cómo Ansible lo maneja.

Cree un nuevo archivo llamado error.sh en el directorio scripts:

  1. Haga clic en el menú "Archivo"
  2. Seleccione "Nuevo archivo"
  3. Guárdelo como scripts/error.sh en el directorio ~/project/ansible-output-demo

Agregue el siguiente contenido al archivo error.sh:

#!/bin/bash

## Print some standard output
echo "Starting error demonstration script"
echo "This will appear in stdout"

## Print some standard error
echo "This will appear in stderr" >&2
echo "Error: Something went wrong!" >&2

## Exit with a non-zero code to indicate error
exit 1

Haga que el script sea ejecutable:

chmod +x ~/project/ansible-output-demo/scripts/error.sh

Ahora creemos un playbook para ejecutar este script y manejar el error. Cree un nuevo archivo llamado handle_errors.yml:

  1. Haga clic en el menú "Archivo"
  2. Seleccione "Nuevo archivo"
  3. Guárdelo como handle_errors.yml en el directorio ~/project/ansible-output-demo

Agregue el siguiente contenido al archivo handle_errors.yml:

---
- name: Handle Script Errors
  hosts: local
  gather_facts: no

  tasks:
    - name: Execute the error script
      command: "{{ playbook_dir }}/scripts/error.sh"
      register: script_output
      ignore_errors: yes

    - name: Display standard output
      debug:
        var: script_output.stdout_lines

    - name: Display standard error
      debug:
        var: script_output.stderr_lines

    - name: Display return code
      debug:
        msg: "Return Code: {{ script_output.rc }}"

    - name: Check if script failed
      debug:
        msg: "The script failed with return code {{ script_output.rc }}"
      when: script_output.rc != 0

Observe la adición de ignore_errors: yes, que le dice a Ansible que continúe ejecutando el playbook incluso si el comando falla (devuelve un código de salida distinto de cero).

Ejecutemos este playbook:

ansible-playbook -i inventory handle_errors.yml

Debería ver una salida similar a la siguiente:

PLAY [Handle Script Errors] *******************************************

TASK [Execute the error script] ***************************************
changed: [localhost]

TASK [Display standard output] ****************************************
ok: [localhost] => {
    "script_output.stdout_lines": [
        "Starting error demonstration script",
        "This will appear in stdout"
    ]
}

TASK [Display standard error] *****************************************
ok: [localhost] => {
    "script_output.stderr_lines": [
        "This will appear in stderr",
        "Error: Something went wrong!"
    ]
}

TASK [Display return code] ********************************************
ok: [localhost] => {
    "msg": "Return Code: 1"
}

TASK [Check if script failed] *****************************************
ok: [localhost] => {
    "msg": "The script failed with return code 1"
}

PLAY RECAP **********************************************************
localhost                  : ok=5    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Este ejemplo demuestra cómo:

  1. Capturar la salida de un script que produce un error
  2. Continuar la ejecución del playbook a pesar del error
  3. Ejecutar condicionalmente tareas basadas en el código de retorno del script

En el siguiente paso, exploraremos casos de uso más avanzados y las mejores prácticas para trabajar con la salida de scripts en Ansible.

Procesamiento Avanzado de Salida y Casos de Uso Prácticos

Ahora que entendemos cómo capturar diferentes tipos de salida, exploremos algunas técnicas más avanzadas para procesar y utilizar la salida de scripts en Ansible.

Análisis de la Salida con Filtros

Ansible proporciona varios filtros que le permiten manipular y extraer información específica de la salida del script. En esta sección, veremos algunas técnicas comunes de filtrado.

Cree un nuevo archivo llamado parse_output.yml en el directorio ~/project/ansible-output-demo:

  1. Haga clic en el menú "Archivo"
  2. Seleccione "Nuevo archivo"
  3. Guárdelo como parse_output.yml en el directorio ~/project/ansible-output-demo

Primero, creemos un script que genere una salida estructurada que podamos analizar. Cree un nuevo archivo llamado system_stats.sh:

  1. Haga clic en el menú "Archivo"
  2. Seleccione "Nuevo archivo"
  3. Guárdelo como scripts/system_stats.sh en el directorio ~/project/ansible-output-demo

Agregue el siguiente contenido al archivo system_stats.sh:

#!/bin/bash

## Display CPU info
echo "CPU_MODEL: $(grep 'model name' /proc/cpuinfo | head -1 | cut -d ':' -f2 | xargs)"
echo "CPU_CORES: $(grep -c 'processor' /proc/cpuinfo)"

## Display memory info in GB
mem_total=$(free -g | grep Mem | awk '{print $2}')
echo "MEMORY_GB: $mem_total"

## Display disk usage
disk_usage=$(df -h / | tail -1 | awk '{print $5}' | tr -d '%')
echo "DISK_USAGE_PCT: $disk_usage"

## Display load average
load_avg=$(uptime | awk -F'load average: ' '{print $2}' | cut -d, -f1)
echo "LOAD_AVG: $load_avg"

exit 0

Haga que el script sea ejecutable:

chmod +x ~/project/ansible-output-demo/scripts/system_stats.sh

Ahora creemos un playbook que ejecute este script, capture su salida y la analice para extraer información específica:

Agregue el siguiente contenido al archivo parse_output.yml:

---
- name: Parse Script Output
  hosts: local
  gather_facts: no

  tasks:
    - name: Execute the system_stats.sh script
      command: "{{ playbook_dir }}/scripts/system_stats.sh"
      register: stats_output

    - name: Display raw output
      debug:
        var: stats_output.stdout_lines

    - name: Parse CPU model
      set_fact:
        cpu_model: "{{ stats_output.stdout | regex_search('CPU_MODEL: (.+)', '\\1') | first }}"

    - name: Parse CPU cores
      set_fact:
        cpu_cores: "{{ stats_output.stdout | regex_search('CPU_CORES: (\\d+)', '\\1') | first }}"

    - name: Parse memory
      set_fact:
        memory_gb: "{{ stats_output.stdout | regex_search('MEMORY_GB: (\\d+)', '\\1') | first }}"

    - name: Parse disk usage
      set_fact:
        disk_usage: "{{ stats_output.stdout | regex_search('DISK_USAGE_PCT: (\\d+)', '\\1') | first }}"

    - name: Parse load average
      set_fact:
        load_avg: "{{ stats_output.stdout | regex_search('LOAD_AVG: ([0-9.]+)', '\\1') | first }}"

    - name: Display parsed information
      debug:
        msg: |
          Parsed system information:
          - CPU Model: {{ cpu_model }}
          - CPU Cores: {{ cpu_cores }}
          - Memory (GB): {{ memory_gb }}
          - Disk Usage (%): {{ disk_usage }}
          - Load Average: {{ load_avg }}

Este playbook:

  1. Ejecuta nuestro script system_stats.sh
  2. Muestra la salida sin procesar
  3. Utiliza el filtro regex_search para extraer información específica de la salida
  4. Almacena la información extraída en variables
  5. Muestra la información analizada en un formato estructurado

Ejecutemos este playbook:

cd ~/project/ansible-output-demo
ansible-playbook -i inventory parse_output.yml

Debería ver una salida similar a la siguiente:

PLAY [Parse Script Output] ********************************************

TASK [Execute the system_stats.sh script] *****************************
changed: [localhost]

TASK [Display raw output] *********************************************
ok: [localhost] => {
    "stats_output.stdout_lines": [
        "CPU_MODEL: Intel(R) Xeon(R) CPU E5-2676 v3 @ 2.40GHz",
        "CPU_CORES: 2",
        "MEMORY_GB: 7",
        "DISK_USAGE_PCT: 58",
        "LOAD_AVG: 0.08"
    ]
}

TASK [Parse CPU model] ************************************************
ok: [localhost]

TASK [Parse CPU cores] ************************************************
ok: [localhost]

TASK [Parse memory] ***************************************************
ok: [localhost]

TASK [Parse disk usage] ***********************************************
ok: [localhost]

TASK [Parse load average] *********************************************
ok: [localhost]

TASK [Display parsed information] *************************************
ok: [localhost] => {
    "msg": "Parsed system information:\n- CPU Model: Intel(R) Xeon(R) CPU E5-2676 v3 @ 2.40GHz\n- CPU Cores: 2\n- Memory (GB): 7\n- Disk Usage (%): 58\n- Load Average: 0.08"
}

PLAY RECAP ***********************************************************
localhost                  : ok=8    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Tomar Decisiones Basadas en la Salida

Uno de los aspectos más poderosos de la captura de la salida del script es usarla para tomar decisiones en sus playbooks de Ansible. Creemos un playbook que demuestre la ejecución condicional basada en la salida del script.

Cree un nuevo archivo llamado conditional_actions.yml en el directorio ~/project/ansible-output-demo:

  1. Haga clic en el menú "Archivo"
  2. Seleccione "Nuevo archivo"
  3. Guárdelo como conditional_actions.yml en el directorio ~/project/ansible-output-demo

Agregue el siguiente contenido:

---
- name: Conditional Actions Based on Script Output
  hosts: local
  gather_facts: no

  tasks:
    - name: Execute the system_stats.sh script
      command: "{{ playbook_dir }}/scripts/system_stats.sh"
      register: stats_output

    - name: Parse disk usage
      set_fact:
        disk_usage: "{{ stats_output.stdout | regex_search('DISK_USAGE_PCT: (\\d+)', '\\1') | first | int }}"

    - name: Parse load average
      set_fact:
        load_avg: "{{ stats_output.stdout | regex_search('LOAD_AVG: ([0-9.]+)', '\\1') | first | float }}"

    - name: Display system status
      debug:
        msg: "Current system status: Disk usage: {{ disk_usage }}%, Load average: {{ load_avg }}"

    - name: Warn about high disk usage
      debug:
        msg: "WARNING: Disk usage is high at {{ disk_usage }}%. Consider cleaning up disk space."
      when: disk_usage > 50

    - name: Warn about high load average
      debug:
        msg: "WARNING: Load average is high at {{ load_avg }}. Check for resource-intensive processes."
      when: load_avg > 1.0

    - name: Report healthy system
      debug:
        msg: "System is healthy. All metrics within normal ranges."
      when: disk_usage <= 50 and load_avg <= 1.0

Este playbook:

  1. Ejecuta el script system_stats.sh
  2. Analiza los valores de uso del disco y promedio de carga
  3. Muestra diferentes mensajes basados en los valores:
    • Una advertencia si el uso del disco es superior al 50%
    • Una advertencia si el promedio de carga es superior a 1.0
    • Un mensaje de "sistema saludable" si todas las métricas están dentro de los rangos normales

Ejecutemos este playbook:

ansible-playbook -i inventory conditional_actions.yml

La salida dependerá del estado actual de su sistema, pero debería incluir mensajes condicionales basados en el uso de su disco y el promedio de carga.

Estos ejemplos demuestran cómo puede:

  1. Analizar y extraer información específica de la salida del script
  2. Usar esa información para tomar decisiones en sus playbooks de Ansible
  3. Tomar diferentes acciones basadas en la salida del script

Estas técnicas son esenciales para crear flujos de trabajo de automatización dinámicos y receptivos que pueden adaptarse a diferentes condiciones y escenarios.

Caso de Uso del Mundo Real - Verificación del Estado del Sistema

En este paso final, crearemos un ejemplo completo del mundo real que reúne todo lo que hemos aprendido sobre la captura y el procesamiento de la salida de scripts con Ansible. Construiremos una herramienta de verificación del estado del sistema que:

  1. Recopila varias métricas del sistema
  2. Analiza las métricas para identificar posibles problemas
  3. Genera un informe de estado
  4. Toma medidas correctivas cuando sea necesario

Creación del Script de Verificación del Estado

Primero, creemos un script completo de verificación del estado que recopile varias métricas del sistema.

Cree un nuevo archivo llamado health_check.sh en el directorio scripts:

  1. Haga clic en el menú "Archivo"
  2. Seleccione "Nuevo archivo"
  3. Guárdelo como scripts/health_check.sh en el directorio ~/project/ansible-output-demo

Agregue el siguiente contenido al archivo health_check.sh:

#!/bin/bash

## System Health Check Script

echo "HEALTH_CHECK_START: $(date)"

## CPU load
cpu_load=$(uptime | awk -F'load average: ' '{print $2}' | cut -d, -f1)
echo "CPU_LOAD: $cpu_load"
if (($(echo "$cpu_load > 1.0" | bc -l))); then
  echo "CPU_STATUS: WARNING"
else
  echo "CPU_STATUS: OK"
fi

## Memory usage
mem_total=$(free | grep Mem | awk '{print $2}')
mem_used=$(free | grep Mem | awk '{print $3}')
mem_pct=$(echo "scale=2; $mem_used / $mem_total * 100" | bc)
echo "MEM_USAGE_PCT: $mem_pct"
if (($(echo "$mem_pct > 80" | bc -l))); then
  echo "MEM_STATUS: WARNING"
else
  echo "MEM_STATUS: OK"
fi

## Disk usage
disk_usage=$(df -h / | tail -1 | awk '{print $5}' | tr -d '%')
echo "DISK_USAGE_PCT: $disk_usage"
if [ "$disk_usage" -gt 80 ]; then
  echo "DISK_STATUS: WARNING"
else
  echo "DISK_STATUS: OK"
fi

## Check for zombie processes
zombie_count=$(ps aux | grep -c Z)
echo "ZOMBIE_PROCESSES: $zombie_count"
if [ "$zombie_count" -gt 0 ]; then
  echo "ZOMBIE_STATUS: WARNING"
else
  echo "ZOMBIE_STATUS: OK"
fi

## Check system uptime
uptime_days=$(uptime | awk '{print $3}')
echo "UPTIME_DAYS: $uptime_days"

## Check last 5 log entries for errors
echo "RECENT_ERRORS: $(grep -i error /var/log/syslog 2> /dev/null | tail -5 | wc -l)"

echo "HEALTH_CHECK_END: $(date)"

Haga que el script sea ejecutable:

chmod +x ~/project/ansible-output-demo/scripts/health_check.sh

Creación del Playbook de Verificación del Estado

Ahora, creemos un playbook completo que ejecute el script de verificación del estado, analice los resultados y tome las acciones apropiadas en función de los hallazgos.

Cree un nuevo archivo llamado system_health_check.yml en el directorio ~/project/ansible-output-demo:

  1. Haga clic en el menú "Archivo"
  2. Seleccione "Nuevo archivo"
  3. Guárdelo como system_health_check.yml en el directorio ~/project/ansible-output-demo

Agregue el siguiente contenido al archivo system_health_check.yml:

---
- name: System Health Check
  hosts: local
  gather_facts: no

  tasks:
    - name: Execute health check script
      command: "{{ playbook_dir }}/scripts/health_check.sh"
      register: health_check

    - name: Display raw health check output
      debug:
        var: health_check.stdout_lines

    ## Parse metrics from the health check output
    - name: Parse CPU load
      set_fact:
        cpu_load: "{{ health_check.stdout | regex_search('CPU_LOAD: ([0-9.]+)', '\\1') | first | float }}"
        cpu_status: "{{ health_check.stdout | regex_search('CPU_STATUS: (\\w+)', '\\1') | first }}"

    - name: Parse memory usage
      set_fact:
        mem_usage: "{{ health_check.stdout | regex_search('MEM_USAGE_PCT: ([0-9.]+)', '\\1') | first | float }}"
        mem_status: "{{ health_check.stdout | regex_search('MEM_STATUS: (\\w+)', '\\1') | first }}"

    - name: Parse disk usage
      set_fact:
        disk_usage: "{{ health_check.stdout | regex_search('DISK_USAGE_PCT: (\\d+)', '\\1') | first | int }}"
        disk_status: "{{ health_check.stdout | regex_search('DISK_STATUS: (\\w+)', '\\1') | first }}"

    - name: Parse zombie processes
      set_fact:
        zombie_count: "{{ health_check.stdout | regex_search('ZOMBIE_PROCESSES: (\\d+)', '\\1') | first | int }}"
        zombie_status: "{{ health_check.stdout | regex_search('ZOMBIE_STATUS: (\\w+)', '\\1') | first }}"

    ## Generate a health status summary
    - name: Generate health status summary
      set_fact:
        health_status:
          cpu:
            load: "{{ cpu_load }}"
            status: "{{ cpu_status }}"
          memory:
            usage_percent: "{{ mem_usage }}"
            status: "{{ mem_status }}"
          disk:
            usage_percent: "{{ disk_usage }}"
            status: "{{ disk_status }}"
          processes:
            zombie_count: "{{ zombie_count }}"
            status: "{{ zombie_status }}"

    ## Display health summary
    - name: Display health summary
      debug:
        var: health_status

    ## Check overall system status
    - name: Determine overall system status
      set_fact:
        overall_status: "{{ 'WARNING' if (cpu_status == 'WARNING' or mem_status == 'WARNING' or disk_status == 'WARNING' or zombie_status == 'WARNING') else 'OK' }}"

    - name: Display overall system status
      debug:
        msg: "Overall System Status: {{ overall_status }}"

    ## Take remedial actions if necessary
    - name: Recommend actions for CPU issues
      debug:
        msg: "Action recommended: Check for resource-intensive processes using 'top' or 'htop'"
      when: cpu_status == "WARNING"

    - name: Recommend actions for memory issues
      debug:
        msg: "Action recommended: Free up memory by restarting services or clearing cache"
      when: mem_status == "WARNING"

    - name: Recommend actions for disk issues
      debug:
        msg: "Action recommended: Clean up disk space using 'du -sh /* | sort -hr' to identify large directories"
      when: disk_status == "WARNING"

    - name: Recommend actions for zombie processes
      debug:
        msg: "Action recommended: Identify and restart parent processes of zombies"
      when: zombie_status == "WARNING"

    ## Generate health report file
    - name: Create health report directory
      file:
        path: "{{ playbook_dir }}/reports"
        state: directory

    - name: Get current timestamp
      command: date "+%Y%m%d_%H%M%S"
      register: timestamp

    - name: Create health report file
      copy:
        content: |
          System Health Report - {{ timestamp.stdout }}
          ----------------------------------------------

          CPU:
            Load Average: {{ cpu_load }}
            Status: {{ cpu_status }}

          Memory:
            Usage: {{ mem_usage }}%
            Status: {{ mem_status }}

          Disk:
            Usage: {{ disk_usage }}%
            Status: {{ disk_status }}

          Processes:
            Zombie Count: {{ zombie_count }}
            Status: {{ zombie_status }}

          Overall Status: {{ overall_status }}

          Recommendations:
          {% if cpu_status == "WARNING" %}
          - CPU: Check for resource-intensive processes using 'top' or 'htop'
          {% endif %}
          {% if mem_status == "WARNING" %}
          - Memory: Free up memory by restarting services or clearing cache
          {% endif %}
          {% if disk_status == "WARNING" %}
          - Disk: Clean up disk space using 'du -sh /* | sort -hr' to identify large directories
          {% endif %}
          {% if zombie_status == "WARNING" %}
          - Processes: Identify and restart parent processes of zombies
          {% endif %}
          {% if overall_status == "OK" %}
          - System is healthy. No actions required.
          {% endif %}
        dest: "{{ playbook_dir }}/reports/health_report_{{ timestamp.stdout }}.txt"

    - name: Display report location
      debug:
        msg: "Health report saved to {{ playbook_dir }}/reports/health_report_{{ timestamp.stdout }}.txt"

Este playbook completo:

  1. Ejecuta nuestro script de verificación del estado
  2. Analiza las diversas métricas de la salida del script
  3. Crea un resumen estructurado del estado del sistema
  4. Determina el estado general del sistema en función de los estados de los componentes individuales
  5. Proporciona recomendaciones específicas para cualquier problema detectado
  6. Genera un archivo de informe de estado detallado con marca de tiempo

Ejecución de la Verificación del Estado

Ejecutemos nuestro playbook de verificación del estado del sistema:

cd ~/project/ansible-output-demo
ansible-playbook -i inventory system_health_check.yml

Debería ver una salida detallada que muestra el estado del sistema, junto con cualquier recomendación necesaria para mejorar. La salida variará según el estado actual de su sistema.

Después de ejecutar el playbook, verifique el directorio de informes para ver el informe de estado generado:

ls -l ~/project/ansible-output-demo/reports/

Debería ver un archivo llamado health_report_[timestamp].txt. Vea el contenido de este archivo:

cat ~/project/ansible-output-demo/reports/health_report_*.txt

Resumen de lo que Aprendimos

A lo largo de este tutorial, hemos aprendido:

  1. Cómo capturar diferentes tipos de salida (stdout, stderr, códigos de retorno) de scripts ejecutados por Ansible
  2. Cómo analizar y extraer información específica de la salida del script utilizando filtros de Ansible
  3. Cómo usar la salida del script para tomar decisiones y realizar acciones condicionales
  4. Cómo implementar una solución completa del mundo real que aprovecha la salida del script para la supervisión del estado del sistema

Estas técnicas son herramientas poderosas en su conjunto de herramientas de automatización de Ansible, lo que le permite crear flujos de trabajo de automatización sofisticados, dinámicos y receptivos.

Resumen

En este laboratorio, exploramos cómo capturar y utilizar eficazmente la salida de scripts ejecutados a través de Ansible. Comenzamos con la captura básica de salida utilizando la palabra clave register y avanzamos a técnicas más avanzadas, como el análisis de la salida con filtros y la toma de decisiones basadas en los resultados del script.

Las conclusiones clave de este tutorial incluyen:

  1. La capacidad de capturar diferentes tipos de salida (stdout, stderr, códigos de retorno) de scripts ejecutados por Ansible
  2. Técnicas para analizar y extraer información específica de la salida del script
  3. Métodos para ejecutar tareas condicionalmente en función de la salida del script
  4. Un ejemplo completo del mundo real que demuestra cómo construir una solución de monitoreo del estado del sistema con Ansible

Al dominar estas técnicas, puede crear flujos de trabajo de automatización más sofisticados, dinámicos y receptivos que pueden adaptarse a diferentes condiciones y escenarios. Esta capacidad es esencial para la gestión eficaz de la infraestructura, la implementación de aplicaciones y la administración del sistema utilizando Ansible.

A medida que continúe su viaje con Ansible, recuerde que la captura de la salida del script es solo una de las muchas funciones poderosas que ofrece Ansible. Explorar otras capacidades de Ansible, como roles, plantillas y vault, mejorará aún más su conjunto de herramientas de automatización.