Introdução
Programas de manutenção existentes precisam de uma integração cuidadosa com a automação declarativa. Você distinguirá command, shell e script, passará um caminho com espaço de forma segura, classificará resultados somente leitura e protegerá a execução com base em uma saída real de script. Um pipeline e comprovantes delegados ao controlador tornarão observáveis o local de execução e a propagação de falhas. Você também provocará e recuperará uma falha real de entrada ausente.
Executar um comando direto com argumentos seguros
Nesta etapa, você inspecionará uma entrada gerenciada com command, preservará um caminho contendo um espaço e classificará corretamente a operação somente leitura.
Prefira módulos declarativos como copy e file para gerenciar estado. Command, shell e script são úteis ao integrar um executável ou programa de manutenção existente. command executa um executável gerenciado sem um shell, portanto pipes e redirecionamentos não são interpretados. Sua forma argv mantém cada argumento separado, incluindo um caminho com espaços.
Cada destino preparado tem /home/automation/maintenance input.txt contendo uma linha de dados aprovados e um pré-requisito maintenance-ready. O controlador fornece um script existente em scripts/ para uso posterior. Preserve essas entradas.
Entre no projeto do controlador:
cd /home/labex/project
Crie um playbook usando argv. O caminho com espaço é uma entrada única da lista YAML. register captura o resultado do executável, incluindo stdout e seu código de retorno numérico rc. Zero normalmente significa sucesso; um código de retorno diferente de zero normalmente faz a tarefa falhar.
cat > maintenance.yml <<'YAML'
- name: Inspect maintenance inputs safely
hosts: all
gather_facts: false
tasks:
- name: Read the managed input with a space-safe argument list
ansible.builtin.command:
argv:
- /usr/bin/cat
- /home/automation/maintenance input.txt
register: input_result
changed_when: false
- name: Retain the inspected input in a managed record
ansible.builtin.copy:
dest: /home/automation/command-result.txt
content: "{{ input_result.stdout }}\n"
mode: "0640"
YAML
O comando cat é somente leitura, portanto changed_when false classifica seu resultado como sem alterações. Essa configuração muda o relato, não o que um comando realmente faz; ela não deve ser usada para ocultar alterações de um programa que modifica o estado. A tarefa copy usa o stdout retornado e grava um registro gerenciado real com uma quebra de linha final explícita.
Verifique e execute o playbook:
ansible-playbook maintenance.yml --syntax-check
ansible-playbook maintenance.yml
As duas tarefas de leitura devem informar ok, enquanto a primeira cópia do registro altera cada destino. Inspecione os registros reais:
ansible all -m ansible.builtin.command -a 'cat /home/automation/command-result.txt'
Cada um deve conter Approved maintenance data. Nesta versão do core, command pode expandir argumentos de variáveis de ambiente por meio de Python mesmo sem invocar um shell. Use expand_argument_vars false quando precisar de argumentos literais com prefixo de dólar; isso é desnecessário para este caminho fixo.
Transferir um script do controlador e proteger a execução pela saída real
Nesta etapa, você invocará o script de manutenção fornecido no controlador nos dois destinos e evitará execuções repetidas desnecessárias.
Inspecione o programa fornecido antes de executá-lo:
cat scripts/host-maintenance.sh
Ele verifica a entrada maintenance-ready do destino antes de criar qualquer saída. A ausência de prontidão imprime um erro e termina com 42. Caso contrário, grava um relatório protegido contendo o nome real do host de destino e seu argumento de rótulo. Sua pequena implementação em shell é uma entrada de integração existente; use módulos declarativos para a configuração comum de arquivos.
O módulo script transfere uma origem do controlador para o destino e a executa lá. Isso difere de command, cujo executável já deve existir no nó gerenciado. O rótulo entre aspas abaixo continua sendo um argumento único com espaço. O caminho creates é verificado no destino gerenciado: quando esse relatório já existe, o script é pulado.
Acrescente a tarefa de script:
cat >> maintenance.yml <<'YAML'
- name: Run the supplied controller script once per target report
ansible.builtin.script:
cmd: /home/labex/project/scripts/host-maintenance.sh 'Maintenance checked'
creates: /home/automation/maintenance-run/report.txt
register: maintenance_result
failed_when: maintenance_result.rc is defined and maintenance_result.rc != 0
YAML
O rc do resultado registrado controla failed_when. A proteção is defined considera um resultado que não inclua um código de retorno de execução. Não use ignore_errors nem failed_when false para transformar uma falha real do script em sucesso aparente.
Execute o playbook estendido:
ansible-playbook maintenance.yml
Os dois destinos devem criar relatórios. Leia as saídas reais:
ansible all -m ansible.builtin.command -a 'cat /home/automation/maintenance-run/report.txt'
Cada um deve conter seu próprio nome de host e label=Maintenance checked. Repita o mesmo playbook:
ansible-playbook maintenance.yml
O script deve ser pulado porque seu relatório no destino existe, e os dois resumos devem informar changed=0 sem destinos failed/unreachable. Creates é uma proteção baseada em existência, não um mecanismo de reconciliação de conteúdo: ele não corrige um relatório existente corrompido nem o regenera automaticamente quando as entradas do script mudam.
Propagar falhas e delegar comprovantes ao controlador
Nesta etapa, você usará shell apenas para um pipeline real, armazenará comprovantes distintos no controlador e exercitará uma falha visível de script sem suprimi-la.
Um pipe conecta a saída de um comando à entrada de outro e, portanto, precisa de shell. O pipefail do Bash faz com que um comando malsucedido em um pipeline produza uma falha, em vez de permitir que um comando wc final bem-sucedido a oculte. O pipeline abaixo apenas conta linhas da entrada; changed_when false é apropriado porque ele lê sem alterar o estado do destino. failed_when também rejeita uma contagem de linhas inesperada.
Crie um diretório de comprovantes no controlador. Cada cópia delegada usará o nome original do inventário em um arquivo separado, impedindo que os hosts sobrescrevam um comprovante compartilhado:
mkdir -p receipts
Acrescente as tarefas de pipeline e comprovante. delegate_to localhost executa apenas a tarefa do comprovante no controlador; inventory_hostname ainda identifica o destino original. become false mantém a criação de arquivos no controlador sob a conta comum labex.
cat >> maintenance.yml <<'YAML'
- name: Count managed input lines with explicit pipeline failure propagation
ansible.builtin.shell: |
set -o pipefail
cat '/home/automation/maintenance input.txt' | wc -l
args:
executable: /bin/bash
register: line_result
changed_when: false
failed_when: line_result.rc != 0 or (line_result.stdout | trim) != '1'
- name: Store a per-target receipt on the controller
ansible.builtin.copy:
dest: "/home/labex/project/receipts/{{ inventory_hostname }}.txt"
content: |
host={{ inventory_hostname }}
input_lines={{ line_result.stdout | trim }}
mode: "0640"
delegate_to: localhost
become: false
YAML
Execute o fluxo completo de manutenção:
ansible-playbook maintenance.yml
Inspecione os dois comprovantes no controlador. Cada um deve identificar seu próprio host original e input_lines=1:
cat receipts/web1.txt receipts/web2.txt
Agora exercite o ramo de falha real do script em web1. Remova seu relatório protegido por creates e a entrada de prontidão com o módulo file; essas são alterações temporárias intencionais dentro do nó de treinamento:
ansible web1 -m ansible.builtin.file -a 'path=/home/automation/maintenance-run/report.txt state=absent'
ansible web1 -m ansible.builtin.file -a 'path=/home/automation/maintenance-ready state=absent'
A próxima execução deve fazer a tarefa de script falhar em web1 com rc 42 e a mensagem de entrada ausente. || permite que o fluxo no Terminal continue após essa saída esperada diferente de zero do playbook; ele não muda a classificação da falha no Ansible:
ansible-playbook maintenance.yml || printf 'Expected missing-readiness failure\n'
Inspecione o caminho do relatório; web1 não deve ter um relatório de sucesso fabricado após a falha do script:
ansible web1 -m ansible.builtin.stat -a 'path=/home/automation/maintenance-run/report.txt'
Restaure a entrada de prontidão a partir de uma origem exata no controlador e execute novamente o fluxo completo:
printf 'Ready\n' > ready.txt
ansible web1 -m ansible.builtin.copy -a 'src=/home/labex/project/ready.txt dest=/home/automation/maintenance-ready mode=0644'
ansible-playbook maintenance.yml
Web1 deve regenerar seu relatório com sucesso. A repetição final deve ter zero alterações, destinos inacessíveis e falhas:
ansible-playbook maintenance.yml
As inspeções somente leitura ainda executam, o script protegido pula relatórios existentes e cada comprovante delegado permanece no controlador. Isso preserva os sinais reais de erro enquanto mantém estável uma execução repetida bem-sucedida.
Resumo
Você usou argv para execução gerenciada direta, script para transferência de programas do controlador ao destino e shell apenas para um pipeline real com propagação explícita de falhas. Relatar fielmente as inspeções somente leitura como sem alterações, usar uma proteção creates real e manter os códigos de saída sem suprimir erros tornou os resultados significativos. Comprovantes delegados por host demonstraram a execução no controlador, e o exercício de entrada ausente terminou em um fluxo restaurado e estável.


