Como Exibir a Saída de Comandos Shell em Playbooks Ansible

AnsibleIntermediate
Pratique Agora

Introdução

Ansible é uma poderosa ferramenta de automação de código aberto, amplamente utilizada por administradores de sistemas e profissionais de DevOps. Uma de suas principais capacidades é a execução de comandos shell em hosts remotos e o processamento de suas saídas. Neste tutorial prático, você aprenderá como capturar, exibir e processar efetivamente a saída de comandos shell em playbooks Ansible. Essa habilidade é essencial para criar fluxos de trabalho de automação robustos que podem se adaptar a diferentes condições do sistema e fornecer feedback útil.

Este é um Lab Guiado, que fornece instruções passo a passo para ajudá-lo a aprender e praticar. Siga as instruções cuidadosamente para completar cada etapa e ganhar experiência prática. Dados históricos mostram que este é um laboratório de nível intermediário com uma taxa de conclusão de 53%. Recebeu uma taxa de avaliações positivas de 100% dos estudantes.

Configurando seu Primeiro Playbook Ansible com Comandos Shell

Nesta etapa, configuraremos um playbook Ansible básico que executa comandos shell e captura sua saída. Isso fornecerá a base para técnicas mais avançadas nas etapas posteriores.

Instalando o Ansible

Primeiro, vamos instalar o Ansible em nosso sistema:

sudo apt update
sudo apt install -y ansible

Agora, verifique se o Ansible está instalado corretamente:

ansible --version

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

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 15 2022, 12:22:08) [GCC 11.2.0]
  jinja version = 3.0.3
  libyaml = True

Criando um Arquivo de Inventário

O Ansible usa um arquivo de inventário para saber quais hosts gerenciar. Para este laboratório, criaremos um inventário simples que inclui apenas a máquina local:

  1. Abra seu WebIDE e crie um novo arquivo chamado inventory.ini no diretório /home/labex/project.
  2. Adicione o seguinte conteúdo ao arquivo:
[local]
localhost ansible_connection=local

Este inventário define um grupo chamado local que contém apenas o localhost e diz ao Ansible para se conectar diretamente sem SSH.

Criando seu Primeiro Playbook

Agora, vamos criar um playbook simples que executa comandos shell:

  1. Crie um novo arquivo chamado first_playbook.yml no diretório /home/labex/project.
  2. Adicione o seguinte conteúdo YAML ao arquivo:
---
- name: Shell Command Example
  hosts: local
  gather_facts: no

  tasks:
    - name: Run a simple shell command
      shell: echo "Hello from Ansible shell command"
      register: hello_output

    - name: Display the output
      debug:
        msg: "{{ hello_output.stdout }}"

Este playbook faz o seguinte:

  • Destina-se ao grupo local que definimos em nosso inventário
  • Ignora a coleta de fatos (informações do sistema) para manter as coisas simples
  • Executa um comando shell que ecoa uma mensagem de saudação
  • Armazena a saída em uma variável usando a palavra-chave register
  • Exibe a saída usando o módulo debug

Executando seu Playbook

Agora, vamos executar o playbook:

ansible-playbook -i inventory.ini first_playbook.yml

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

PLAY [Shell Command Example] **************************************************

TASK [Run a simple shell command] *********************************************
changed: [localhost]

TASK [Display the output] *****************************************************
ok: [localhost] => {
    "msg": "Hello from Ansible shell command"
}

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

A saída mostra que nosso playbook foi executado com sucesso, executando o comando shell e exibindo sua saída.

Conceitos-Chave a Entender

Deste exercício, observe estes conceitos importantes:

  1. O módulo shell permite que você execute comandos shell
  2. A diretiva register captura a saída de uma tarefa em uma variável
  3. O módulo debug ajuda a exibir valores de variáveis
  4. A saída do comando shell contém tanto stdout (saída padrão) quanto stderr (saída de erro)

Na próxima etapa, exploraremos como processar e formatar a saída do comando shell de forma mais eficaz.

Trabalhando com Saída Estruturada de Comandos Shell

Agora que você entende os conceitos básicos de execução de comandos shell no Ansible, vamos explorar como trabalhar com a saída estruturada de comandos e exibi-la em diferentes formatos.

Processando Informações do Sistema

Vamos criar um playbook mais prático que coleta informações do sistema e as apresenta de forma estruturada:

  1. Crie um novo arquivo chamado system_info.yml no diretório /home/labex/project.
  2. Adicione o seguinte conteúdo:
---
- name: Gather and Display System Information
  hosts: local
  gather_facts: no

  tasks:
    - name: Gather system information
      shell: |
        echo "OS Information: $(cat /etc/os-release | grep PRETTY_NAME | cut -d= -f2)"
        echo "Kernel Version: $(uname -r)"
        echo "CPU Information: $(grep "model name" /proc/cpuinfo | head -1 | cut -d: -f2 | xargs)"
        echo "Memory Information: $(free -h | grep Mem | awk '{print $2}')"
      register: system_info

    - name: Display raw system information
      debug:
        msg: "{{ system_info.stdout }}"

    - name: Display information as a list
      debug:
        msg: "{{ system_info.stdout_lines }}"

Este playbook:

  • Executa um script shell de várias linhas que coleta vários detalhes do sistema
  • Armazena a saída na variável system_info
  • Exibe a saída primeiro como uma string bruta e depois como uma lista de linhas

Execute o playbook:

ansible-playbook -i inventory.ini system_info.yml

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

PLAY [Gather and Display System Information] **********************************

TASK [Gather system information] **********************************************
changed: [localhost]

TASK [Display raw system information] *****************************************
ok: [localhost] => {
    "msg": "OS Information: \"Ubuntu 22.04.1 LTS\"\nKernel Version: 5.15.0-1023-azure\nCPU Information: Intel(R) Xeon(R) Platinum 8171M CPU @ 2.60GHz\nMemory Information: 4.0Gi"
}

TASK [Display information as a list] *****************************************
ok: [localhost] => {
    "msg": [
        "OS Information: \"Ubuntu 22.04.1 LTS\"",
        "Kernel Version: 5.15.0-1023-azure",
        "CPU Information: Intel(R) Xeon(R) Platinum 8171M CPU @ 2.60GHz",
        "Memory Information: 4.0Gi"
    ]
}

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

Observe como a segunda tarefa de exibição mostra a saída como uma lista em vez de uma string com quebras de linha. Este formato de lista facilita o trabalho com saída de várias linhas.

Trabalhando com Resultados de Comandos e Códigos de Retorno

Comandos shell no Linux retornam códigos de saída para indicar sucesso (0) ou falha (diferente de zero). O Ansible captura isso no atributo rc (código de retorno) da variável registrada.

Vamos criar um playbook que demonstra como trabalhar com códigos de retorno:

  1. Crie um novo arquivo chamado command_results.yml no diretório /home/labex/project.
  2. Adicione o seguinte conteúdo:
---
- name: Working with Command Results
  hosts: local
  gather_facts: no

  tasks:
    - name: Check if a file exists
      shell: test -f /etc/hosts
      register: file_check
      ignore_errors: yes

    - name: Show command result details
      debug:
        msg: |
          Return code: {{ file_check.rc }}
          Succeeded: {{ file_check.rc == 0 }}
          Failed: {{ file_check.rc != 0 }}

    - name: Check if a non-existent file exists
      shell: test -f /file/does/not/exist
      register: missing_file
      ignore_errors: yes

    - name: Show command result for missing file
      debug:
        msg: |
          Return code: {{ missing_file.rc }}
          Succeeded: {{ missing_file.rc == 0 }}
          Failed: {{ missing_file.rc != 0 }}

Este playbook:

  • Executa dois comandos de teste para verificar se os arquivos existem
  • Usa ignore_errors: yes para evitar que o playbook pare se um comando falhar
  • Exibe informações detalhadas sobre o resultado do comando, incluindo o código de retorno e o status de sucesso/falha

Execute o playbook:

ansible-playbook -i inventory.ini command_results.yml

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

PLAY [Working with Command Results] *******************************************

TASK [Check if a file exists] *************************************************
changed: [localhost]

TASK [Show command result details] ********************************************
ok: [localhost] => {
    "msg": "Return code: 0\nSucceeded: True\nFailed: False\n"
}

TASK [Check if a non-existent file exists] ************************************
fatal: [localhost]: FAILED! => {"changed": true, "cmd": "test -f /file/does/not/exist", "delta": "0:00:00.003183", "end": "2023-07-14 15:24:33.931406", "msg": "non-zero return code", "rc": 1, "start": "2023-07-14 15:24:33.928223", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
...ignoring

TASK [Show command result for missing file] ***********************************
ok: [localhost] => {
    "msg": "Return code: 1\nSucceeded: False\nFailed: True\n"
}

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

Observe como o código de retorno é 0 para o arquivo existente e 1 para o arquivo não existente. Isso demonstra como você pode usar códigos de retorno para tomar decisões em seus playbooks.

Entendendo a Estrutura da Variável Registrada

A variável registrada a partir de um comando shell contém vários atributos úteis:

  • stdout: A saída padrão como uma única string
  • stdout_lines: A saída padrão dividida em uma lista de linhas
  • stderr: A saída de erro padrão como uma única string
  • stderr_lines: A saída de erro padrão dividida em uma lista de linhas
  • rc: O código de retorno (0 para sucesso, diferente de zero para falha)
  • cmd: O comando que foi executado
  • start e end: Carimbos de data/hora para quando o comando começou e terminou
  • delta: A duração da execução do comando

Entender essa estrutura é crucial para trabalhar efetivamente com a saída do comando shell no Ansible.

Execução Condicional Baseada na Saída do Shell

Uma das capacidades mais poderosas do Ansible é a capacidade de tomar decisões com base na saída de comandos shell. Nesta etapa, aprenderemos como usar condições e filtros para processar a saída de comandos shell e tornar os playbooks mais dinâmicos.

Usando Condições com Saída do Shell

Vamos criar um playbook que toma decisões com base na saída do comando shell:

  1. Crie um novo arquivo chamado conditional_playbook.yml no diretório /home/labex/project.
  2. Adicione o seguinte conteúdo:
---
- 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:

  • Executa um comando shell para verificar a porcentagem de uso do disco no sistema de arquivos raiz
  • Usa a condição when com base na saída do comando
  • Usa o filtro int para converter a saída da string em um inteiro para comparação

Execute o playbook:

ansible-playbook -i inventory.ini conditional_playbook.yml

A saída variará dependendo do seu uso real do disco, mas terá uma aparência semelhante a esta:

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 como o Ansible executou apenas uma das tarefas condicionais com base no valor real de uso do disco.

Manipulando Saída JSON de Comandos

Muitas ferramentas CLI modernas retornam dados em formato JSON. O Ansible possui recursos integrados para lidar com a saída JSON:

  1. Crie um novo arquivo chamado json_output.yml no diretório /home/labex/project.
  2. Adicione o seguinte conteúdo:
---
- 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:

  • Cria um arquivo JSON de amostra para demonstração
  • Lê o arquivo JSON com um comando shell
  • Usa o filtro from_json para analisar a string JSON em uma estrutura de dados
  • Percorre a estrutura de dados para exibir informações
  • Usa lógica condicional para filtrar apenas os serviços em execução

Execute o playbook:

ansible-playbook -i inventory.ini json_output.yml

Você deve ver uma saída semelhante 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 como o playbook analisa o JSON, extrai informações específicas e filtra os dados com base em condições.

Tratamento de Erros com Comandos Shell

Ao executar comandos shell, é importante lidar com possíveis erros de forma adequada:

  1. Crie um novo arquivo chamado error_handling.yml no diretório /home/labex/project.
  2. Adicione o seguinte conteúdo:
---
- 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:

  • Executa comandos que devem falhar
  • Usa ignore_errors: yes para continuar a execução do playbook mesmo quando os comandos falham
  • Mostra diferentes métodos para lidar e exibir informações de erro

Execute o playbook:

ansible-playbook -i inventory.ini error_handling.yml

Você deve ver uma saída semelhante 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

Isso demonstra como capturar e responder a diferentes condições de erro ao executar comandos shell.

Criando uma Ferramenta Prática de Processamento de Saída do Shell

Nesta etapa final, reuniremos tudo o que aprendemos para criar um playbook Ansible prático que coleta informações do sistema, as processa e gera um relatório. Isso representa um cenário do mundo real onde os recursos de processamento de comandos shell do Ansible podem ser extremamente úteis.

Construindo uma Ferramenta de Relatório de Informações do Sistema

Vamos criar uma ferramenta abrangente de coleta de informações do sistema:

  1. Crie um novo arquivo chamado system_report.yml no diretório /home/labex/project.
  2. Adicione o seguinte conteúdo:
---
- name: Comprehensive System Report
  hosts: local
  gather_facts: no

  vars:
    report_file: /tmp/system_report.txt

  tasks:
    - name: Collect basic system information
      shell: |
        echo "SYSTEM REPORT" > {{ report_file }}
        echo "=============" >> {{ report_file }}
        echo "" >> {{ report_file }}

        echo "HOSTNAME: $(hostname)" >> {{ report_file }}
        echo "TIMESTAMP: $(date)" >> {{ report_file }}
        echo "" >> {{ report_file }}

        echo "SYSTEM INFORMATION" >> {{ report_file }}
        echo "------------------" >> {{ report_file }}
        echo "OS: $(cat /etc/os-release | grep PRETTY_NAME | cut -d= -f2)" >> {{ report_file }}
        echo "KERNEL: $(uname -r)" >> {{ report_file }}
        echo "UPTIME: $(uptime -p)" >> {{ report_file }}
        echo "" >> {{ report_file }}

        echo "RESOURCE UTILIZATION" >> {{ report_file }}
        echo "-------------------" >> {{ report_file }}
        echo "CPU LOAD: $(uptime | awk -F'load average:' '{print $2}')" >> {{ report_file }}
        echo "MEMORY USAGE:" >> {{ report_file }}
        free -h >> {{ report_file }}
        echo "" >> {{ report_file }}
        echo "DISK USAGE:" >> {{ report_file }}
        df -h >> {{ report_file }}
        echo "" >> {{ report_file }}

        echo "NETWORK INFORMATION" >> {{ report_file }}
        echo "-------------------" >> {{ report_file }}
        echo "IP ADDRESSES:" >> {{ report_file }}
        ip addr | grep "inet " | awk '{print $2}' >> {{ report_file }}
        echo "" >> {{ report_file }}

        echo "PROCESS INFORMATION" >> {{ report_file }}
        echo "-------------------" >> {{ report_file }}
        echo "TOP 5 CPU CONSUMING PROCESSES:" >> {{ report_file }}
        ps aux --sort=-%cpu | head -6 >> {{ report_file }}
        echo "" >> {{ report_file }}
        echo "TOP 5 MEMORY CONSUMING PROCESSES:" >> {{ report_file }}
        ps aux --sort=-%mem | head -6 >> {{ report_file }}
      register: report_generation

    - name: Check if report was generated successfully
      stat:
        path: "{{ report_file }}"
      register: report_stat

    - name: Display report generation status
      debug:
        msg: "Report generated successfully at {{ report_file }}"
      when: report_stat.stat.exists

    - name: Display report content
      shell: cat {{ report_file }}
      register: report_content
      when: report_stat.stat.exists

    - name: Show report content
      debug:
        msg: "{{ report_content.stdout_lines }}"
      when: report_stat.stat.exists

    - name: Analyze disk usage
      shell: df -h / | grep -v Filesystem | awk '{print $5}' | sed 's/%//'
      register: disk_usage
      when: report_stat.stat.exists

    - name: Generate disk usage alert if needed
      debug:
        msg: "ALERT: Disk usage on / is {{ disk_usage.stdout }}% which exceeds the 80% threshold!"
      when:
        - report_stat.stat.exists
        - disk_usage.stdout|int > 80

    - name: Generate disk usage warning if needed
      debug:
        msg: "WARNING: Disk usage on / is {{ disk_usage.stdout }}% which exceeds the 60% threshold."
      when:
        - report_stat.stat.exists
        - disk_usage.stdout|int > 60
        - disk_usage.stdout|int <= 80

    - name: Confirm normal disk usage
      debug:
        msg: "Disk usage on / is normal at {{ disk_usage.stdout }}%."
      when:
        - report_stat.stat.exists
        - disk_usage.stdout|int <= 60

Este playbook:

  • Coleta informações abrangentes do sistema usando uma série de comandos shell
  • Escreve as informações em um arquivo de relatório
  • Verifica se o relatório foi criado com sucesso
  • Exibe o conteúdo do relatório
  • Analisa os dados de uso do disco
  • Gera alertas apropriados com base na análise

Execute o playbook:

ansible-playbook -i inventory.ini system_report.yml

Você verá uma saída abrangente mostrando a execução do playbook e o relatório completo do sistema. A saída é bastante longa, então aqui está apenas uma amostra do que você pode ver:

PLAY [Comprehensive System Report] ********************************************

TASK [Collect basic system information] ***************************************
changed: [localhost]

TASK [Check if report was generated successfully] *****************************
ok: [localhost]

TASK [Display report generation status] ***************************************
ok: [localhost] => {
    "msg": "Report generated successfully at /tmp/system_report.txt"
}

TASK [Display report content] *************************************************
changed: [localhost]

TASK [Show report content] ****************************************************
ok: [localhost] => {
    "msg": [
        "SYSTEM REPORT",
        "=============",
        "",
        "HOSTNAME: ubuntu-vm",
        "TIMESTAMP: Fri Jul 14 16:35:42 UTC 2023",
        "",
        "SYSTEM INFORMATION",
        "------------------",
        "OS: \"Ubuntu 22.04.1 LTS\"",
        "KERNEL: 5.15.0-1023-azure",
        "UPTIME: up 3 hours, 25 minutes",
        ...

Examinando o Relatório

Vamos examinar o relatório do sistema que geramos:

cat /tmp/system_report.txt

Isso exibirá o relatório completo que foi gerado pelo nosso playbook.

Criando um Script Shell Personalizado e Chamando-o do Ansible

Para operações mais complexas, às vezes é mais fácil criar um script shell dedicado e chamá-lo do Ansible:

  1. Crie um novo arquivo chamado disk_analyzer.sh no diretório /home/labex/project.
  2. Adicione o seguinte conteúdo:
#!/bin/bash

## disk_analyzer.sh - A simple script to analyze disk usage

echo "DISK USAGE ANALYSIS"
echo "------------------"

## Get overall disk usage
ROOT_USAGE=$(df -h / | grep -v Filesystem | awk '{print $5}' | sed 's/%//')
echo "Root filesystem usage: ${ROOT_USAGE}%"

## Categorize the usage
if [ $ROOT_USAGE -gt 80 ]; then
  echo "STATUS: CRITICAL - Immediate action required"
elif [ $ROOT_USAGE -gt 60 ]; then
  echo "STATUS: WARNING - Consider cleaning up disk space"
else
  echo "STATUS: OK - Disk usage is within normal parameters"
fi

echo ""

## Find largest directories
echo "Top 5 largest directories in /var:"
du -h /var --max-depth=1 2> /dev/null | sort -hr | head -5

echo ""

## Find largest files
echo "Top 5 largest files in /var/log:"
find /var/log -type f -exec du -h {} \; 2> /dev/null | sort -hr | head -5

exit 0
  1. Torne o script executável:
chmod +x /home/labex/project/disk_analyzer.sh
  1. Crie um novo playbook para chamar este script:
touch /home/labex/project/call_script.yml
  1. Adicione o seguinte conteúdo ao playbook:
---
- name: Call Custom Shell Script
  hosts: local
  gather_facts: no

  tasks:
    - name: Run disk analyzer script
      shell: /home/labex/project/disk_analyzer.sh
      register: script_output

    - name: Display script output
      debug:
        msg: "{{ script_output.stdout_lines }}"

    - name: Check for critical status
      debug:
        msg: "CRITICAL DISK USAGE DETECTED! Immediate action required."
      when: script_output.stdout is search("STATUS: CRITICAL")
  1. Execute o playbook:
ansible-playbook -i inventory.ini call_script.yml

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

PLAY [Call Custom Shell Script] ***********************************************

TASK [Run disk analyzer script] ***********************************************
changed: [localhost]

TASK [Display script output] **************************************************
ok: [localhost] => {
    "msg": [
        "DISK USAGE ANALYSIS",
        "------------------",
        "Root filesystem usage: 38%",
        "STATUS: OK - Disk usage is within normal parameters",
        "",
        "Top 5 largest directories in /var:",
        "60M\t/var/lib",
        "60M\t/var/cache",
        "12M\t/var/log",
        "4.0K\t/var/tmp",
        "4.0K\t/var/mail",
        "",
        "Top 5 largest files in /var/log:",
        "4.0M\t/var/log/journal/c75af53674ce472fb9654a1d5cf8cc37/system.journal",
        "2.3M\t/var/log/auth.log",
        "1.3M\t/var/log/syslog",
        "724K\t/var/log/kern.log",
        "428K\t/var/log/cloud-init.log"
    ]
}

TASK [Check for critical status] **********************************************
skipped: [localhost]

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

Essa abordagem combina o poder dos scripts shell com os recursos de automação do Ansible. O script shell lida com a lógica complexa para análise de disco, enquanto o Ansible gerencia a execução e o processamento posterior dos resultados.

Principais Conclusões

Por meio deste laboratório, você aprendeu várias técnicas importantes para trabalhar com a saída de comandos shell no Ansible:

  1. Como executar comandos shell e capturar sua saída
  2. Como processar e formatar a saída do comando para exibição
  3. Como usar a execução condicional com base nos resultados do comando
  4. Como lidar com a saída JSON e condições de erro
  5. Como criar ferramentas práticas que combinam comandos shell com os recursos de automação do Ansible

Essas habilidades serão inestimáveis ​​ao construir soluções de automação mais complexas com o Ansible.

Resumo

Neste laboratório, você aprendeu a trabalhar efetivamente com a saída de comandos shell em playbooks Ansible. Começando com o básico da execução de comandos shell e captura de sua saída, você progrediu para técnicas mais avançadas, como execução condicional, tratamento de erros e processamento de formatos de dados estruturados como JSON.

Você dominou várias habilidades-chave:

  • Executando comandos shell em playbooks Ansible usando o módulo shell
  • Capturando a saída do comando com a diretiva register
  • Exibindo a saída usando o módulo debug
  • Processando a saída com filtros e condicionais Jinja2
  • Criando ferramentas de automação práticas que combinam Ansible com scripts shell

Essas técnicas permitem que você crie fluxos de trabalho de automação mais dinâmicos e responsivos que podem se adaptar a diferentes condições do sistema e fornecer feedback útil sobre as operações que estão sendo executadas.

Ao continuar sua jornada no Ansible, lembre-se de que, embora os comandos shell forneçam grande flexibilidade, os módulos integrados do Ansible são frequentemente uma solução mais robusta e portátil para tarefas comuns. Use comandos shell quando precisar aproveitar scripts shell existentes ou executar operações complexas que não são facilmente tratadas pelos módulos Ansible.