Como exibir a saída de scripts em playbooks Ansible

AnsibleBeginner
Pratique Agora

Introdução

Ansible é uma ferramenta de automação poderosa que auxilia administradores de sistemas e desenvolvedores a gerenciar a infraestrutura de forma eficiente. Ao executar scripts ou comandos através de playbooks Ansible, é frequentemente crucial capturar e exibir sua saída para fins de monitoramento e solução de problemas.

Neste laboratório prático, você aprenderá como exibir efetivamente a saída de scripts em seus playbooks Ansible. Começaremos com os fundamentos da estrutura de um playbook Ansible, depois exploraremos várias técnicas para capturar e exibir saídas de comandos e, finalmente, abordaremos alguns métodos avançados para formatar e filtrar dados de saída.

Ao final deste laboratório, você terá experiência prática com diferentes abordagens para lidar com a saída de scripts no Ansible, permitindo que você crie fluxos de trabalho de automação mais informativos e fáceis de depurar.

Configurando Seu Primeiro Playbook Ansible

Antes de explorarmos como exibir a saída de scripts, precisamos configurar um ambiente Ansible básico e criar nosso primeiro playbook.

Instalando o Ansible

Vamos começar garantindo que o Ansible esteja instalado em nosso sistema:

sudo apt update
sudo apt install -y ansible

Este comando instalará o Ansible em seu sistema Ubuntu. Após a conclusão da instalação, verifique-a verificando a versão do Ansible:

ansible --version

Você deve ver uma saída semelhante à seguinte, que confirma que o Ansible está corretamente instalado:

ansible [core 2.12.x]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/labex/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3/dist-packages/ansible
  ansible collection location = /home/labex/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.10.x (default, Mar 14 2023, 14:50:41) [GCC 11.3.0]
  jinja version = 3.0.3
  libyaml = True

Entendendo o Inventário Ansible

O Ansible precisa saber a quais hosts se conectar. Para este laboratório, usaremos um arquivo de inventário simples que inclui apenas a máquina local.

Crie um diretório para nosso projeto Ansible:

mkdir -p ~/project/ansible-lab
cd ~/project/ansible-lab

Agora, crie um arquivo de inventário chamado inventory.ini:

echo "localhost ansible_connection=local" > inventory.ini

Este arquivo de inventário diz ao Ansible para executar comandos na máquina local sem usar SSH.

Criando Seu Primeiro Playbook

Agora, vamos criar um playbook Ansible básico. No WebIDE, crie um novo arquivo chamado first_playbook.yml no diretório ~/project/ansible-lab com o seguinte conteúdo:

---
- name: My First Ansible Playbook
  hosts: localhost
  gather_facts: yes

  tasks:
    - name: Display a simple message
      debug:
        msg: "Hello from Ansible!"

    - name: Display system information
      debug:
        msg: "You are running {{ ansible_distribution }} {{ ansible_distribution_version }}"

Este playbook simples tem duas tarefas:

  1. Exibir uma mensagem de saudação simples
  2. Exibir informações sobre o sistema operacional que você está executando

Vamos executar este playbook para ver como ele funciona:

cd ~/project/ansible-lab
ansible-playbook -i inventory.ini first_playbook.yml

Você deve ver uma saída semelhante a esta:

PLAY [My First Ansible Playbook] *********************************************************

TASK [Gathering Facts] *******************************************************************
ok: [localhost]

TASK [Display a simple message] **********************************************************
ok: [localhost] => {
    "msg": "Hello from Ansible!"
}

TASK [Display system information] ********************************************************
ok: [localhost] => {
    "msg": "You are running Ubuntu 22.04"
}

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

Esta saída mostra:

  • O playbook foi executado com sucesso
  • Todas as tarefas foram concluídas com o status "ok"
  • A saída de cada tarefa de depuração é exibida

Agora que temos um playbook básico funcionando, podemos explorar como executar scripts e exibir sua saída com mais detalhes.

Executando Scripts e Capturando Saída

Agora que temos um ambiente Ansible básico configurado, vamos explorar como executar scripts e capturar sua saída usando os módulos command e shell.

A Diferença Entre os Módulos Command e Shell

O Ansible fornece dois módulos principais para executar comandos:

  • command: Executa um comando em um nó remoto sem passar por um shell, o que significa que operadores de shell como |, >, <, e & não funcionam.
  • shell: Executa um comando através de um shell, permitindo operadores de shell e variáveis de ambiente.

Criando um Script Simples para Executar

Primeiro, vamos criar um script de shell simples que podemos executar com o Ansible. Crie um arquivo chamado system_info.sh em seu diretório ~/project/ansible-lab:

cd ~/project/ansible-lab

No WebIDE, crie o arquivo com o seguinte conteúdo:

#!/bin/bash

echo "=== System Information ==="
echo "Hostname: $(hostname)"
echo "Kernel Version: $(uname -r)"
echo "CPU Info: $(grep 'model name' /proc/cpuinfo | head -1 | cut -d':' -f2 | xargs)"
echo "Memory Info: $(free -h | grep Mem | awk '{print $2 " total, " $3 " used, " $4 " free"}')"
echo "Disk Usage: $(df -h / | grep / | awk '{print $5 " of " $2 " used"}')"

Torne o script executável:

chmod +x ~/project/ansible-lab/system_info.sh

Agora, vamos executar este script manualmente para ver qual saída ele produz:

./system_info.sh

Você deve ver uma saída semelhante a:

=== System Information ===
Hostname: labex-xxxxxxxx
Kernel Version: 5.15.0-xx-generic
CPU Info: Intel(R) Xeon(R) xxxxxx
Memory Info: 8.0G total, 1.2G used, 5.8G free
Disk Usage: 15% of 50G used

Executando o Script com Ansible

Agora, vamos criar um novo playbook que executará este script e capturará sua saída. Crie um arquivo chamado script_output.yml em seu diretório ~/project/ansible-lab:

---
- name: Run Script and Capture Output
  hosts: localhost
  gather_facts: no

  tasks:
    - name: Run system info script
      command: ./system_info.sh
      register: script_result

    - name: Display script output
      debug:
        msg: "{{ script_result.stdout }}"

Este playbook faz duas coisas:

  1. Executa nosso script system_info.sh usando o módulo command
  2. Armazena a saída em uma variável chamada script_result usando a palavra-chave register
  3. Exibe a saída capturada usando o módulo debug

Vamos executar este playbook:

cd ~/project/ansible-lab
ansible-playbook -i inventory.ini script_output.yml

Você deve ver uma saída semelhante a:

PLAY [Run Script and Capture Output] ***************************************************

TASK [Run system info script] ***********************************************************
changed: [localhost]

TASK [Display script output] ************************************************************
ok: [localhost] => {
    "msg": "=== System Information ===\nHostname: labex-xxxxxxxx\nKernel Version: 5.15.0-xx-generic\nCPU Info: Intel(R) Xeon(R) xxxxxx\nMemory Info: 8.0G total, 1.2G used, 5.8G free\nDisk Usage: 15% of 50G used"
}

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

Observe como a saída aparece como uma única string com caracteres de nova linha (\n). Vamos melhorar a exibição na próxima seção.

Entendendo a Variável Register

A palavra-chave register cria uma variável que contém vários atributos, não apenas a saída do comando. Vamos criar um novo playbook para explorar esses atributos.

Crie um arquivo chamado register_details.yml em seu diretório ~/project/ansible-lab:

---
- name: Explore Register Variable
  hosts: localhost
  gather_facts: no

  tasks:
    - name: Run system info script
      command: ./system_info.sh
      register: script_result

    - name: Display all register properties
      debug:
        var: script_result

    - name: Display just stdout
      debug:
        var: script_result.stdout

    - name: Display stdout as a list of lines
      debug:
        var: script_result.stdout_lines

Execute este playbook:

ansible-playbook -i inventory.ini register_details.yml

Você verá uma saída mais detalhada que mostra todas as propriedades da variável script_result, incluindo:

  • stdout: A saída padrão como uma única string
  • stderr: O erro padrão (se houver)
  • rc: O código de retorno (0 significa sucesso)
  • stdout_lines: A saída padrão dividida em uma lista de linhas

A última tarefa é particularmente útil, pois formata a saída como uma lista de linhas, tornando-a muito mais legível.

Técnicas Avançadas de Tratamento de Saída

Agora que entendemos os conceitos básicos de captura da saída de scripts, vamos explorar algumas técnicas mais avançadas para tratar e exibir a saída em playbooks Ansible.

Tratando Erros de Script

Ao executar scripts, é importante tratar adequadamente as condições de erro. O Ansible marca uma tarefa como falha se o comando retornar um código de saída diferente de zero. Vamos criar um playbook que demonstra o tratamento de erros.

Crie um arquivo chamado error_handling.yml em seu diretório ~/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

Neste playbook:

  1. Tentamos listar um diretório que não existe
  2. Usamos ignore_errors: yes para evitar que o playbook pare se o comando falhar
  3. Verificamos o código de retorno (cmd_result.rc) para determinar se o comando foi bem-sucedido ou falhou
  4. Exibimos mensagens apropriadas com base no resultado

Vamos executar este playbook:

cd ~/project/ansible-lab
ansible-playbook -i inventory.ini error_handling.yml

Você deve ver uma saída semelhante 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, apesar da falha do comando, o playbook continua a ser executado e exibe a mensagem de erro.

Formatando Saída Multilinha

Vamos criar um script mais complexo que gera saída multilinha e, em seguida, formatá-la de forma agradável em nosso playbook.

Crie um arquivo chamado package_info.sh em seu diretório ~/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

Torne-o executável:

chmod +x ~/project/ansible-lab/package_info.sh

Agora, crie um playbook para executar este script e formatar a saída de forma agradável. Crie um arquivo chamado 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:

  1. Executa nosso script package_info.sh
  2. Exibe a saída bruta
  3. Usa um template Jinja2 para formatar a saída com um título e rodapé

Vamos executá-lo:

ansible-playbook -i inventory.ini formatted_output.yml

Você deve ver uma saída formatada de forma agradável:

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

Exibindo Saída Condicionalmente

Às vezes, você só quer exibir a saída sob certas condições, como ao executar no modo verbose. Vamos ver como fazer isso.

Crie um arquivo chamado conditional_output.yml em seu diretório ~/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

Neste playbook:

  1. Capturamos informações de uso do disco
  2. Sempre exibimos um resumo (primeiras duas linhas)
  3. Exibimos os detalhes completos apenas quando executamos no modo verbose (com a flag -v)

Vamos executá-lo no modo normal primeiro:

ansible-playbook -i inventory.ini conditional_output.yml

Agora, vamos executá-lo no modo verbose:

ansible-playbook -i inventory.ini conditional_output.yml -v

Você notará que, no modo verbose, você obtém as informações completas de uso do disco, enquanto no modo normal, você só vê o resumo.

Essa técnica é útil para ocultar saídas potencialmente sensíveis ou avassaladoras por padrão, ao mesmo tempo em que as torna disponíveis quando necessário para depuração.

Resumo

Neste laboratório, você aprendeu várias técnicas para capturar e exibir a saída de scripts em playbooks Ansible:

  1. Você configurou um ambiente Ansible básico e criou seu primeiro playbook
  2. Você aprendeu como executar scripts usando os módulos command e shell
  3. Você capturou a saída do script usando a diretiva register
  4. Você exibiu a saída usando o módulo debug em diferentes formatos
  5. Você tratou condições de erro e implementou a exibição de saída condicional
  6. Você aplicou técnicas de formatação para tornar a saída mais legível

Essas habilidades permitem que você crie playbooks Ansible mais informativos que fornecem feedback claro durante a execução. Essa visibilidade é crucial tanto para monitorar processos automatizados quanto para solucionar problemas quando surgem.

Ao alavancar essas técnicas de tratamento de saída, você pode construir fluxos de trabalho de automação mais robustos que não apenas executam tarefas, mas também comunicam claramente o que está acontecendo em cada etapa. Isso torna sua automação mais transparente e fácil de manter, especialmente ao trabalhar em ambientes de equipe ou com infraestruturas complexas.