ANSIBLE SERIES: h.t.wrt* … tasks, plays e books: conditionals
CONT. ☝
👈 ANTERIOR: WHERE TASKS RUN ?
Condicionais, em bom português, são aquelas famosas palavrinhas que aprendemos (lógica da programação) com o intuito de:
- parar momentaneamente o fluxo do programa;
- desviar a sequência ou conteúdo de variável para um bloco de código que faz checagem;
- chamar uma função ou sub-rotina;
- capturar exceções e tratá-las;
- exibir informações ou mensagens ao usuário;
- dentre outras tarefas.
Pois bem, alguns exemplos dessas palavras que normalmente usamos para tais propósitos: SE, SENÃO, ENTÃO, ENQUANTO, PARA, E, OU, NÃO (!not) …
No casos dos playbooks, nossos objetivos vão desde: (a) executar diferentes tasks que dependem do valor de um fato (dado de um host remoto), variável ou resultado anterior (b) atribuir valor a uma variável baseando-se em outra variável precedente (c) definir e criar novos grupos de hosts em cima de alguns critérios de correspondência.
Uma pequena ressalva da documentação oficial:
Ansible usa testes e filtros
https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html#playbooks-conditionalsJinja2em condicionais. O Ansible oferece suporte a todos os testes e filtros padrão e também adiciona alguns exclusivos
E uma pequena nota de rodapé:
Existem muitas opções para controlar o fluxo de execução no Ansible. Você pode encontrar mais exemplos de condicionais com suporte em https://jinja.palletsprojects.com/en/master/templates/#comparisons
https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html#playbooks-conditionals
Devido ao sumário de tamanho “razoável” que esta seção apresenta na wiki oficial, tentarei ao máximo fazer breves explanações dos códigos e talvez pule algumas delas, seja porque são muito raras de utilizar ou porque fogem muito dos nossos objetivos, ok?

04-a. Condicionais básicas com WHEN
A unidade mais básica para uma condicional, chamada por alguns de “declaração mais simples”, é essencialmente aplicada a uma única tarefa por vez. Na prática, isso quer dizer que, quando se cria uma tarefa, seguida de uma declaração when, um teste será executado. Essa cláusula when na verdade é uma expressão Jinja2 bruta e sem chaves duplas. Quando se roda uma task ou playbook o que acontece é que o Ansible valida esse teste para todos os hosts remotos. Se qualquer um deles “passar na prova”, o valor retornado é true, e então a task é executada. Para ilustrar, um exemplo:
tasks:
- name: Configure SELinux to start mysql on any port
ansible.posix.seboolean:
name: mysql_connect_any
state: true
persistent: yes
when: ansible_selinux.status == "enabled"
# all variables can be used directly in conditionals without double curly braces
! ! ! BASEADAS EM ANSIBLE_FACTS ! ! !
Às vezes, ao invés de executar tarefas, simplesmente queremos o oposto. Em outras palavras, desejamos pulá-las e passar adiante. Isso pode ser feito através dos fatos, ou melhor, por meio dos atributos (dados) de um node específico. IP, SO, filesystem, status, são apenas alguns para citar.
Com as condicionais baseadas em fatos, é possível:
- instalar pacotes somente para determinadas versões ou famílias de um sistema operacional
- pular configurações de firewall para hosts internos à rede
- fazer uma limpeza em sistemas de arquivos muito cheios
Veja quais fatos estão disponíveis em cada host, acrescentando uma simples tarefa do tipo debug:
- name: Show facts available on the systemansible.builtin.debug:var:ansible_facts
Exemplo 1 x 1: uma condicional para um fato
tasks:
- name: Shut down Debian flavored systems
ansible.builtin.command: /sbin/shutdown -t now
when: ansible_facts['os_family'] == "Debian"
Exemplo N x N: múltiplas condicionais para múltiplos fatos
tasks:
- name: Shut down CentOS 6 and Debian 7 systems
ansible.builtin.command: /sbin/shutdown -t now
when: (ansible_facts['distribution'] == "CentOS" and ansible_facts['distribution_major_version'] == "6") or
(ansible_facts['distribution'] == "Debian" and ansible_facts['distribution_major_version'] == "7")
Outra forma, um pouco mais abreviada:
tasks:
- name: Shut down CentOS 6 systems
ansible.builtin.command: /sbin/shutdown -t now
when:
- ansible_facts['distribution'] == "CentOS"
- ansible_facts['distribution_major_version'] == "6"
https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html#commonly-used-facts
! ! ! BASEADAS EM VARIÁVEIS ! ! !
Você também pode criar condicionais com base em variáveis definidas nos playbooks ou inventários. Como as condicionais requerem entrada booleana (um teste deve ser avaliado como True para acionar a condição), você deve aplicar o
https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html#conditionals-based-on-variables|Filtro booleanopara variáveis não booleanas, como variáveis de string com conteúdo como‘sim’,‘ativado’,‘1’ou‘verdadeiro’.
Defina suas variáveis exatamente assim:
vars:
epic: true
monumental: "yes"
Agora execute o código a seguir:
tasks:
- name: Run the command if "epic" or "monumental" is true
ansible.builtin.shell: echo "This certainly is epic!"
when: epic or monumental | bool
- name: Run the command if "epic" is false
ansible.builtin.shell: echo "This certainly isn't epic!"
when: not epic
Verá que o Ansible roda uma delas e pula a outra!
! ! ! BASEADAS EM LOOPS ! ! !
Processa a condição separadamente para cada item presente no laço. Isso ocorre para que você possa executar a tarefa em alguns elementos e ignorá-la em outros. Por exemplo:
tasks:
- name: Run with items greater than 5
ansible.builtin.command: echo {{ item }}
loop: [ 0, 2, 4, 6, 8, 10 ]
when: item > 5
Sobre uma lista:
- name: Skip the whole task when a loop variable is undefined
ansible.builtin.command: echo {{ item }}
loop: "{{ mylist|default([]) }}"
when: item > 5
Sobre um dicionário:
- name: The same as above using a dict
ansible.builtin.command: echo {{ item.key }}
loop: "{{ query('dict', mydict|default({})) }}"
when: item.value > 5