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 Jinja2 em condicionais. O Ansible oferece suporte a todos os testes e filtros padrão e também adiciona alguns exclusivos

https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html#playbooks-conditionals

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?

Figura 01. Sumário da seção (docs.ansible.com)

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 system
  ansible.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 | Filtro booleano para variáveis não booleanas, como variáveis de string com conteúdo como ‘sim’, ‘ativado’, ‘1’ ou ‘verdadeiro’.

https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html#conditionals-based-on-variables

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

CONTINUA (…)

Próximo post >>> Blocks

REFERÊNCIAS:

https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html#playbooks-conditionals

Deixe uma resposta

Este site utiliza o Akismet para reduzir spam. Saiba como seus dados em comentários são processados.