Condicionais e Laços de Repetição no Ansible

AnsibleBeginner
Pratique Agora

Introdução

Neste laboratório, você explorará duas funcionalidades poderosas do Ansible: condicionais e laços de repetição (loops). Esses conceitos permitem criar playbooks mais dinâmicos e eficientes, controlando a execução de tarefas com base em condições específicas e repetindo tarefas para vários itens. Ao final deste laboratório, você entenderá como usar condicionais para tomar decisões em seus playbooks e como implementar loops para executar tarefas repetitivas de forma eficiente. Esse conhecimento ajudará você a criar playbooks do Ansible mais flexíveis e potentes para gerenciar sua infraestrutura.

Configurando o Ambiente

Nesta etapa, você configurará o ambiente de trabalho para os exercícios de condicionais e loops do Ansible. Esta preparação fornece os arquivos e diretórios utilizados em todas as tarefas subsequentes.

Primeiro, vamos navegar até o diretório do projeto. No terminal, digite:

cd ~/project

Este comando altera seu diretório atual para ~/project, que é o nosso espaço de trabalho designado para este laboratório.

Agora, criaremos um arquivo de inventário. No Ansible, um arquivo de inventário define os hosts e grupos de hosts sobre os quais os comandos, módulos e tarefas em um playbook operam. Para este laboratório, usaremos um inventário simples que inclui apenas o localhost.

Crie um novo arquivo chamado inventory.ini:

nano inventory.ini

Este comando abre o editor de texto nano. Se você não está familiarizado com o nano, não se preocupe — é um editor de texto simples e fácil de usar. O cursor será posicionado no arquivo, pronto para você digitar.

Agora, vamos adicionar o seguinte conteúdo ao arquivo:

[local]
localhost ansible_connection=local

Vamos analisar o que isso significa:

  • [local] define um grupo chamado "local"
  • localhost é o nome do host
  • ansible_connection=local instrui o Ansible a executar os comandos localmente em vez de via SSH

Para salvar o arquivo e sair do nano, pressione Ctrl+X, pressione Y para salvar o buffer modificado e, em seguida, pressione Enter para confirmar o nome do arquivo.

Em seguida, vamos criar um diretório para os nossos playbooks:

mkdir playbooks
cd playbooks

O comando mkdir cria um novo diretório chamado "playbooks", e então usamos cd para entrar nesse novo diretório.

Por que estamos fazendo isso? Organizar seus arquivos do Ansible em diretórios é uma boa prática. Isso mantém seu projeto organizado, especialmente à medida que ele cresce e se torna maior e mais complexo.

Seguindo esses passos, você configurou um ambiente básico do Ansible. Você tem um arquivo de inventário que diz ao Ansible quais hosts utilizar e um diretório dedicado para os seus playbooks. Essa estrutura facilitará o gerenciamento dos seus projetos Ansible à medida que você aprende e experimenta recursos mais complexos.

Introdução às Condicionais

Nesta etapa, você usará condicionais do Ansible para controlar a execução de tarefas com base em condições específicas. Isso é útil quando você precisa realizar ações diferentes dependendo do estado do seu sistema ou do valor de certas variáveis.

Vamos criar um playbook simples que demonstra o uso de condicionais:

nano conditional_example.yml

Este comando abre o editor de texto nano para criar um novo arquivo chamado conditional_example.yml. Agora, adicione o seguinte conteúdo:

---
- name: Conditional Example
  hosts: localhost
  gather_facts: yes
  tasks:
    - name: Check OS family
      debug:
        msg: "This is a Debian-based system"
      when: ansible_os_family == "Debian"

    - name: Check OS family (alternative)
      debug:
        msg: "This is not a Debian-based system"
      when: ansible_os_family != "Debian"

Vamos analisar este código:

  • --- no topo do arquivo indica o início de um documento YAML.
  • name: Conditional Example atribui um nome ao nosso playbook.
  • hosts: localhost especifica que este playbook será executado na máquina local.
  • gather_facts: yes instrui o Ansible a coletar informações sobre o sistema antes de executar as tarefas. Isso é importante porque usaremos esses fatos em nossas condições.
  • tasks: inicia a lista de tarefas a serem executadas.

Cada tarefa usa o módulo debug para exibir uma mensagem, mas a execução é controlada pela cláusula when:

  • A primeira tarefa será executada apenas se o sistema for baseado em Debian (ansible_os_family == "Debian").
  • A segunda tarefa será executada apenas se o sistema não for baseado em Debian (ansible_os_family != "Debian").

ansible_os_family é um fato coletado pelo Ansible sobre o sistema de destino. Ele é usado aqui para demonstrar como as condicionais funcionam.

Salve e saia do editor nano (Ctrl+X, depois Y, depois Enter).

Agora, vamos executar o playbook:

ansible-playbook -i ../inventory.ini conditional_example.yml

Este comando instrui o Ansible a executar nosso playbook. A opção -i ../inventory.ini especifica o arquivo de inventário que criamos anteriormente.

Você deverá ver uma saída indicando se o seu sistema é baseado em Debian ou não. Apenas uma das mensagens de depuração será exibida, dependendo da família do sistema operacional do seu sistema.

Este exemplo demonstra como as condicionais podem ser usadas para tornar seus playbooks adaptáveis a diferentes ambientes. Em cenários do mundo real, você pode usar condicionais para instalar diferentes pacotes em diferentes tipos de SO, ou para ignorar certas tarefas se um arquivo já existir.

Lembre-se de que o poder das condicionais reside na capacidade de tornar seus playbooks flexíveis e capazes de lidar com vários cenários sem a necessidade de playbooks separados para cada caso.

Trabalhando com Múltiplas Condições

Nesta etapa, você combinará várias condições usando operadores lógicos antes de executar uma tarefa. Esse padrão dá suporte a um comportamento condicional mais avançado em playbooks do mundo real.

Crie um novo arquivo chamado multiple_conditions.yml:

nano multiple_conditions.yml

Agora, adicione o seguinte conteúdo ao arquivo:

---
- name: Multiple Conditions Example
  hosts: localhost
  gather_facts: yes
  vars:
    check_memory: true
  tasks:
    - name: Check OS and Memory
      debug:
        msg: "This is a Debian-based system with more than 1GB of memory"
      when:
        - ansible_os_family == "Debian"
        - ansible_memtotal_mb > 1024
        - check_memory | bool

    - name: Print System Information
      debug:
        msg: "OS: {{ ansible_distribution }}, Memory: {{ ansible_memtotal_mb }} MB"
      when: ansible_distribution == "Ubuntu" or ansible_memtotal_mb < 2048

Vamos analisar este playbook:

  • Definimos uma variável check_memory no nível do playbook. Ela poderia ser definida dinamicamente ou passada como uma variável extra ao executar o playbook.

  • A primeira tarefa usa múltiplas condições:

    • Ela verifica se a família do SO é Debian
    • Ela verifica se a memória total é superior a 1024 MB (1 GB)
    • Ela verifica se a variável check_memory é verdadeira

    Todas essas condições devem ser verdadeiras para que a tarefa seja executada. O caractere | em check_memory | bool é um filtro que converte o valor para booleano.

  • A segunda tarefa demonstra o uso do operador or. Ela será executada se a distribuição for Ubuntu OU se a memória total for inferior a 2048 MB (2 GB).

  • Estamos usando mais fatos do Ansible aqui: ansible_distribution fornece o nome específico da distribuição, e ansible_memtotal_mb fornece a memória total do sistema em megabytes.

Salve e saia do editor nano.

Agora, vamos executar este playbook:

ansible-playbook -i ../inventory.ini multiple_conditions.yml

Observe a saída. Dependendo das características do seu sistema, você poderá ver uma ou ambas as mensagens de depuração.

Este exemplo mostra como você pode criar condições complexas para tornar seus playbooks altamente adaptáveis a diferentes cenários. Você pode combinar vários fatos do sistema, variáveis personalizadas e operadores lógicos para ajustar com precisão quando suas tarefas devem ser executadas.

Introdução aos Loops

Nesta etapa, você usará loops do Ansible para repetir uma tarefa com valores diferentes. Isso é útil quando você precisa realizar a mesma ação com vários itens, como criar vários usuários, instalar múltiplos pacotes ou criar vários diretórios.

Vamos criar um playbook para demonstrar o uso de loops. Crie um novo arquivo chamado loop_example.yml:

nano loop_example.yml

Agora, adicione o seguinte conteúdo:

---
- name: Loop Example
  hosts: localhost
  vars:
    fruits:
      - apple
      - banana
      - cherry
  tasks:
    - name: Print fruit names
      debug:
        msg: "Current fruit: {{ item }}"
      loop: "{{ fruits }}"

    - name: Create directories
      file:
        path: "/tmp/{{ item }}"
        state: directory
      loop:
        - dir1
        - dir2
        - dir3

Vamos analisar este código:

  • Definimos uma variável fruits como uma lista de nomes de frutas.

  • A primeira tarefa usa um loop para iterar sobre a lista fruits. Para cada iteração, o valor atual fica disponível como {{ item }}.

  • A segunda tarefa demonstra como usar um loop com o módulo file para criar múltiplos diretórios. Estamos criando três diretórios na pasta /tmp.

  • Observe que podemos usar o loop diretamente na tarefa (como na segunda tarefa) ou referenciar uma variável (como na primeira tarefa).

Salve e saia do editor nano.

Agora, vamos executar este playbook:

ansible-playbook -i ../inventory.ini loop_example.yml

Quando você executar este playbook, verá que a primeira tarefa imprime o nome de cada fruta e a segunda tarefa cria três diretórios em /tmp.

Os loops são um recurso poderoso no Ansible que pode reduzir significativamente a quantidade de código repetitivo em seus playbooks. Eles são especialmente úteis ao trabalhar com listas de itens, como usuários, pacotes ou arquivos.

Técnicas Avançadas de Loop

Nesta etapa, você usará técnicas avançadas de loop do Ansible para trabalhar com estruturas de dados complexas e controlar o processo de repetição.

Crie um novo arquivo chamado advanced_loops.yml:

nano advanced_loops.yml

Agora, adicione o seguinte conteúdo:

---
- name: Advanced Loop Techniques
  hosts: localhost
  vars:
    users:
      - name: alice
        groups: ["developers", "testers"]
      - name: bob
        groups: ["managers", "developers"]
  tasks:
    - name: Create users with groups
      debug:
        msg: "Creating user {{ item.name }} with groups: {{ item.groups | join(', ') }}"
      loop: "{{ users }}"

    - name: Demonstrate loop_control
      debug:
        msg: "Processing item {{ index }} - {{ item }}"
      loop: ["a", "b", "c", "d"]
      loop_control:
        index_var: index

    - name: Loop over dictionary
      debug:
        msg: "{{ key }}: {{ value }}"
      loop: "{{ {'x': 1, 'y': 2, 'z': 3} | dict2items }}"
      vars:
        key: "{{ item.key }}"
        value: "{{ item.value }}"

Vamos analisar estas técnicas avançadas:

  • Fazendo loop sobre uma lista de dicionários: A primeira tarefa percorre a lista users, onde cada item é um dicionário contendo um nome e uma lista de grupos. Podemos acessar esses elementos aninhados usando a notação de ponto (item.name, item.groups).

  • Usando o loop_control: A segunda tarefa demonstra o loop_control, que nos permite alterar o nome da variável de loop (o padrão é item) e acessar o índice atual do loop. Aqui, usamos index_var: index para criar uma variável index que acompanha o número da iteração atual.

  • Fazendo loop sobre um dicionário: A última tarefa mostra como percorrer um dicionário. Usamos o filtro dict2items para converter o dicionário em uma lista de pares chave-valor que podem ser iterados. Em seguida, usamos item.key e item.value para acessar as chaves e os valores do dicionário.

Salve e saia do editor nano.

Agora, vamos executar este playbook:

ansible-playbook -i ../inventory.ini advanced_loops.yml

Quando você executar este playbook, verá como essas técnicas avançadas de loop funcionam. A saída mostrará:

  • Mensagens de criação de usuários com seus respectivos grupos
  • Itens sendo processados juntamente com seus índices
  • Pares de chave-valor extraídos do dicionário

Essas técnicas avançadas permitem trabalhar com estruturas de dados mais complexas e oferecem um controle mais refinado sobre os seus loops. Elas são particularmente úteis ao lidar com dados aninhados, quando você precisa acompanhar o índice do loop ou quando trabalha com dicionários.

Resumo

Neste laboratório, você aprendeu sobre condicionais e loops no Ansible, duas funcionalidades poderosas que permitem criar playbooks mais dinâmicos e eficientes. Aqui estão os principais aprendizados:

  1. As condicionais (cláusula when) permitem controlar a execução de tarefas com base em condições específicas, como fatos sobre o sistema de destino ou variáveis definidas pelo usuário.
  2. Você pode combinar várias condições usando operadores lógicos como and e or para criar declarações condicionais mais complexas.
  3. Os loops (palavra-chave loop) permitem repetir tarefas com valores diferentes, aumentando a eficiência e reduzindo a complexidade do playbook.
  4. O Ansible oferece suporte a vários tipos de loops, incluindo iteração sobre listas, dicionários e estruturas de dados mais complexas.
  5. Técnicas avançadas de loop, como loop_control e a iteração sobre dicionários, proporcionam ainda mais flexibilidade no tratamento de tarefas repetitivas.

Esses recursos são essenciais para criar playbooks do Ansible flexíveis e potentes, capazes de se adaptar a diferentes cenários e gerenciar eficientemente múltiplos itens. À medida que você continuar trabalhando com Ansible, pratique incorporar condicionais e loops em seus playbooks para torná-los mais dinâmicos e eficientes.

Lembre-se de sempre considerar a legibilidade e a manutenibilidade dos seus playbooks ao usar esses recursos. Embora eles possam simplificar muito o seu código, o uso excessivo ou condições e loops excessivamente complexos podem dificultar a compreensão e a manutenção dos playbooks.