Controlar o Estado da Tarefa com changed_when e failed_when
Nesta etapa, você obterá um controle mais refinado sobre como o Ansible interpreta o resultado de suas tarefas. Você aprenderá sobre duas diretivas poderosas: changed_when e failed_when.
changed_when: Por padrão, módulos como ansible.builtin.command ou ansible.builtin.shell quase sempre relatam um estado "changed" (alterado), mesmo que o comando que executaram não tenha modificado o sistema. changed_when permite definir uma condição personalizada que determina se uma tarefa deve ser relatada como "changed". Isso é crucial para escrever playbooks idempotentes e para acionar handlers com precisão.
failed_when: Às vezes, um comando pode sair com um código de status diferente de zero (que o Ansible considera uma falha), mesmo quando o resultado é aceitável. failed_when permite substituir as condições de falha padrão, permitindo que seu playbook continue com base em critérios mais inteligentes, como a saída do comando ou um código de saída específico.
Vamos começar configurando um novo diretório de projeto.
cd ~/project
mkdir control-state-lab
cd control-state-lab
Crie o arquivo inventory padrão para localhost.
nano inventory
Adicione o seguinte conteúdo:
localhost ansible_connection=local
Salve e saia do editor (Ctrl+X, Y, Enter).
Usando changed_when
Primeiro, vamos ver como uma tarefa de comando se comporta por padrão. Criaremos um playbook que executa o comando date. Este comando simplesmente imprime a data e não altera o sistema, mas o módulo command o relatará como uma alteração.
Crie um novo playbook chamado playbook.yml.
nano playbook.yml
Insira o seguinte conteúdo:
---
- name: Control Task State
hosts: localhost
tasks:
- name: Check local time (default behavior)
ansible.builtin.command: date
Salve e saia. Agora, execute o playbook.
ansible-playbook -i inventory playbook.yml
Observe na saída que a tarefa é relatada como changed=1, mesmo que nada no sistema tenha sido modificado.
...
TASK [Check local time (default behavior)] *************************************
changed: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 ...
Agora, vamos usar changed_when para dizer ao Ansible que este comando nunca altera o sistema. Modifique playbook.yml.
nano playbook.yml
Adicione changed_when: false à tarefa.
---
- name: Control Task State
hosts: localhost
tasks:
- name: Check local time (with changed_when)
ansible.builtin.command: date
changed_when: false
Salve e saia. Execute o playbook novamente.
ansible-playbook -i inventory playbook.yml
Desta vez, a tarefa relata ok e o resumo final mostra changed=0. Você substituiu com sucesso o comportamento padrão.
...
TASK [Check local time (with changed_when)] ************************************
ok: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 ...
Usando failed_when
Em seguida, vamos explorar failed_when. Criaremos uma tarefa que verifica a existência de um arquivo que não está lá. O comando "falhará" por padrão.
Primeiro, crie um arquivo dummy para pesquisar.
echo "System is running" > status.txt
Agora, modifique playbook.yml para procurar a palavra "ERROR" neste arquivo. O comando grep sairá com um código de status 1 porque a palavra não é encontrada, o que o Ansible interpreta como uma falha.
nano playbook.yml
Substitua o conteúdo pelo seguinte:
---
- name: Control Task State
hosts: localhost
tasks:
- name: Check for ERROR in status file (will fail)
ansible.builtin.command: grep ERROR status.txt
Salve e saia. Execute o playbook.
ansible-playbook -i inventory playbook.yml
Como esperado, a execução do playbook para com uma mensagem FAILED!.
...
TASK [Check for ERROR in status file (will fail)] ******************************
fatal: [localhost]: FAILED! => {"changed": true, "cmd": ["grep", "ERROR", "status.txt"], "delta": "...", "end": "...", "msg": "non-zero return code", "rc": 1, ...}
...
Isso não é o que queremos. A ausência de "ERROR" é uma condição de sucesso para nós. Podemos usar failed_when para redefinir o que constitui uma falha. Diremos ao Ansible para falhar apenas se o código de retorno do comando for maior que 1. Um código de retorno de 1 (padrão não encontrado) agora será considerado um sucesso. Também precisamos registrar o resultado da tarefa para inspecionar seu código de retorno (rc).
Modifique playbook.yml mais uma vez.
nano playbook.yml
Atualize o playbook com register e failed_when.
---
- name: Control Task State
hosts: localhost
tasks:
- name: Check for ERROR in status file (with failed_when)
ansible.builtin.command: grep ERROR status.txt
register: grep_result
failed_when: grep_result.rc > 1
changed_when: false
Também adicionamos changed_when: false porque grep é uma operação somente leitura e não altera o sistema.
Salve e saia. Execute o playbook final.
ansible-playbook -i inventory playbook.yml
Sucesso! A tarefa agora relata ok porque seu código de retorno foi 1, o que não atende à nossa nova condição de falha (rc > 1). O playbook é concluído com sucesso.
...
TASK [Check for ERROR in status file (with failed_when)] ***********************
ok: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 ...
Agora você aprendeu como usar changed_when e failed_when para definir precisamente os estados de sucesso, alterado e falha de suas tarefas, levando a uma automação mais robusta e inteligente.