britho / Ansible-HedHat

0 stars 0 forks source link

Aula-3-4-5 #3

Open britho opened 3 years ago

britho commented 3 years ago

Meta | Escrever um playbook do Ansible simples e executá-lo para automatizar tarefas em vários hosts. -- | -- Objetivos | Escrever um playbook do Ansible básico e executá-lo usando o comando ansible-playbook. Escrever um playbook que usa múltiplas ações e escalonamento de privilégios por ação. Usar ansible-doc de maneira eficaz a fim de aprender a usar novos módulos para implementar tarefas em uma ação. Seções | Criação e execução de playbooks (e exercício orientado)Implementação de múltiplas ações (e exercício orientado) Laboratório | Implementação de playbooks

Objetivos

Depois de concluir esta seção, você deverá ser capaz de escrever um playbook básico do Ansible e executá-lo usando o comando ansible-playbook.

Playbooks do Ansible e comandos ad hoc

Os comandos ad hoc podem ser executados como uma tarefa simples e única em um conjunto de hosts direcionados como um comando avulso. O verdadeiro poder do Ansible, contudo, está em aprender como usar playbooks para executar múltiplas tarefas complexas em um conjunto de hosts direcionados de uma maneira facilmente reproduzível.

Uma ação é um conjunto ordenado de tarefas executadas em relação a hosts selecionados no inventário. Um playbook é um arquivo de texto contendo uma lista de uma ou mais ações a serem executadas em uma ordem específica.

Os playbooks permitem que você altere um conjunto longo e complexo de tarefas manuais em uma rotina facilmente reproduzível com resultados previsíveis e com êxito. Em um playbook, você pode salvar a sequência de tarefas em uma ação em um formato legível e imediatamente executável. As tarefas em si, devido à maneira na qual elas foram escritas, documentam as etapas necessárias para implantar seu aplicativo ou infraestrutura.

Formato de um playbook do Ansible

Para ajudar você a entender o formato de um playbook, revise este comando ad hoc de um capítulo anterior:

[student@workstation ~]$ ansible -m user -a "name=newbie uid=4000 state=present" \
> servera.lab.example.com

Ele pode ser reescrito como uma ação de tarefa única e salvo em um playbook. O playbook resultante terá o seguinte conteúdo:

---
- name: Configure important user consistently
  hosts: servera.lab.example.com
  tasks:
    - name: newbie exists with UID 4000
      user:
        name: newbie
        uid: 4000
        state: present

Um playbook é um arquivo de texto escrito em formato YAML e é normalmente salvo com a extensão yml. O playbook usa recuo com caracteres de espaço para indicar a estrutura de seus dados. O YAML não estabelece requisitos rigorosos em relação à quantidade de espaços usada para o recuo, mas há duas regras básicas.

  • Os elementos de dados no mesmo nível da hierarquia (como itens na mesma lista) devem ter o mesmo recuo.

  • Itens que são filhos de um outro item devem ter mais recuo que os seus pais.

Você também pode adicionar linhas em branco por questões de legibilidade.

Apenas o caractere de espaço pode ser usado como recuo; caracteres de tabulação não são permitidos.

Se você usar o editor de texto vi, poderá aplicar algumas configurações que podem facilitar a edição dos seus playbooks. Por exemplo, você pode adicionar a linha a seguir ao seu arquivo $HOME/.vimrc e, quando vi detectar que você está editando um arquivo YAML, ele fará um recuo com dois espaços quando a tecla Tab for pressionada. As linhas seguintes serão automaticamente recuadas.

autocmd FileType yaml setlocal ai ts=2 sw=2 et

Um playbook começa com uma linha composta por três traços (---) como início do marcador de documento. Ele pode terminar em três pontos (...) como final de marcador de documento, embora, na prática, isso seja frequentemente omitido.

Entre esses marcadores, o playbook é definido como uma lista de ações. Um item em uma lista YAML começa com um único traço seguido por um espaço. Por exemplo, uma lista YAML poderá aparecer com o seguinte conteúdo:

- apple
- orange
- grape

Em , a linha depois de --- começa com um traço e inicia a primeira ação (e somente ela) na lista de ações.

A própria ação é uma coleção de pares de chave-valor. As chaves em uma mesma ação devem ter o mesmo recuo. O exemplo a seguir mostra um trecho YAML com três chaves. As duas primeiras chaves têm valores simples. A terceira tem uma lista de três itens como um valor.

  name: just an example
  hosts: webservers
  tasks:
    - first
    - second
    - third

A ação de exemplo original tem três chaves, name, hosts e tasks, porque todas essas chaves têm o mesmo recuo.

A primeira linha da ação de exemplo começa com um traço e um espaço (indicando que a ação é o primeiro item de uma lista) e, então, a primeira chave, o atributo name. A chave name associa com a ação uma string arbitrária de rótulo. Isso identifica para que serve a ação. A chave name é opcional, mas é recomendada, já que ela ajuda a documentar seu playbook. Isso é particularmente útil quando um playbook contém várias ações.

- name: Configure important user consistently

A segunda chave na ação é um atributo hosts, que especifica os hosts nos quais as tarefas da ação são executadas. Assim como o argumento para o comando ansible, o atributo hosts toma um padrão de host como um valor, como os nomes de hosts gerenciados ou grupos no inventário.

  hosts: servera.lab.example.com

Finalmente, a última chave na ação é o atributo tasks, cujo valor especifica uma lista de tarefas a serem executadas para esta ação. Este exemplo tem uma única tarefa, que executa o módulo user com argumentos específicos (para garantir que o usuário newbie existe e que tem uma UID 4000).

  tasks:
    - name: newbie exists with UID 4000
      user:
        name: newbie
        uid: 4000
        state: present

O atributo tasks é a parte da ação que realmente lista, em ordem, as tarefas a serem executadas nos hosts gerenciados. Cada tarefa na lista é, em si, uma coleção de pares de chave-valor.

Neste exemplo, a única tarefa na ação tem duas chaves:

  • name é um rótulo opcional que documenta o propósito da tarefa. É recomendável nomear todas as suas tarefas para ajudar a documentar o propósito de cada etapa do processo de automação.

  • user é o módulo a ser executado para esta tarefa. Seus argumentos são passados como uma coleção de pares de chave-valor, que são filhos do módulo (name, uid e state).

Abaixo, é apresentado outro exemplo de um atributo tasks com múltiplas tarefas, usando o módulo service para garantir que vários serviços de rede estejam habilitados para iniciar durante o boot:

  tasks:
    - name: web server is enabled
      service:
        name: httpd
        enabled: true
    - name: NTP server is enabled
      service:
        name: chronyd
        enabled: true
    - name: Postfix is enabled
      service:
        name: postfix
        enabled: true

A ordem na qual as ações e tarefas são listadas em um playbook é importante porque o Ansible as executa na mesma ordem.

Os playbooks que você viu até agora são exemplos básicos, e você verá exemplos mais sofisticados do que pode fazer com ações e tarefas à medida que este curso prosseguir.

Execução de playbooks

O comando ansible-playbook é usado para executar playbooks. O comando é executado no nó de controle e o nome do playbook a ser executado é passado como um argumento:

[student@workstation ~]$ ansible-playbook site.yml

Quando você executa o playbook, a saída é gerada para mostrar a ação e as tarefas sendo executadas. A saída também relata os resultados de cada tarefa executada.

O exemplo a seguir mostra o conteúdo de um playbook simples e o resultado de sua execução.

[student@workstation playdemo]$ cat webserver.yml
---
- name: play to setup web server
  hosts: servera.lab.example.com
  tasks:
  - name: latest httpd version installed
    yum:
      name: httpd
      state: latest
...output omitted...
[student@workstation playdemo]$ ansible-playbook webserver.yml
PLAY [play to setup web server] ************************************************
TASK [Gathering Facts] *********************************************************
ok: [servera.lab.example.com]
TASK [latest httpd version installed] ******************************************
changed: [servera.lab.example.com]
PLAY RECAP *********************************************************************
servera.lab.example.com    : ok=2    changed=1    unreachable=0    failed=0

Observe que o valor da chave name de cada ação e tarefa é exibido quando o playbook é executado. (A tarefa Gathering Facts é uma tarefa especial que o módulo setup normalmente executa de forma automática no início de uma ação. Isso é abordado posteriormente no curso). Para playbooks com múltiplas ações e tarefas, a definição dos atributos name torna fácil monitorar o progresso da execução do playbook.

Você também deverá ver que a tarefa latest httpd version installed é alterada para servera.lab.example.com. Isso significa que a tarefa alterou algo nesse host para garantir que sua especificação foi atendida. Neste caso, significa que o pacote httpd provavelmente não foi instalado ou não era a versão mais recente.

Em geral, as tarefas nos playbooks do Ansible são idempotentes e é seguro executar o playbook várias vezes. Se os hosts gerenciados direcionados já estiverem no estado correto, nenhuma mudança deve ser feita. Por exemplo, suponha que o playbook do exemplo anterior é executado novamente:

[student@workstation playdemo]$ ansible-playbook webserver.yml
PLAY [play to setup web server] ************************************************
TASK [Gathering Facts] *********************************************************
ok: [servera.lab.example.com]
TASK [latest httpd version installed] ******************************************
ok: [servera.lab.example.com]
PLAY RECAP *********************************************************************
servera.lab.example.com    : ok=2    changed=0    unreachable=0    failed=0

Dessa vez, todas as tarefas foram passadas com o status ok e nenhuma alteração foi relatada.

Aumento do detalhamento de saída

A saída padrão fornecida pelo comando ansible-playbook não fornece informações detalhadas de execução de tarefas. O comando ansible-playbook -v oferece informações adicionais, com um total de quatro níveis.

Opção | Descrição -- | -- -v | Os resultados da tarefa são exibidos. -vv | Os resultados da tarefa e a configuração da tarefa são exibidos. -vvv | Inclui informações sobre conexões com hosts gerenciados. -vvvv | Inclui opções adicionais de detalhes aos plug-ins de conexão, inclusive os usuários usados nos hosts gerenciados para executar scripts e o que estes executarão.

Verificação de sintaxe

Antes de executar um playbook, é recomendável realizar uma verificação para garantir que a sintaxe do conteúdo esteja correta. O comando ansible-playbook oferece uma opção --syntax-check que pode ser usada para verificar a sintaxe de um playbook. O exemplo a seguir mostra verificação com êxito da sintaxe de um playbook.

[student@workstation ~]$ ansible-playbook --syntax-check webserver.yml
playbook: webserver.yml

Quando uma verificação de sintaxe falha, um erro de sintaxe é reportado. A saída também inclui o local aproximado do problema de sintaxe no playbook. O exemplo a seguir mostra uma verificação de sintaxe de um playbook que falhou, na qual o separador de espaço está ausente após o atributo name da ação.

[student@workstation ~]$ ansible-playbook --syntax-check webserver.yml
ERROR! Syntax Error while loading YAML.
  mapping values are not allowed in this context
The error appears to have been in ...output omitted... line 3, column 8, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
- name:play to setup web server
  hosts: servera.lab.example.com
       ^ here

Execução de uma simulação

Você pode usar a opção -C para executar uma simulação da execução do playbook. Isso faz com que o Ansible relate que mudanças teriam ocorrido se o playbook fosse executado, mas não faz nenhuma mudança real nos hosts gerenciados.

O exemplo a seguir mostra a simulação de um playbook contendo uma tarefa única para garantir que a versão mais recente do pacote httpd esteja instalada em um host gerenciado. Observe que a simulação informa que a tarefa realizaria uma mudança no host gerenciado.

[student@workstation ~]$ ansible-playbook -C webserver.yml
PLAY [play to setup web server] ************************************************
TASK [Gathering Facts] *********************************************************
ok: [servera.lab.example.com]
TASK [latest httpd version installed] ******************************************
changed: [servera.lab.example.com]
PLAY RECAP *********************************************************************
servera.lab.example.com    : ok=2    changed=1    unreachable=0    failed=0
britho commented 3 years ago

Neste exercício, você escreverá e executará um playbook do Ansible.

Resultados

Você deverá ser capaz de escrever um playbook usando a sintaxe YAML básica e a estrutura de playbook do Ansible e executá-lo com êxito usando o comando ansible-playbook.

Faça login na workstation como student usando a senha student.

Na workstation, execute o comando lab playbook-basic start. Essa função garante que os hosts gerenciados serverc.lab.example.com e serverd.lab.example.com estejam acessíveis na rede. Ela também garante que o arquivo de configuração e o arquivo de inventário corretos do Ansible sejam instalados no nó de controle.

[student@workstation ~]$ lab playbook-basic start

O diretório de trabalho /home/student/playbook-basic foi criado na workstation para este exercício. Esse diretório já foi preenchido com um arquivo de configuração ansible.cfg e também um arquivo de inventário inventory, o que define um grupo web que inclui ambos os hosts gerenciados listados acima como membros.

Nesse diretório, use um editor de texto para criar um playbook chamado site.yml. Esse playbook contém uma ação, que deve se direcionar a membros do grupo de host web. O playbook deve usar tarefas para garantir que as seguintes condições sejam atendidas nos hosts gerenciados:

O pacote httpd esteja presente, usando o módulo yum.

O arquivo files/index.html local seja copiado para /var/www/html/index.html em cada host gerenciado usando o módulo copy.

O serviço httpd seja iniciado e esteja habilitado, usando o módulo service. 

Você pode usar o comando ansible-doc para ajudá-lo a entender as palavras-chave necessárias para cada um dos módulos.

Depois que o playbook for criado, verifique sua sintaxe e, então, use ansible-playbook para executá-lo e implementar a configuração.

Mude para o diretório /home/student/playbook-basic.

[student@workstation ~]$ cd ~/playbook-basic

Use o editor de texto para criar um novo playbook chamado /home/student/playbook-basic/site.yml. Comece a escrever uma ação direcionada aos hosts no grupo de hosts web.

    Crie e abra o ~/playbook-basic/site.yml. A primeira linha do arquivo deve ter três traços para indicar o início do playbook.

    ---

    A próxima linha inicia a ação. Ela precisa começar com um traço e um espaço antes da primeira palavra-chave da ação. Nomeie a ação com uma string arbitrária documentando qual é o propósito da ação, usando a palavra-chave name.

    ---
    - name: Install and start Apache HTTPD

    Adicione um par de palavra-chave e valor hosts para especificar que a ação é executada no grupo de hosts web do inventário. Certifique-se de que a palavra-chave hosts tem recuo de dois espaços de modo que se alinhe à palavra-chave name na linha anterior.

    O arquivo site.yml completo deve aparecer com o seguinte conteúdo:

    ---
    - name: Install and start Apache HTTPD
      hosts: web

Continue para editar o arquivo /home/student/playbook-basic/site.yml e adicione uma palavra-chave tasks e as três tarefas para sua ação que foram especificadas nas instruções.

    Adicione uma palavra-chave tasks com um recuo de dois espaços (alinhada com a palavra-chave hosts) para iniciar a lista de tarefas. Seu arquivo deve aparecer com o seguinte conteúdo:

    ---
    - name: Install and start Apache HTTPD
      hosts: web
      tasks:

    Adicione a primeira tarefa. Faça um recuo de quatro espaços e inicie a tarefa com um traço e um espaço e, então, dê um nome à tarefa, como httpd package is present. Use o módulo yum para essa tarefa. Recue mais dois espaços nas palavras-chave do módulo; configure o nome do pacote como httpd e o estado do pacote como present. A tarefa deverá aparecer com o seguinte conteúdo:

        - name: httpd package is present
          yum:
            name: httpd
            state: present

    Adicione a segunda tarefa: Corresponda ao formato da tarefa anterior e dê um nome à tarefa, como correct index.html is present. Use o módulo copy. As palavras-chave do módulo devem definir a chave src como files/index.html e a chave dest como /var/www/html/index.html. A tarefa deverá aparecer com o seguinte conteúdo:

        - name: correct index.html is present
          copy:
            src: files/index.html
            dest: /var/www/html/index.html

    Adicione a terceira tarefa para iniciar e habilitar o serviço httpd. Corresponda ao formato das duas tarefas anteriores e dê um nome à nova tarefa, como httpd is started. Use o módulo service para essa tarefa. Defina a chave name do serviço como httpd, a chave state como started e a chave enabled como true. A tarefa deverá aparecer com o seguinte conteúdo:

        - name: httpd is started
          service:
            name: httpd
            state: started
            enabled: true

    Todo o seu playbook do Ansible site.yml deve corresponder ao seguinte exemplo: Certifique-se de que o recuo das palavras-chave da ação, a lista de tarefas e as palavras-chave de cada tarefa estejam todas corretas.

    ---
    - name: Install and start Apache HTTPD
      hosts: web
      tasks:
        - name: httpd package is present
          yum:
            name: httpd
            state: present

        - name: correct index.html is present
          copy:
            src: files/index.html
            dest: /var/www/html/index.html

        - name: httpd is started
          service:
            name: httpd
            state: started
            enabled: true

    Salve o arquivo e feche o editor de texto. 

Antes de executar seu playbook, execute o comando ansible-playbook --syntax-check site.yml para verificar sua sintaxe. Se ela relatar algum erro, corrija-o antes de ir para a próxima etapa. Você verá uma saída semelhante à seguinte:

[student@workstation playbook-basic]$ ansible-playbook --syntax-check site.yml

playbook: site.yml

Execute o playbook. Leia a saída gerada para garantir que todas as tarefas foram concluídas com êxito.

[student@workstation playbook-basic]$ ansible-playbook site.yml

PLAY [Install and start Apache HTTPD] ******************************************

TASK [Gathering Facts] *********************************************************
ok: [serverd.lab.example.com]
ok: [serverc.lab.example.com]

TASK [httpd package is present] ************************************************
changed: [serverd.lab.example.com]
changed: [serverc.lab.example.com]

TASK [correct index.html is present] *******************************************
changed: [serverd.lab.example.com]
changed: [serverc.lab.example.com]

TASK [httpd is started] ********************************************************
changed: [serverd.lab.example.com]
changed: [serverc.lab.example.com]

PLAY RECAP *********************************************************************
serverc.lab.example.com    : ok=4    changed=3    unreachable=0    failed=0      
serverd.lab.example.com    : ok=4    changed=3    unreachable=0    failed=0

Se tudo tiver corrido bem, você deverá ser capaz de executar o playbook uma segunda vez e ver todas as tarefas concluídas sem nenhuma alteração nos hosts gerenciados.

[student@workstation playbook-basic]$ ansible-playbook site.yml

PLAY [Install and start Apache HTTPD] ******************************************

TASK [Gathering Facts] *********************************************************
ok: [serverd.lab.example.com]
ok: [serverc.lab.example.com]

TASK [httpd package is present] ************************************************
ok: [serverd.lab.example.com]
ok: [serverc.lab.example.com]

TASK [correct index.html is present] *******************************************
ok: [serverc.lab.example.com]
ok: [serverd.lab.example.com]

TASK [httpd is started] ********************************************************
ok: [serverd.lab.example.com]
ok: [serverc.lab.example.com]

PLAY RECAP *********************************************************************
serverc.lab.example.com    : ok=4    changed=0    unreachable=0    failed=0      
serverd.lab.example.com    : ok=4    changed=0    unreachable=0    failed=0

Use o comando curl para verificar se ambos serverc e serverd estão configurados como um servidor HTTPD.

[student@workstation playbook-basic]$ curl serverc.lab.example.com
This is a test page.
[student@workstation playbook-basic]$ curl serverd.lab.example.com
This is a test page.

Encerramento

Em workstation, execute o script lab playbook-basic finish para limpar os recursos criados neste exercício.

[student@workstation ~]$ lab playbook-basic finish

Isso conclui o exercício orientado.

britho commented 3 years ago

Objetivos

Depois de concluir esta seção, você deverá ser capaz de:

Escrever um playbook que usa múltiplas ações e escalonamento de privilégios por ação.

Usar ansible-doc de maneira eficaz a fim de aprender a usar novos módulos para implementar tarefas em uma ação. 

Criação de múltiplas ações

Um playbook é um arquivo YAML que contém uma lista de uma ou mais ações. Lembre-se de que uma única ação é uma lista ordenada de tarefas a serem executadas em hosts selecionados no inventário. Portanto, se um playbook contém múltiplas ações, cada ação deve aplicar suas tarefas a um conjunto separado de hosts.

Isso pode ser muito útil ao orquestrar uma implantação complexa que possa envolver diferentes tarefas em diferentes hosts. Você pode escrever um playbook que execute uma ação em um conjunto de hosts e, quando concluir, ele executa outra ação em outro conjunto de hosts.

Criar um playbook que contenha várias ações é algo muito simples. Cada ação no playbook é criada como um item de lista de nível superior no playbook. Cada ação é uma lista contendo as palavras-chave comuns de ação.

O exemplo a seguir mostra um playbook simples com duas ações. A primeira ação é executada em web.example.com e a segunda ação é executada em database.example.com.


This is a simple playbook with two plays

Usuários remotos e o escalonamento de privilégios em ações

As ações podem usar usuários remotos ou configurações de escalonamento de privilégios para uma ação diferentes do que é especificado pelos padrões no arquivo de configuração. Eles são definidos na própria ação no mesmo nível que as palavras-chave hosts ou tasks.

Atributos de usuário

As tarefas nos playbooks normalmente são executadas por meio de uma conexão de rede com os hosts gerenciados. Assim como com os comandos ad hoc, a conta de usuário usada para a execução de tarefas depende de várias palavras-chave do arquivo de configuração do Ansible, /etc/ansible/ansible.cfg. O usuário que executa as tarefas pode ser definido pela palavra-chave remote_user. Entretanto, se o escalonamento de privilégios estiver habilitado, outras palavras-chave, como become_user, também poderão causar impacto.

Se o usuário remoto definido na configuração do Ansible para a execução de tarefas não for adequado, ele poderá ser substituído usando a palavra-chave remote_user em uma ação.

remote_user: remoteuser

Atributos de escalonamento de privilégios

Palavras-chave adicionais também estão disponíveis para definir os parâmetros de escalonamento de privilégios dentro de um playbook. A palavra-chave booleana become pode ser utilizada para habilitar ou desabilitar o escalonamento de privilégios, independentemente de como estiver definida no arquivo de configuração do Ansible. Ela pode usar yes ou true para habilitar o escalonamento de privilégios, ou no ou false para desabilitá-lo.

become: true

Se o escalonamento de privilégios estiver habilitado, a palavra-chave become_method poderá ser usada para definir o método de escalonamento de privilégios a ser usado durante uma ação específica. O exemplo abaixo especifica que sudo deve ser usado para o escalonamento de privilégios.

become_method: sudo

Além disso, com o escalonamento de privilégios habilitado, a palavra-chave become_user pode definir a conta de usuário a ser utilizada para o escalonamento de privilégios no contexto de uma ação específica.

become_user: privileged_user

Este exemplo demonstra o uso dessas palavras-chave em uma ação:

Pesquisa de módulos para tarefas

Documentação dos módulos

O grande número de módulos que vêm integrados com o Ansible fornece aos administradores muitas ferramentas para tarefas administrativas comuns. No início deste curso, discutimos sobre o site da documentação do Ansible em http://docs.ansible.com. O Modules Index no site é uma maneira fácil de navegar pela lista dos módulos incluídos no Ansible. Por exemplo, os módulos para o gerenciamento de usuários e serviços podem ser encontrados nos Systems Modules, e os módulos para administração de bancos de dados podem ser encontrados nos Database Modules.

Para cada módulo, o site de documentação do Ansible fornece um sumário de suas funções e instruções sobre como cada função específica pode ser invocada com opções para o módulo. A documentação também fornece exemplos úteis que mostram como usar cada módulo e como definir suas palavras-chave em uma tarefa.

Você já trabalhou com o comando ansible-doc para procurar informações sobre módulos instalados no sistema local. Como revisão, para ver uma lista dos módulos disponíveis em um nó de controle, execute o comando ansible-doc -l. Ele exibe uma lista de nomes de nós e uma sinopse de suas funções.

[student@workstation modules]$ ansible-doc -l a10_server Manage A10 Networks ... devices' server object. a10_server_axapi3 Manage A10 Networks ... devices a10_service_group Manage A10 Networks ... devices' service groups. a10_virtual_server Manage A10 Networks ... devices' virtual servers. ...output omitted... zfs_facts Gather facts about ZFS datasets. znode Create, ... and update znodes using ZooKeeper zpool_facts Gather facts about ZFS pools. zypper Manage packages on SUSE and openSUSE zypper_repository Add and remove Zypper repositories

Use o comando ansible-doc [module name] para exibir a documentação detalhada de um módulo. Do mesmo modo que o site de documentação do Ansible, o comando fornece uma sinopse da função do módulo, detalhes de suas várias opções e exemplos. O exemplo a seguir mostra a documentação exibida para o módulo yum.

[student@workstation modules]$ ansible-doc yum

YUM (/usr/lib/python3.6/site-packages/ansible/modules/packaging/os/yum.py)

    Installs, upgrade, downgrades, removes, and lists packages and groups with the `yum' package manager. This module only works on Python 2. If you require Python
    3 support see the [dnf] module.

OPTIONS (= is mandatory):

O comando ansible-doc também oferece a opção -s, que produz um exemplo de saída que pode servir como um modelo de como usar um módulo específico em um playbook. Essa saída pode servir como um modelo de início que pode ser incluído em um playbook para implementar o módulo para execução das tarefas. Os comentários estão incluídos na saída para lembrar os administradores do uso de cada opção. O exemplo a seguir mostra a saída para o módulo yum.

[student@workstation ~]$ ansible-doc -s yum

Módulo de manutenção

O Ansible inclui um grande número de módulos que podem ser usados em muitas tarefas. A comunidade upstream é muita ativa e esses módulos podem estar em diferentes estágios de desenvolvimento. A documentação ansible-doc para o módulo deve especificar quem mantém esse módulo na comunidade upstream do Ansible e qual é seu status de desenvolvimento. Isso é indicado na seção METADATA no final da saída de ansible-doc desse módulo.

O campo status registra o status de desenvolvimento do módulo:

stableinterface: as palavras-chave do módulo são estáveis e todos os esforços serão feitos para não removê-las ou alterar seus significados.

preview: o módulo é uma amostra de tecnologia e pode ser instável, suas palavras-chave podem ser alteradas ou ele pode precisar de bibliotecas ou serviços web que estejam sujeitos a alterações incompatíveis.

deprecated: o módulo é obsoleto e não estará mais disponível em uma versão futura.

removed: o módulo foi removido da versão, mas existe um stub para propósito de documentação e para ajudar antigos usuários a migrarem para novos módulos. 

O status stableinterface apenas indica que a interface de um módulo é estável, mas não classifica a qualidade do código do módulo.

O campo supported_by registra quem mantém o módulo na comunidade upstream do Ansible. Os valores possíveis são:

core: mantido pelo upstream "core" de desenvolvedores do Ansible e é sempre incluído com o Ansible.

curated: módulos enviados e mantidos por parceiros ou empresas na comunidade. Os mantenedores desses módulos devem monitorar qualquer problema relatado ou extrair solicitações feitas em relação ao módulo. Os desenvolvedores "core" do upstream revisam alterações propostas a módulos curados depois que os mantenedores da comunidade aprovarem as alterações. Confirmadores core também garantem que qualquer problema com esses módulos devido a alterações no Ansible seja remediado. Esses módulos atualmente estão incluídos com o Ansible, mas podem ser empacotados separadamente em algum momento no futuro.

community: módulos não suportados por desenvolvedores core, parceiros ou empresas upstream, mas que são totalmente mantidos pela comunidade de open source em geral. Os módulos dessa categoria ainda são totalmente utilizáveis, mas o índice de resposta a problemas depende inteiramente da comunidade. Esses módulos atualmente também estão incluídos com o Ansible, mas provavelmente serão empacotados separadamente em algum ponto no futuro. 

A comunidade upstream do Ansible tem um rastreador de problemas para o Ansible e os módulos integrados em https://github.com/ansible/ansible/issues.

Às vezes, não existe um módulo para algo que você deseja fazer. Como um usuário final, você pode escrever seus módulos privados ou obter módulos de terceiros. O Ansible procura por módulos personalizados na localização especificada pela variável de ambiente ANSIBLE_LIBRARY, ou, se ela não estiver definida, por uma palavra-chave library no arquivo de configuração atual do Ansible. O Ansible também procura por módulos personalizados no diretório ./library relativo ao playbook atualmente sendo executado.

library = /usr/share/my_modules

Informações sobre a criação de módulos estão além do escopo deste curso. A documentação que explica como fazer isso está disponível em https://docs.ansible.com/ansible/latest/dev_guide/developing_modules.html.

Use o comando ansible-doc para descobrir e aprender como usar os módulos para suas tarefas.

Sempre que possível, tente evitar os módulos command, shell e raw em playbooks, por mais simples de usar que eles pareçam. Como eles têm comandos arbitrários, é muito fácil escrever playbooks não idempotentes com esses módulos.

Por exemplo, a tarefa a seguir usando o módulo shell não é idempotente. Cada vez que a ação é executada, ela sobrescreve /etc/resolv.conf, mesmo se já consistir na linha nameserver 192.0.2.1.

Há várias maneiras de escrever tarefas usando o módulo shell de uma forma idempotente e, às vezes, fazer tais alterações e usar shell é a melhor abordagem. Uma solução mais rápida pode ser utilizar ansible-doc para detectar o módulo copy e depois utilizá-lo para obter o efeito desejado.

O exemplo a seguir não sobrescreve o arquivo /etc/resolv.conf se ele já tiver o conteúdo correto:

O módulo copy testa se o estado já foi atingido e, nesse caso, não faz nenhuma alteração. O módulo shell permite muita flexibilidade, mas também exige mais atenção para garantir que seja executado de forma idempotente.

Os playbooks idempotentes também podem ser executados repetidas vezes para garantir que os sistemas se encontrem em determinado estado sem interromper os sistemas caso a resposta seja afirmativa. Variações da sintaxe de playbooks

A última parte deste capítulo investiga algumas variações da sintaxe YAML ou de playbooks do Ansible com os quais você poderá se deparar.

Comentários YAML

Os comentários também podem ser usados para melhorar a legibilidade. Em YAML, tudo que estiver à direita do símbolo de cerquilha ou símbolo de hash (#) é um comentário. Se houver conteúdo à esquerda do comentário, insira um espaço antes da cerquilha.

This is a YAML comment

some data # This is also a YAML comment

Strings do YAML

As strings no YAML normalmente não precisam estar entre aspas, mesmo que haja espaços na string. Você pode colocar as strings entre aspas duplas ou simples.

this is a string

'this is another string'

"this is yet another a string"

Há duas maneiras de escrever strings multilinhas. Você pode usar o caractere de barra vertical (|) para denotar que caracteres de nova linha dentro da string devem ser preservados.

include_newlines: | Example Company 123 Main Street Atlanta, GA 30303

Você também pode escrever strings multilinhas usando o caractere de maior que (>) para indicar que os caracteres de nova linha devem ser convertidos em espaços e que espaços em branco à esquerda nas linhas devem ser removidos. Esse método é usado com frequência para quebrar strings longas em espaços de caracteres para que elas possam ser distribuídas em várias linhas para maior legibilidade.

fold_newlines: > This is an example of a long string, that will become a single sentence once folded.

Dicionário de YAML

Você viu coleções de pares de chave-valor escritos como um bloco com recuo, conforme a seguir:

name: svcrole svcservice: httpd svcport: 80

Os dicionários também podem ser escritos em formato de bloco entre chaves em linha, conforme a seguir:

{name: svcrole, svcservice: httpd, svcport: 80}

Na maioria dos casos, o formato de bloco em linha deve ser evitado, pois é mais difícil de ser lido. Contudo, há, no mínimo, uma situação na qual ele é mais comumente usado. O uso de roles é discutido em detalhes mais adiante neste curso. Quando um playbook inclui uma lista de funções, é mais comum usar essa sintaxe para facilitar a distinção entre as funções incluídas em uma ação e as variáveis sendo passadas para uma função.

Listas de YAML

Você também viu listas escritas com sintaxe normal com um traço:

hosts:

As listas também têm um formato embutido entre colchetes, como a seguir:

hosts: [servera, serverb, serverc]

Você deve evitar essa sintaxe porque ela geralmente é mais difícil de ler.

Abreviação obsoleta de playbook com chave=valor

Alguns playbooks podem usar um método antigo de abreviação para definir tarefas colocando os pares de chave-valor do módulo na mesma linha que o nome do módulo. Por exemplo, você pode ver esta sintaxe:

tasks:

Normalmente, você escreveria a mesma tarefa assim:

tasks:

Em geral, você deve evitar a forma abreviada e usar a forma normal.

A forma normal tem mais linhas, mas é mais fácil de se trabalhar. As palavras-chave da tarefa são empilhadas verticalmente e são mais fáceis de diferenciar. Seus olhos podem descer ao longo da ação com menos movimentos da esquerda para a direita. Além disso, a sintaxe normal é nativa de YAML, enquanto a abreviada não é. Ferramentas de destaque de sintaxe em editores de texto modernos podem ajudar de forma mais eficaz se você utilizar o formato abreviado.

Você pode ver essa sintaxe em documentos e playbooks antigos de outras pessoas e ver que a sintaxe ainda funciona.

Páginas do man ansible-playbook(1) e ansible-doc(1)

Intro to Playbooks — Ansible Documentation

Playbooks — Ansible Documentation

Developing Modules — Ansible Documentation

Module Support — Ansible Documentation

YAML Syntax — Ansible Documentation

britho commented 3 years ago

Neste exercício, você criará um playbook que contém várias ações. Depois, você usará esse playbook para realizar tarefas de configuração em hosts gerenciados.

Resultados

Você deverá ser capaz de criar e executar um playbook para gerenciar a configuração e realizar a administração de um host gerenciado.

Faça login na workstation como student usando a senha student.

Na workstation, execute o comando lab playbook-multi start. Essa função garante que o host gerenciado, servera.lab.example.com, esteja acessível na rede. Ela também garante que o arquivo de configuração e o arquivo de inventário corretos do Ansible sejam instalados no nó de controle.

[student@workstation ~]$ lab playbook-multi start
  1. Um diretório de trabalho, /home/student/playbook-multi, foi criado na workstation para o projeto do Ansible. O diretório já foi preenchido com um arquivo de configuração ansible.cfg e um arquivo de inventário inventory. O host gerenciado, servera.lab.example.com, já está definido nesse arquivo de inventário. Crie um novo playbook, /home/student/playbook-multi/intranet.yml, e adicione as linhas necessárias para iniciar a primeira ação. Ele deve ser direcionado ao host gerenciado servera.lab.example.com e habilitar o escalonamento de privilégios.

    1. Altere o diretório para o diretório de trabalho /home/student/playbook-multi.

      [student@workstation ~]$ cd ~/playbook-multi
      [student@workstation playbook-multi]$ 
    2. Crie e abra um novo playbook, /home/student/playbook-multi/intranet.yml, e adicione uma linha composta por três traços no início do arquivo para indicar o começo do arquivo YAML.

      ---
    3. Adicione a linha a seguir ao arquivo /home/student/playbook-multi/intranet.yml para denotar o início de uma ação com o nome Enable intranet services.

      - name: Enable intranet services
    4. Adicione a linha a seguir para indicar que a ação se aplica ao host gerenciado servera.lab.example.com. Certifique-se de fazer o recuo da linha com dois espaços (alinhando com a palavra-chave name acima dela) para indicar que ela faz parte da primeira ação.

        hosts: servera.lab.example.com
    5. Adicione a linha a seguir para habilitar o escalonamento de privilégios. Certifique-se de fazer o recuo da linha com dois espaços (alinhando com as palavras-chave acima dela) para indicar que ela faz parte da primeira ação.

        become: yes
    6. Adicione a linha a seguir para definir o início da lista tasks. Faça o recuo da linha com dois espaços (alinhando com as palavras-chave acima dela) para indicar que ela faz parte da primeira ação.

        tasks:
  2. Como a primeira tarefa na primeira ação, defina a tarefa que garanta que os pacotes httpd e firewalld estejam atualizados.

    Certifique-se de fazer o recuo da primeira linha da tarefa com quatro espaços. Abaixo da palavra-chave tasks na primeira ação, adicione as linhas a seguir.

        - name: latest version of httpd and firewalld installed
          yum:
            name:
              - httpd
              - firewalld
            state: latest

    A primeira linha fornece um nome descritivo para a tarefa. A segunda linha é recuada com seis espaços e chama o módulo yum. A primeira linha é recuada com oito espaços e é uma palavra-chave name. Ela especifica quais pacotes o módulo yum deve garantir que estejam atualizados. A palavra-chave name (que é diferente do nome da tarefa) do módulo yum pode receber uma lista de pacotes, que é recuada com dez espaços nas duas linhas a seguir. Depois da lista, a palavra-chave state com recuo de oito espaços especifica que o módulo yum deve garantir que a versão mais recente dos pacotes está instalada.

  3. Adicione uma tarefa à lista da primeira ação que garante que o conteúdo correto esteja em /var/www/html/index.html.

    Adicione as linhas a seguir para definir o conteúdo para /var/www/html/index.html. Certifique-se de fazer o recuo da primeira linha com quatro espaços.

        - name: test html page is installed
          copy:
            content: "Welcome to the example.com intranet!\n"
            dest: /var/www/html/index.html

    A primeira entrada fornece um nome descritivo para a tarefa. A segunda entrada é recuada com seis espaços e chama o módulo copy. As entradas restantes são recuadas com oito espaços e passam os argumentos necessários para garantir que o conteúdo correto está na página da web.

  4. Defina mais duas tarefas na ação para garantir que o serviço firewalld esteja em execução e será iniciado durante o boot e, além disso, permitirá conexões ao serviço httpd.

    1. Adicione as linhas a seguir ao arquivo para garantir que o serviço firewalld esteja ativado e funcionando. Certifique-se de fazer o recuo da primeira linha com quatro espaços.

          - name: firewalld enabled and running
            service:
              name: firewalld
              enabled: true
              state: started

      A primeira entrada fornece um nome descritivo para a tarefa. A segunda entrada é recuada com oito espaços e chama o módulo service. As entradas restantes são recuadas com dez espaços e passam os argumentos necessários para garantir que o serviço firewalld esteja ativado e funcionando.

    2. Adicione as linhas a seguir para garantir que o firewalld permita conexões HTTP a partir de sistemas remotos. Certifique-se de fazer o recuo da primeira linha com quatro espaços.

          - name: firewalld permits access to httpd service
            firewalld:
              service: http
              permanent: true
              state: enabled
              immediate: yes

      A primeira entrada fornece um nome descritivo para a tarefa. A segunda entrada é recuada com seis espaços e chama o módulo firewalld. As entradas restantes são recuadas com oito espaços e passam os argumentos necessários para garantir que as conexões HTTP remotas sejam permitidas permanentemente.

  5. Adicione uma tarefa à primeira ação que tenha o objetivo de garantir que o serviço httpd esteja em execução e iniciará durante o boot.

    Adicione as linhas a seguir ao arquivo para garantir que o serviço httpd esteja ativado e funcionando. Certifique-se de fazer o recuo da primeira linha com quatro espaços.

        - name: httpd enabled and running
          service:
            name: httpd
            enabled: true
            state: started

    A primeira entrada fornece um nome descritivo para a tarefa. A segunda entrada é recuada com seis espaços e chama o módulo service. As entradas restantes são recuadas com oito espaços e passam os argumentos necessários para garantir que o serviço httpd esteja ativado e funcionando.

  6. Em /home/student/playbook-multi/intranet.yml, defina uma segunda ação direcionada ao localhost que testará o servidor web da intranet. Ela não precisa de privilégios de escalonamento.

    1. Adicione a linha a seguir para definir o início de uma segunda ação. Observe que não há recuo.

      - name: Test intranet web server
    2. Adicione a linha a seguir para indicar que a ação se aplica ao host gerenciado localhost. Certifique-se de recuar a linha com dois espaços para indicar que é contida pela segunda ação.

        hosts: localhost
    3. Adicione a linha a seguir para desabilitar o escalonamento de privilégios. Certifique-se de alinhar o recuo com a palavra-chave hosts acima dele.

        become: no
    4. Adicione a linha a seguir ao arquivo /home/student/playbook-multi/intranet.yml para definir o início da lista tasks. Certifique-se de recuar a linha com dois espaços para indicar que é contida pela segunda ação.

        tasks:
  7. Adicione uma única tarefa à segunda ação e use o módulo uri para solicitar conteúdo de http://servera.lab.example.com. A tarefa deve verificar um código de status HTTP de retorno 200. Configure a tarefa para colocar o conteúdo retornado na variável de resultados da tarefa.

    Adicione as linhas a seguir para criar a tarefa de modo a verificar o serviço web a partir do nó de controle. Certifique-se de fazer o recuo da primeira linha com quatro espaços.

        - name: connect to intranet web server
          uri:
            url: http://servera.lab.example.com
            return_content: yes
            status_code: 200

    A primeira linha fornece um nome descritivo para a tarefa. A segunda linha é recuada com seis espaços e chama o módulo uri. As linhas restantes são recuadas com oito espaços e passam os argumentos necessários para executar uma consulta para o conteúdo da web a partir do nó de controle para o host gerenciado e verificam o código do status recebido. A palavra-chave return_content garante que a resposta do servidor seja adicionada aos resultados da tarefa.

  8. Verifique se o playbook final /home/student/playbook-multi/intranet.yml reflete o conteúdo estruturado a seguir. Em seguida, salve e feche o arquivo.

    ---
    - name: Enable intranet services
      hosts: servera.lab.example.com
      become: yes
      tasks:
        - name: latest version of httpd and firewalld installed
          yum:
            name:
              - httpd
              - firewalld
            state: latest
        - name: test html page is installed
          copy:
            content: "Welcome to the example.com intranet!\n"
            dest: /var/www/html/index.html
        - name: firewalld enabled and running
          service:
            name: firewalld
            enabled: true
            state: started
        - name: firewalld permits access to httpd service
          firewalld:
            service: http
            permanent: true
            state: enabled
            immediate: yes
        - name: httpd enabled and running
          service:
            name: httpd
            enabled: true
            state: started
    - name: Test intranet web server
      hosts: localhost
      become: no
      tasks:
        - name: connect to intranet web server
          uri:
            url: http://servera.lab.example.com
            return_content: yes
            status_code: 200
  9. Execute o comando ansible-playbook --syntax-check para verificar a sintaxe do playbook /home/student/playbook-multi/intranet.yml.

    [student@workstation playbook-multi]$ ansible-playbook --syntax-check intranet.yml
    playbook: intranet.yml
  10. Execute o playbook usando a opção -v para produzir resultados detalhados para cada tarefa. Leia a saída gerada para garantir que todas as tarefas foram concluídas com êxito. Verifique se uma solicitação HTTP GET para http://servera.lab.example.com fornece o conteúdo correto.

    [student@workstation playbook-multi]$ ansible-playbook -v intranet.yml
    ...output omitted...
    PLAY [Enable intranet services] *************************************************
    TASK [Gathering Facts] **********************************************************
    ok: [servera.lab.example.com]
    TASK [latest version of httpd and firewalld installed] **************************
    changed: [servera.lab.example.com] => {"changed": true, ...output omitted...
    TASK [test html page is installed] **********************************************
    changed: [servera.lab.example.com] => {"changed": true, ...output omitted...
    TASK [firewalld enabled and running] ********************************************
    ok: [servera.lab.example.com] => {"changed": false, ...output omitted...
    TASK [firewalld permits http service] *******************************************
    changed: [servera.lab.example.com] => {"changed": true, ...output omitted...
    TASK [httpd enabled and running] ************************************************
    changed: [servera.lab.example.com] => {"changed": true, ...output omitted...
    PLAY [Test intranet web server] *************************************************
    TASK [Gathering Facts] **********************************************************
    ok: [localhost]
    TASK [connect to intranet web server] *******************************************
    ok: [localhost] => {"accept_ranges": "bytes", "changed": false, "connection": "cl
    ose", "content"1: "Welcome to the example.com intranet!\n", "content_length":
     "37", "content_type": "text/html; charset=UTF-8", "cookies": {}, "cookies_string
    ": "", "date": "...output omitted...", "etag": "\"25-5790ddbcc5a48\"",
     "last_modified": "...output omitted...", "msg": "OK (37 bytes)", "redir
    ected": false, "server": "Apache/2.4.6 (Red Hat Enterprise Linux)",
    "status"2: 200, "url": "http://servera.lab.example.com"}
    PLAY RECAP **********************************************************************
    localhost                  : ok=2    changed=0    unreachable=0    failed=0    
    servera.lab.example.com    : ok=6    changed=4    unreachable=0    failed=0
      | O servidor respondeu com o conteúdo desejado, Welcome to the example.com intranet!\n. -- | --   | O servidor respondeu com um código de status HTTP de 200.
britho commented 3 years ago

Lista de verificação de desempenho

Neste laboratório, você configurará e realizará tarefas administrativas em hosts gerenciados usando um playbook.

Resultados

Você deve construir e executar um playbook para instalar, configurar e verificar o status dos serviços da web e de banco de dados em um host gerenciado.

Faça login na workstation como student usando a senha student.

Na workstation, execute o comando lab playbook-review start. Essa função garante que o host gerenciado, serverb.lab.example.com, esteja acessível na rede. Ela também garante que o arquivo de configuração e o arquivo de inventário corretos do Ansible sejam instalados no nó de controle.

[student@workstation ~]$ lab playbook-review start

Um diretório de trabalho, /home/student/playbook-review, foi criado na workstation para o projeto do Ansible. O diretório já foi preenchido com um arquivo de configuração ansible.cfg e um arquivo inventory. O host gerenciado, serverb.lab.example.com, já está definido nesse arquivo de inventário.

O playbook usado neste laboratório é muito semelhante ao que você escreveu no exercício orientado anterior deste capítulo. Se não quiser criar o playbook deste laboratório do zero, você pode usar o playbook deste exercício como um ponto inicial deste laboratório.

Se você o fizer, tenha cuidado ao direcionar aos hosts corretos e alterar as tarefas para corresponderem às instruções deste exercício.

Crie um novo playbook, /home/student/playbook-review/internet.yml, e adicione as entradas necessárias para iniciar uma primeira ação chamada Enable internet services e especifique seu host gerenciado pretendido, serverb.lab.example.com. Adicione uma entrada para habilitar o escalonamento de privilégios e outra para iniciar uma lista de tarefas.

Adicione as entradas necessárias ao arquivo /home/student/playbook-review/internet.yml para definir uma tarefa que instale as versões mais recentes dos pacotes firewalld, httpd, mariadb-server, php e php-mysqlnd.

- name: latest version of all required packages installed
  yum:
    name:
      - firewalld
      - httpd
      - mariadb-server
      - php
      - php-mysqlnd
    state: latest

Adicione as entradas necessárias ao arquivo /home/student/playbook-review/internet.yml para definir as tarefas de configuração do firewall. Eles devem garantir que o serviço firewalld esteja ativado e em execução, e esse acesso é permitido ao serviço httpd.

- name: firewalld enabled and running
  service:
    name: firewalld
    enabled: true
    state: started

- name: firewalld permits http service
  firewalld:
    service: http
    permanent: true
    state: enabled
    immediate: yes

Adicione as tarefas necessárias para garantir que os serviços httpd e mariadb estejam ativados e em execução.

- name: httpd enabled and running
  service:
    name: httpd
    enabled: true
    state: started

- name: mariadb enabled and running
  service:
    name: mariadb
    enabled: true
    state: started

Adicione as entradas necessárias para definir a tarefa final com o objetivo de gerar conteúdo da web para teste. Use o módulo get_url para copiar http://materials.example.com/labs/playbook-review/index.php para /var/www/html/ no host gerenciado.

- name: test php page is installed
  get_url:
    url: "http://materials.example.com/labs/playbook-review/index.php"
    dest: /var/www/html/index.php
    mode: 0644

Em /home/student/playbook-review/internet.yml, defina outra ação para a tarefa ser realizada no nó de controle. Essa ação testará o acesso ao servidor web que deve estar em execução no host gerenciado serverb. Essa ação não exige escalonamento de privilégios e será executada no host gerenciado localhost.

Adicione a entrada a seguir para denotar o início de uma segunda ação com o nome de Test internet web server.

- name: Test internet web server

Adicione a entrada a seguir para indicar que a ação se aplica ao host gerenciado localhost.

  hosts: localhost

Adicione a linha a seguir após a palavra-chave hosts para desabilitar o escalonamento de privilégios para a segunda ação.

  become: no

Adicione uma entrada ao arquivo /home/student/playbook-review/internet.yml para definir o início da lista tasks.

  tasks:

Adicione uma tarefa que testa o serviço web em execução mp serverb a partir do nó de controle usando o módulo uri. Verifique se há um código de status de retorno 200.

- name: connect to internet web server
  uri:
    url: http://serverb.lab.example.com
    status_code: 200

Verifique a sintaxe do playbook internet.yml.

[student@workstation playbook-review]$ ansible-playbook --syntax-check \

internet.yml

playbook: internet.yml

Use o comando ansible-playbook para executar o playbook. Leia a saída gerada para garantir que todas as tarefas foram concluídas com êxito.

[student@workstation playbook-review]$ ansible-playbook internet.yml PLAY [Enable internet services] ****

TASK [Gathering Facts] ***** ok: [serverb.lab.example.com]

TASK [latest version of all required packages installed] *** changed: [serverb.lab.example.com]

TASK [firewalld enabled and running] *** ok: [serverb.lab.example.com]

TASK [firewalld permits http service] ** changed: [serverb.lab.example.com]

TASK [httpd enabled and running] *** changed: [serverb.lab.example.com]

TASK [mariadb enabled and running] ***** changed: [serverb.lab.example.com]

TASK [test php page installed] ***** changed: [serverb.lab.example.com]

PLAY [Test internet web server] ****

TASK [Gathering Facts] ***** ok: [localhost]

TASK [connect to internet web server] ** ok: [localhost]

PLAY RECAP ***** localhost : ok=2 changed=0 unreachable=0 failed=0 serverb.lab.example.com : ok=7 changed=5 unreachable=0 failed=0

Avaliação

Classifique seu trabalho executando o comando lab playbook-review grade a partir da sua máquina workstation. Corrija todas as falhas relatadas e execute novamente o script até que ele seja concluído com êxito.

[student@workstation ~]$ lab playbook-review grade

Encerramento

Na workstation, execute o script lab playbook-review finish para limpar os recursos criados neste laboratório.

[student@workstation ~]$ lab playbook-review finish

Isso conclui o laboratório.

britho commented 3 years ago

Neste capítulo, você aprendeu que:

Uma ação é uma lista ordenada de tarefas que é executada em hosts selecionados no inventário.

Um playbook é um arquivo de texto que contém uma lista de uma ou mais ações a serem executadas em ordem.

Os playbooks do Ansible são escritos no formato YAML.

Os arquivos YAML são estruturados usando recuo de espaço para representar a hierarquia de dados.

As tarefas são implementadas usando codificações padronizadas empacotadas como módulos do Ansible.

O comando ansible-doc pode listar módulos instalados, além de fornecer documentação e trechos de código de exemplos de como usá-los em playbooks.

O comando ansible-playbook é usado para verificar a sintaxe de playbooks e executar playbooks. 
britho commented 3 years ago

Meta | Escrever playbooks que usem variáveis para simplificar o gerenciamento do playbook e fatos para fazer referência a informações sobre os hosts gerenciados. -- | -- Objetivos | Criar e fazer referência a variáveis que afetam determinados hosts ou grupos de hosts, a ação ou o ambiente global, além de descrever como funciona a precedência de variáveis. Criptografar variáveis confidenciais usando o Ansible Vault e executar os playbooks que fazem referência aos arquivos com variáveis criptografadas pelo Vault. Fazer referência a dados sobre hosts gerenciados usando fatos do Ansible e configurar fatos personalizados em hosts gerenciados. Seções | Gerenciamento de variáveis (e exercício orientado) Gerenciamento de segredos (e exercício orientado) Gerenciamento de fatos (e exercício orientado) Laboratório | Gerenciamento de variáveis e fatos

Objetivos

Depois de concluir esta seção, você deverá ser capaz de criar e fazer referência a variáveis do playbooks que afetam determinados hosts ou grupos de hosts, a ação ou o ambiente global, além de descrever como funciona a precedência de variáveis.

Introdução às variáveis do Ansible

O Ansible suporta variáveis que podem ser usadas para armazenar valores que podem ser reutilizados entre todos os arquivos de um projeto do Ansible. Isso poderá simplificar a criação e a manutenção de um projeto e reduzir o número de erros.

As variáveis proporcionam um modo conveniente de gerenciar valores dinâmicos para um dado ambiente em seu projeto do Ansible. Os exemplos de valores que as variáveis podem conter incluem:

  • Usuários a criar

  • Pacotes a instalar

  • Serviços a reiniciar

  • Arquivos a remover

  • Arquivos a recuperar da internet

Nomeação de variáveis

Os nomes das variáveis devem começar com uma letra e podem conter apenas letras, números e sublinhados.

A tabela a seguir ilustra a diferença entre os nomes de variáveis válidos e os inválidos.

Nomes de variáveis inválidos | Nomes de variáveis válidos -- | -- web server | web_server remote.file | remote_file 1st file | file_1 file1 remoteserver$1 | remote_server_1 remote_server1

Definição de variáveis

As variáveis podem ser definidas em uma variedade de lugares em um projeto do Ansible. No entanto, isso pode ser simplificado para três níveis básicos de escopo:

  • Escopo global: variáveis definidas na linha de comando ou na configuração Ansible

  • Escopo da ação: variáveis definidas nas estruturas da ação e relacionadas

  • Escopo do host: variáveis definidas em grupos de host e hosts individuais pelo inventário, por coleta de fatos ou tarefas registradas

Se o mesmo nome de variável estiver definido em mais de um nível, vencerá o de maior precedência. O escopo restrito tem precedência sobre o escopo maior: as variáveis definidas pelo inventário são substituídas pelas definidas pelo playbook, que, por sua vez, são substituídas pelas definidas na linha de comando.

Há uma discussão detalhada sobre a precedência das variáveis disponível na documentação do Ansible. O respectivo link é fornecido nas Referências ao fim deste artigo.

Variáveis em playbooks

As variáveis têm uma função importante nos playbooks do Ansible porque facilitam o gerenciamento de dados das variáveis em um playbook.

Definição de variáveis em playbooks

Ao escrever playbooks, você pode definir suas próprias variáveis e invocar esses valores em uma tarefa. Por exemplo, uma variável chamada web_package pode ser definida com o valor httpd. Em seguida, uma tarefa pode chamar a variável usando o módulo yum para instalar o pacote httpd.

As variáveis do playbook podem ser definidas de várias maneiras. Um método comum é colocar a variável em um bloco vars no início de um playbook:

- hosts: all
  vars:
    user: joe
    home: /home/joe

Também é possível definir as variáveis do playbook em arquivos externos. Nesse caso, em vez de usar o bloco vars no playbook, é possível utilizar a diretriz vars_files, seguida de uma lista de arquivos de variáveis externos relacionados ao local do playbook:

- hosts: all
  vars_files:
    - vars/users.yml

As variáveis do playbook são, então, definidas nesse arquivo ou nesses arquivos em formato YAML:

user: joe
home: /home/joe

Uso de variáveis em playbooks

Assim que as variáveis forem declaradas, os administradores poderão usá-las em tarefas. As variáveis são referenciadas colocando-se o nome da variável entre chaves duplas ({{}}). O Ansible substitui a variável pelo seu valor quando a tarefa é executada.

vars:
  user: joe
tasks:
  # This line will read: Creates the user joe
  - name: Creates the user {{ user }}
    user:
      # This line will create the user named Joe
      name: "{{ user }}"

Quando uma variável for usada como o primeiro elemento para iniciar um valor, as aspas serão obrigatórias. Isso impedirá que o Ansible interprete que a referência da variável está iniciando um dicionário YAML. Se as aspas estiverem ausentes, a seguinte mensagem será exibida:

yum:
     name: {{ service }}
            ^ here
We could be wrong, but this one looks like it might be an issue with
missing quotes.  Always quote template expression brackets when they
start a value. For instance:
    with_items:
      - {{ foo }}
Should be written as:
    with_items:
      - "{{ foo }}"

Variáveis de host e variáveis de grupo

As variáveis de inventário que se aplicam diretamente aos hosts se enquadram em duas categorias amplas: as variáveis de host se aplicam a um host específico; e as variáveis de grupo se aplicam a todos os hosts em um grupo de hosts ou em um grupo de grupos de hosts. As variáveis de host têm precedência sobre as de grupo, mas as variáveis definidas por um playbook têm precedência sobre ambas.

Uma forma de definir as variáveis de host e de grupo é fazer isso diretamente no arquivo de inventário. Essa é uma abordagem antiga e não é a preferencial, mas você ainda pode encontrá-la.

  • Definição da variável de host ansible_user para demo.example.com:

    [servers]
    demo.example.com  ansible_user=joe
  • Definição da variável de grupo user para o grupo de hosts servers.

    [servers]
    demo1.example.com
    demo2.example.com
    [servers:vars]
    user=joe
  • Definição da variável de grupo user para o grupo servers, que consiste em dois grupos de hosts, cada um com dois servidores.

    [servers1]
    demo1.example.com
    demo2.example.com
    [servers2]
    demo3.example.com
    demo4.example.com
    [servers:children]
    servers1
    servers2
    [servers:vars]
    user=joe

Algumas desvantagens dessa abordagem são: ela torna o arquivo de inventário mais difícil de trabalhar, ela mistura as informações sobre os hosts e as variáveis no mesmo arquivo e usa sintaxe obsoleta.

Uso de diretórios para preencher variáveis de host e grupo

A abordagem preferencial para definir variáveis de hosts e grupos de hosts é criar dois diretórios, group_vars e host_vars, no mesmo diretório de trabalho como o arquivo ou o diretório do inventário. Esses diretórios contêm arquivos que definem as variáveis de grupo e de host respectivamente.

A prática recomendada é definir as variáveis de inventário usando os diretórios host_vars e group_vars, e não as definir diretamente nos arquivos do inventário.

Para definir variáveis de grupo para o grupo servers, crie um arquivo YAML chamado group_vars/servers. O conteúdo desse arquivo definirá os valores das variáveis usando a mesma sintaxe de um playbook:

user: joe

Da mesma forma, para definir as variáveis de host para um host específico, crie um arquivo com o nome correspondente ao do host no diretório host_vars para conter as variáveis do host.

Os exemplos a seguir ilustram essa abordagem com mais detalhes. Imagine um cenário em que há dois data centers para gerenciar e os hosts do data center estão definidos no arquivo de inventário ~/project/inventory:

[admin@station project]$ cat ~/project/inventory
[datacenter1]
demo1.example.com
demo2.example.com
[datacenter2]
demo3.example.com
demo4.example.com
[datacenters:children]
datacenter1
datacenter2
  • Se você precisar definir um valor geral para todos os servidores nos dois data centers, estabeleça uma variável de grupo para o grupo de hosts datacenters:

    [admin@station project]$ cat ~/project/group_vars/datacenters
    package: httpd
  • Se o valor a ser definido variar para cada data center, estabeleça uma variável de grupo para cada grupo de hosts do data center:

    [admin@station project]$ cat ~/project/group_vars/datacenter1
    package: httpd
    [admin@station project]$ cat ~/project/group_vars/datacenter2
    package: apache
  • Se o valor a ser definido variar para cada host em cada data center, estabeleça as variáveis em arquivos de variáveis de host separados:

    [admin@station project]$ cat ~/project/host_vars/demo1.example.com
    package: httpd
    [admin@station project]$ cat ~/project/host_vars/demo2.example.com
    package: apache
    [admin@station project]$ cat ~/project/host_vars/demo3.example.com
    package: mariadb-server
    [admin@station project]$ cat ~/project/host_vars/demo4.example.com
    package: mysql-server

A estrutura do diretório para o projeto de exemplo, project, se contiver todos os arquivos de exemplo acima, aparecerá da seguinte forma:

project
├── ansible.cfg
├── group_vars
│   ├── datacenters
│   ├── datacenters1
│   └── datacenters2
├── host_vars
│   ├── demo1.example.com
│   ├── demo2.example.com
│   ├── demo3.example.com
│   └── demo4.example.com
├── inventory
└── playbook.yml

Substituição de variáveis da linha de comando

As variáveis de inventário são substituídas pelas definidas em um playbook, mas ambos os tipos de variáveis podem ser substituídos por argumentos passados para os comandos ansible ou ansible-playbook na linha de comando. As variáveis definidas na linha de comando são consideradas variáveis extras.

As variáveis extras podem ser úteis quando você precisa substituir o valor definido para uma variável por uma execução única de um playbook. Por exemplo:

[user@demo ~]$ ansible-playbook main.yml -e "package=apache"

Uso de matrizes como variáveis

Em vez de atribuir os dados de configuração que estão relacionados ao mesmo elemento (uma lista de pacotes, uma de serviços, uma de usuários e assim por diante) a muitas variáveis, os administradores podem usar matrizes. Uma consequência disso é que uma matriz pode ser buscada.

Por exemplo, considere o seguinte trecho:

user1_first_name: Bob
user1_last_name: Jones
user1_home_dir: /users/bjones
user2_first_name: Anne
user2_last_name: Cook
user2_home_dir: /users/acook

Isso pode ser reescrito como uma matriz chamada users:

users:
  bjones:
    first_name: Bob
    last_name: Jones
    home_dir: /users/bjones
  acook:
    first_name: Anne
    last_name: Cook
    home_dir: /users/acook

Então, você pode usar as seguintes variáveis para acessar os dados do usuário:

# Returns 'Bob'
users.bjones.first_name
# Returns '/users/acook'
users.acook.home_dir

Como a variável é definida como um dicionário do Python, uma sintaxe alternativa está disponível.

# Returns 'Bob'
users['bjones']['first_name']
# Returns '/users/acook'
users['acook']['home_dir']

A notação de ponto poderá causar problemas se os nomes das chaves forem os mesmos dos métodos ou dos atributos do Python, como discard, copy, add e assim por diante. Usar a notação de colchetes pode ajudar a evitar conflitos e erros.

As duas sintaxes são válidas, mas, para facilitar a solução de problemas, a RedHat recomenda usar uma sintaxe consistentemente em todos os arquivos em qualquer projeto do Ansible.

Captura da saída de comando com variáveis registradas

Os administradores podem usar a instrução register para capturar a saída de um comando. A saída é salva em uma variável temporária que poderá ser usada posteriormente no playbook para depuração ou para outros fins, como uma configuração específica com base na saída de um comando.

O seguinte playbook demonstra como capturar a saída de um comando para fins de depuração:

---
- name: Installs a package and prints the result
  hosts: all
  tasks:
    - name: Install the package
      yum:
        name: httpd
        state: installed
      register: install_result
    - debug: var=install_result

Quando você executa o playbook, o módulo debug é usado para despejar o valor da variável registrada, install_result, no terminal.

[user@demo ~]$ ansible-playbook playbook.yml
PLAY [Installs a package and prints the result] ****************************
TASK [setup] ***************************************************************
ok: [demo.example.com]
TASK [Install the package] *************************************************
ok: [demo.example.com]
TASK [debug] ***************************************************************
ok: [demo.example.com] => {
    "install_result": {
        "changed": false,
        "msg": "",
        "rc": 0,
        "results": [
            "httpd-2.4.6-40.el7.x86_64 providing httpd is already installed"
        ]
    }
}
PLAY RECAP *****************************************************************
demo.example.com    : ok=3    changed=0    unreachable=0    failed=0
britho commented 3 years ago

Neste exercício, você definirá e usará variáveis em um playbook.

Resultados

Você deverá ser capaz de:

  • Definir variáveis em um playbook.

  • Criar tarefas que usem as variáveis definidas.

Faça login na workstation como student usando a senha student.

Na workstation, execute o comando lab data-variables start. Essa função cria o diretório de trabalho data-variables e o preenche com um arquivo de configuração e um inventário de host do Ansible.

[student@workstation ~]$ lab data-variables start
  1. Em workstation, com o usuário student, acesse o diretório /home/student/data-variables.

    [student@workstation ~]$ cd ~/data-variables
  2. Nas próximas várias etapas, você criará um playbook que instalará o servidor Web da Apache e abrirá as portas para que o serviço seja acessível. O playbook consulta o servidor web para garantir que esteja funcionando corretamente.

    Crie o playbook playbook.yml e defina as seguintes variáveis na seção vars:

    Variável | Descrição -- | -- web_pkg | Pacote do servidor web a instalar. firewall_pkg | Pacote de firewall a instalar. web_service | Serviço Web a gerenciar. firewall_service | Serviço de firewall a gerenciar. python_pkg | Pacote necessário para o módulo uri. rule | O nome do serviço a ser aberto.

    ---
    - name: Deploy and start Apache HTTPD service
      hosts: webserver
      vars:
        web_pkg: httpd
        firewall_pkg: firewalld
        web_service: httpd
        firewall_service: firewalld
        python_pkg: python3-PyMySQL
        rule: http
  3. Crie o bloco tasks e a primeira tarefa que usará o módulo yum para garantir que as versões mais recentes dos pacotes necessários estejam instaladas.

      tasks:
        - name: Required packages are installed and up to date
          yum:
            name:
              - "{{ web_pkg }}"
              - "{{ firewall_pkg }}"
              - "{{ python_pkg }}"
            state: latest

    Você pode usar ansible-doc yum para revisar a sintaxe do módulo yum. A sintaxe mostra que sua diretiva name pode selecionar uma lista de pacotes com os quais o módulo deve funcionar para que você não precise separar tarefas para garantir que todos os pacotes estejam atualizados.

  4. Crie duas tarefas para garantir que os serviços httpd e firewalld foram iniciados e habilitados.

        - name: The {{ firewall_service }} service is started and enabled
          service:
            name: "{{ firewall_service }}"
            enabled: true
            state: started
        - name: The {{ web_service }} service is started and enabled
          service:
            name: "{{ web_service }}"
            enabled: true
            state: started

    O módulo service funciona de modo diferente do módulo yum, como documentado por ansible-doc service. A diretiva name usa o nome de exatamente um serviço para trabalhar com ele.

    Você pode escrever uma tarefa única que garanta que os dois serviços sejam iniciados e ativados, usando a palavra-chave loop explicada posteriormente neste curso.

  5. Adicione uma tarefa que garanta que um conteúdo específico exista no arquivo /var/www/html/index.html.

        - name: Web content is in place
          copy:
            content: "Example web content"
            dest: /var/www/html/index.html
  6. Adicione uma tarefa que use o módulo firewalld para garantir que as portas do firewall estejam abertas para o serviço firewalld chamado na variável rule.

        - name: The firewall port for {{ rule }} is open
          firewalld:
            service: "{{ rule }}"
            permanent: true
            immediate: true
            state: enabled
  7. Crie uma nova ação que consulte o serviço Web para garantir que tudo tenha sido configurado corretamente. Deve ser executado em localhost. Por causa desse fato do Ansible, o Ansible não precisa alterar a identidade, então defina o módulo become como false. Você pode usar o módulo uri para verificar uma URL. Para esta tarefa, procure um código de status de 200 para confirmar que o servidor web em servera.lab.example.com está em execução e foi configurado corretamente.

    - name: Verify the Apache service
      hosts: localhost
      become: false
      tasks:
        - name: Ensure the webserver is reachable
          uri:
            url: http://servera.lab.example.com
            status_code: 200
  8. Quando completo, o playbook deverá ficar da forma a seguir. Analise o playbook e confirme que as ações estão corretas.

    ---
    - name: Deploy and start Apache HTTPD service
      hosts: webserver
      vars:
        web_pkg: httpd
        firewall_pkg: firewalld
        web_service: httpd
        firewall_service: firewalld
        python_pkg: python3-PyMySQL
        rule: http
      tasks:
        - name: Required packages are installed and up to date
          yum:
            name:
              - "{{ web_pkg  }}"
              - "{{ firewall_pkg }}"
              - "{{ python_pkg }}"
            state: latest
        - name: The {{ firewall_service }} service is started and enabled
          service:
            name: "{{ firewall_service }}"
            enabled: true
            state: started
        - name: The {{ web_service }} service is started and enabled
          service:
            name: "{{ web_service }}"
            enabled: true
            state: started
        - name: Web content is in place
          copy:
            content: "Example web content"
            dest: /var/www/html/index.html
        - name: The firewall port for {{ rule }} is open
          firewalld:
            service: "{{ rule }}"
            permanent: true
            immediate: true
            state: enabled
    - name: Verify the Apache service
      hosts: localhost
      become: false
      tasks:
        - name: Ensure the webserver is reachable
          uri:
            url: http://servera.lab.example.com
            status_code: 200
  9. Antes de executar o playbook, use o comando ansible-playbook --syntax-check para verificar sua sintaxe. Se ela relatar algum erro, corrija-o antes de ir para a próxima etapa. Você verá uma saída semelhante à seguinte:

    [student@workstation data-variables]$ ansible-playbook --syntax-check playbook.yml
    playbook: playbook.yml
  10. Use o comando ansible-playbook para executar o playbook. Observe a saída enquanto o Ansible instala os pacotes, inicializa e ativa os serviços e garante que o servidor Web esteja acessível.

    [student@workstation data-variables]$ ansible-playbook playbook.yml
    PLAY [Deploy and start Apache HTTPD service] ***********************************
    TASK [Gathering Facts] *********************************************************
    ok: [servera.lab.example.com]
    TASK [Required packages are installed and up to date] **************************
    changed: [servera.lab.example.com]
    TASK [The firewalld service is started and enabled] ****************************
    ok: [servera.lab.example.com]
    TASK [The httpd service is started and enabled] ********************************
    changed: [servera.lab.example.com]
    TASK [Web content is in place] *************************************************
    changed: [servera.lab.example.com]
    TASK [The firewall port for http is open] **************************************
    changed: [servera.lab.example.com]
    PLAY [Verify the Apache service] ***********************************************
    TASK [Gathering Facts] *********************************************************
    ok: [localhost]
    TASK [Ensure the webserver is reachable] ***************************************
    ok: [localhost]
    PLAY RECAP *********************************************************************
    localhost                  : ok=2    changed=0    unreachable=0    failed=0
    servera.lab.example.com    : ok=6    changed=4    unreachable=0    failed=0

Encerramento

Na workstation, execute o script lab data-variables finish para limpar este exercício.

[student@workstation ~]$ lab data-variables finish

Isso conclui o exercício orientado.

britho commented 3 years ago

Objetivos

Depois de concluir esta seção, você deverá ser capaz de criptografar variáveis confidenciais usando o Ansible Vault e executar os playbooks que fazem referência aos arquivos com variáveis criptografadas pelo Vault. Introdução ao Ansible Vault

O Ansible pode precisar de acesso a dados confidenciais, como senhas ou chaves de API, para configurar os hosts gerenciados. Normalmente, essas informações podem ser armazenadas em texto simples nas variáveis de inventário ou em outros arquivos do Ansible. No entanto, nesse caso, qualquer usuário com acesso aos arquivos do Ansible ou um sistema de controle de versão que armazena arquivos do Ansible pode acessar esses dados confidenciais. Isso apresenta um risco óbvio à segurança.

O Ansible Vault, que está incluído no Ansible, pode ser usado para criptografar ou descriptografar qualquer arquivo de dados estruturados usado pelo Ansible. Para usar o Ansible Vault, uma ferramenta de linha de comando denominada ansible-vault é usada para criar, editar, criptografar, descriptografar e visualizar arquivos. O Ansible Vault pode criptografas qualquer arquivo de dados estruturados usado pelo Ansible. Isso inclui variáveis de inventário, arquivos de variáveis de um playbook, arquivos de variáveis aprovados como argumentos quando o playbook é executado ou variáveis definidas nas funções do Ansible.

O Ansible Vault não implementa suas próprias funções criptográficas, mas usa um conjunto de ferramentas externo do Python. Os arquivos são protegidos com criptografia simétrica usando AES256 com uma senha como a chave secreta. O modo como isso é feito não foi auditado por um terceiro.

Criação de um arquivo criptografado

Para criar um novo arquivo criptografado, use o comando ansible-vault create filename. O comando solicita a nova senha do Vault e abre um arquivo usando o editor padrão, vi. Você pode definir e exportar a variável de ambiente EDITOR para especificar um editor padrão diferente por meio da definição e exportação. Por exemplo, para definir o editor padrão como nano, export EDITOR=nano.

[student@demo ~]$ ansible-vault create secret.yml New Vault password: redhat Confirm New Vault password: redhat

Em vez de inserir a senha do Vault por entrada padrão, você pode usar um arquivo de senha do Vault para armazenar a senha. Proteja esse arquivo usando permissões de arquivo e outros meios.

[student@demo ~]$ ansible-vault create --vault-password-file=vault-pass secret.yml

A cifra usada para proteger arquivos é AES256 em versões recentes do Ansible, mas os arquivos criptografados com versões anteriores podem ainda usar AES de 128 bits.

Exibição de um arquivo criptografado

Você pode usar o comando ansible-vault view filename para visualizar o arquivo criptografado pelo Ansible Vault sem abri-lo para edição.

[student@demo ~]$ ansible-vault view secret1.yml Vault password: secret less 458 (POSIX regular expressions) Copyright (C) 1984-2012 Mark Nudelman

less comes with NO WARRANTY, to the extent permitted by law. For information about the terms of redistribution, see the file named README in the less distribution. Homepage: http://www.greenwoodsoftware.com/less my_secret: "yJJvPqhsiusmmPPZdnjndkdnYNDjdj782meUZcw"

Edição de um arquivo criptografado existente

Para editar um arquivo criptografado existente, o Ansible Vault fornece o comando ansible-vault edit filename. Esse comando descriptografa o arquivo em um arquivo temporário e permite a edição. Quando salvo, ele copia o conteúdo e remove o arquivo temporário.

[student@demo ~]$ ansible-vault edit secret.yml Vault password: redhat

O subcomando edit sempre grava o arquivo novamente, por isso deve ser usado somente ao fazer alterações. Isso pode ter implicações quando o arquivo é mantido sob controle de versão. Sempre use o subcomando view para exibir o conteúdo do arquivo sem fazer alterações.

Criptografia de um arquivo existente

Para criptografar um arquivo existente, use o comando ansible-vault encrypt filename. Esse comando pode usar o nome de vários arquivos para que sejam criptografados como argumentos.

[student@demo ~]$ ansible-vault encrypt secret1.yml secret2.yml New Vault password: redhat Confirm New Vault password: redhat Encryption successful

Use a opção --output=OUTPUT_FILE para salvar o arquivo criptografado com um novo nome. Você só pode usar um arquivo de entrada com a opção --output.

Descriptografia de um arquivo existente

Um arquivo criptografado existente pode ser permanentemente descriptografado usando o comando ansible-vault decrypt filename. Quando você descriptografar um único arquivo, a opção --output pode ser usada para salvar o arquivo descriptografado com um nome diferente.

[student@demo ~]$ ansible-vault decrypt secret1.yml --output=secret1-decrypted.yml Vault password: redhat Decryption successful

Alteração da senha de um arquivo criptografado

Você pode usar o comando ansible-vault rekey filename para alterar a senha de um arquivo criptografado. Esse comando pode realizar o rechaveamento em vários arquivos de dados de uma só vez. Ele pede a senha original e a nova senha.

[student@demo ~]$ ansible-vault rekey secret.yml Vault password: redhat New Vault password: RedHat Confirm New Vault password: RedHat Rekey successful

Ao usar um arquivo de senha do Vault, escolha a opção --new-vault-password-file:

[student@demo ~]$ ansible-vault rekey \

--new-vault-password-file=NEW_VAULT_PASSWORD_FILE secret.yml

Playbooks e o Ansible Vault

Para executar um playbook que acesse arquivos criptografados com o Ansible Vault, você precisa fornecer a senha de criptografia ao comando ansible-playbook. Se você não fornecer a senha, o playbook retornará um erro:

[student@demo ~]$ ansible-playbook site.yml ERROR: A vault password must be specified to decrypt vars/api_key.yml

Para fornecer a senha do Vault para o playbook, use a opção --vault-id. Por exemplo, para fornecer a senha do Vault de forma interativa, use --vault-id @prompt conforme ilustrado neste exemplo:

[student@demo ~]$ ansible-playbook --vault-id @prompt site.yml Vault password (default): redhat

Se você estiver usando uma versão do Ansible anterior à versão2.4, precisará usar a opção --ask-vault-pass para fornecer a senha do Vault de forma interativa. Também poderá usar essa opção se todos os arquivos criptografados pelo Vault e usados pelo playbook tiverem sido criptografados com a mesma senha.

[student@demo ~]$ ansible-playbook --ask-vault-pass site.yml Vault password: redhat

Como alternativa, você pode usar a opção --vault-password-file para especificar um arquivo que armazene a senha de criptografia em texto simples. A senha deve ser uma string armazenada como uma só linha no arquivo. Como o arquivo contém a senha confidencial de texto simples, é vital que ele esteja protegido por permissões de arquivo e outras medidas de segurança.

[student@demo ~]$ ansible-playbook --vault-password-file=vault-pw-file site.yml

Você também pode usar a variável de ambiente ANSIBLE_VAULT_PASSWORD_FILE para especificar o local padrão do arquivo de senha.

A partir do Ansible2.4, você pode usar várias senhas do Ansible Vault com ansible-playbook. Para usar várias senhas, aprove várias opções --vault-id ou --vault-password-file para o comando ansible-playbook.

[student@demo ~]$ ansible-playbook \

--vault-id one@prompt --vault-id two@prompt site.yml Vault password (one): Vault password (two): ...output omitted...

As IDs do Vault one e two que precedem @prompt podem ser qualquer coisa, e você pode até omiti-las completamente. No entanto, se você usar a opção --vault-id id ao criptografar um arquivo com o comando ansible-vault, quando executar ansible-playbook, a senha da ID correspondente será usada antes de qualquer outra. Se ela não corresponder, as outras senhas fornecidas serão tentadas em seguida. A ID do Vault @prompt sem ID é, na verdade, uma abreviação de default@prompt, o que significa solicitar a senha da ID do Vault default.

Práticas recomendadas para o gerenciamento de arquivos de variáveis

Para simplificar o gerenciamento, é sensato configurar o projeto do Ansible para que as variáveis confidenciais e todas as demais variáveis sejam mantidas em arquivos separados. Os arquivos que contêm variáveis confidenciais podem ser protegidos com o comando ansible-vault.

Lembre-se de que a forma preferencial de gerenciar variáveis de grupos e variáveis de host é criando diretórios no playbook. O diretório group_vars normalmente consiste em vários arquivos de variáveis com nomes que correspondem aos grupos de host aos quais se aplicam. O diretório host_vars normalmente consiste em vários arquivos de variáveis com nomes que correspondem aos nomes dos hosts gerenciados aos quais se aplicam.

Entretanto, em vez de usar os arquivos em group_vars ou host_vars, você também pode utilizar os diretórios para cada grupo de hosts ou host gerenciado. Esses diretórios podem conter diversos arquivos de variáveis, e todos são utilizados pelo grupo de host ou host gerenciado. Por exemplo, neste diretório de projeto para playbook.yml, os membros do grupo de hosts webservers usam variáveis do arquivo group_vars/webservers/vars, e demo.example.com usa variáveis tanto de host_vars/demo.example.com/vars quanto de host_vars/demo.example.com/vault:

. ├── ansible.cfg ├── group_vars │ └── webservers │ └── vars ├── host_vars │ └── demo.example.com │ ├── vars │ └── vault ├── inventory └── playbook.yml

Nesse cenário, a vantagem é que a maioria das variáveis de demo.example.com pode ser colocada no arquivo vars, mas as variáveis confidenciais podem ser mantidas em segredo ao colocá-las separadamente no arquivo vault. Assim, o administrador pode usar ansible-vault para criptografar o arquivo vault e deixar o arquivo vars como texto simples.

Não há nada de especial quanto aos nomes de arquivo usados nesse exemplo dentro do diretório host_vars/demo.example.com. O diretório poderia conter mais arquivos, alguns criptografados pelo Ansible Vault e outros não.

As variáveis de playbook (ao contrário das variáveis de inventário) também podem ser protegidas com o Ansible Vault. As variáveis confidenciais do playbook também podem ser colocadas em um arquivo separado criptografado pelo Ansible Vault e incluídas no playbook por meio de uma diretiva vars_files. Isso pode ser útil, já que as variáveis de playbook têm precedência sobre as variáveis de inventário.

Se você estiver usando várias senhas do Vault com seu playbook, verifique se cada arquivo criptografado recebeu uma ID do Vault. Insira a senha correspondente à ID do Vault ao executar o playbook. Isso garante que a senha correta seja selecionada primeiro ao descriptografar o arquivo criptografado pelo Vault, o que é mais rápido do que forçar o Ansible a testar todas as senhas do Vault que você forneceu até encontrar a senha certa.

Páginas do man ansible-playbook(1) e ansible-vault(1)

Vault — Ansible Documentation

Variables and Vaults — Ansible Documentation

britho commented 3 years ago

Neste exercício, você criptografará variáveis confidenciais com o Ansible Vault para protegê-las e, em seguida, executará um playbook que use essas variáveis.

Resultados

Você deverá ser capaz de:

Executar um playbook usando variáveis definidas em um arquivo criptografado. 

Faça login na workstation como student usando a senha student.

Na workstation, execute o comando lab data-secret start. Esse script garante que o Ansible está instalado na workstation e cria um diretório de trabalho para este exercício. O diretório inclui um arquivo de inventário que aponta para o servera.lab.example.com como um host gerenciado que faz parte do grupo devservers.

[student@workstation ~]$ lab data-secret start

Na workstation, como usuário student, mude para o diretório de trabalho /home/student/data-secret.

[student@workstation ~]$ cd ~/data-secret

Edite o conteúdo do arquivo criptografado fornecido, secret.yml. O arquivo pode ser descriptografado usando a senha redhat. Remova o comentário das entradas das variáveis username e pwhash.

    Edite o arquivo criptografado /home/student/data-secret/secret.yml. Forneça a senha redhat para o Vault quando solicitado. O arquivo criptografado é aberto no editor padrão, vim.

    [student@workstation data-secret]$ ansible-vault edit secret.yml
    Vault password: redhat

    Remova o comentário das duas entradas de variáveis, salve o arquivo e saia do editor. Elas devem aparecer da seguinte maneira:

    username: ansibleuser1
    pwhash: $6$jf...uxhP1

Crie um playbook chamado /home/student/data-secret/create_users.yml que use as variáveis definidas no arquivo criptografado /home/student/data-secret/secret.yml.

Configure o playbook para usar o grupo de hosts devservers. Execute esse playbook com o usuário devops no host gerenciado remoto. Configure o playbook para criar o usuário ansibleuser1 definido pela variável username. Defina a senha do usuário usando o hash de senha armazenado na variável pwhash.

---
- name: create user accounts for all our servers
  hosts: devservers
  become: True
  remote_user: devops
  vars_files:
    - secret.yml
  tasks:
    - name: Creating user from secret.yml
      user:
        name: "{{ username }}"
        password: "{{ pwhash }}"

Use o comando ansible-playbook --syntax-check para verificar a sintaxe do playbook create_users.yml. Use a opção --ask-vault-pass para solicitar a senha do Vault que descriptografa o secret.yml. Resolva os erros de sintaxe antes de continuar.

[student@workstation data-secret]$ ansible-playbook --syntax-check \
> --ask-vault-pass create_users.yml
Vault password (default): redhat

playbook: create_users.yml

Em vez de usar --ask-vault-pass, escolha a nova opção --vault-id @prompt para fazer a mesma coisa.

Em vez de pedir uma senha, crie um arquivo de senha chamado vault-pass para usar com a execução do playbook. O arquivo deve conter o texto simples redhat como a senha do vault. Altere as permissões do arquivo para 0600.

[student@workstation data-secret]$ echo 'redhat' > vault-pass
[student@workstation data-secret]$ chmod 0600 vault-pass

Execute o playbook do Ansible usando o arquivo vault-pass, para criar o usuário ansibleuser1 em um sistema remoto, e usando as senhas armazenadas como variáveis no arquivo criptografado secret.yml do Ansible Vault.

[student@workstation data-secret]$ ansible-playbook \
> --vault-password-file=vault-pass create_users.yml

PLAY [create user accounts for all our servers] ********************************

TASK [Gathering Facts] *********************************************************
ok: [servera.lab.example.com]

TASK [Creating users from secret.yml] ******************************************
changed: [servera.lab.example.com]

PLAY RECAP *********************************************************************
servera.lab.example.com    : ok=2    changed=1    unreachable=0    failed=0

Verifique se o playbook foi executado corretamente. O usuário ansibleuser1 deve existir e ter a senha correta em servera.lab.example.com. Teste isso usando ssh para fazer login com esse usuário em servera.lab.example.com. A senha para ansibleuser1 é redhat. Para ter certeza de que o SSH apenas tentará fazer a autenticação por senha e não por uma chave SSH, use a opção -o PreferredAuthentications=password ao fazer login.

Faça logoff do servera quando você tiver feito login com êxito.

[student@workstation data-secret]$ ssh -o PreferredAuthentications=password \
> ansibleuser1@servera.lab.example.com
ansibleuser1@servera.lab.example.com's password: redhat
Activate the web console with: systemctl enable --now cockpit.socket

[ansibleuser1@servera ~]$ exit
logout
Connection to servera.lab.example.com closed.

Encerramento

Na workstation, execute o script lab data-secret finish para limpar este exercício.

[student@workstation ~]$ lab data-secret finish

Isso conclui o exercício orientado.

britho commented 3 years ago

Objetivos

Depois de concluir esta seção, você deverá ser capaz de fazer referência a dados sobre hosts gerenciados usando fatos do Ansible e configurar fatos personalizados em hosts gerenciados.

Descrição de fatos do Ansible

Os fatos do Ansible são variáveis que são automaticamente descobertas pelo Ansible em um host gerenciado. Fatos contendo informações específicas de host que podem ser usados como variáveis comuns em ações, condicionais, loops ou qualquer outra declaração que depende de um valor coletado de um host gerenciado.

Entre os fatos coletados para um host gerenciado, estão:

  • O nome do host

  • A versão do kernel

  • As interfaces de rede

  • Os endereços IP

  • A versão do sistema operacional

  • Diversas variáveis de ambiente

  • O número de CPUs

  • A memória disponível ou livre

  • O espaço em disco disponível

Os fatos são uma maneira conveniente de recuperar o estado de um host gerenciado e determinar que ação tomar com base nesse estado. Por exemplo:

  • Um servidor pode ser reiniciado por uma tarefa condicional executada com base em um fato que contém a versão atual de kernel do host gerenciado.

  • O arquivo de configuração do MySQL pode ser personalizado dependendo da memória disponível relatada por um fato.

  • O endereço IPv4 usado em um arquivo de configuração pode ser baseado no valor de um fato.

Normalmente, todas as ações executam o módulo setup automaticamente antes da primeira tarefa para coletar fatos. Isso é relatado como a tarefa Gathering Facts no Ansible2.3 e posterior ou, simplesmente, como setup nas versões mais antigas do Ansible. Por padrão, você não precisa ter uma tarefa para executar setup em sua ação. Normalmente, o comando é executado automaticamente para você.

Uma maneira de ver quais fatos são coletados para seus hosts gerenciados é executar um pequeno playbook que reúna fatos e use o módulo debug para imprimir o valor da variável ansible_facts.

- name: Fact dump
  hosts: all
  tasks:
    - name: Print all facts
      debug:
        var: ansible_facts

Quando você executa o playbook, os fatos são exibidos na saída do trabalho:

[user@demo ~]$ ansible-playbook facts.yml
PLAY [Fact dump] ***************************************************************
TASK [Gathering Facts] *********************************************************
ok: [demo1.example.com]
TASK [Print all facts] *********************************************************
ok: [demo1.example.com] => {
    "ansible_facts": {
        "all_ipv4_addresses": [
            "172.25.250.10"
        ],
        "all_ipv6_addresses": [
           "fe80::5054:ff:fe00:fa0a"
        ],
        "ansible_local": {},
        "apparmor": {
            "status": "disabled"
        },
        "architecture": "x86_64",
        "bios_date": "01/01/2011",
        "bios_version": "0.5.1",
        "cmdline": {
            "BOOT_IMAGE": "/boot/vmlinuz-3.10.0-327.el7.x86_64",
            "LANG": "en_US.UTF-8",
            "console": "ttyS0,115200n8",
            "crashkernel": "auto",
            "net.ifnames": "0",
            "no_timer_check": true,
            "ro": true,
            "root": "UUID=2460ab6e-e869-4011-acae-31b2e8c05a3b"
        },
...output omitted...

O playbook exibe o conteúdo da variável ansible_facts no formato JSON como um hash/dicionário de variáveis. Você pode navegar na saída para ver quais fatos são coletados, para descobrir quais fatos gostaria de usar nas suas ações.

A tabela a seguir mostra alguns dos fatos que podem ser reunidos de um nó gerenciado e que podem ser úteis em um playbook:

Fato | Variável -- | -- Nome do host curto | ansible_facts['hostname'] Fully qualified domain name | ansible_facts['fqdn'] Endereço IPv4 principal (baseado em roteamento) | ansible_facts['default_ipv4']['address'] Lista de nomes de todas as interfaces de rede | ansible_facts['interfaces'] Tamanho da partição de disco /dev/vda1 | ansible_facts['devices']['vda']['partitions']['vda1']['size'] Lista de servidores DNS | ansible_facts['dns']['nameservers'] Versão do kernel em execução | ansible_facts['kernel']

Quando o valor de uma variável é um hash/dicionário, há duas sintaxes que podem ser usadas para recuperar o valor. Estes são dois exemplos da tabela anterior:

  • ansible_facts['default_ipv4']['address'] também pode ser escrito como ansible_facts.default_ipv4.address

  • ansible_facts['dns']['nameservers'] também pode ser escrito como ansible_facts.dns.nameservers

Quando um fato é usado em um playbook, o Ansible substitui dinamicamente o nome da variável para o fato pelo valor correspondente:

---
- hosts: all
  tasks:
  - name: Prints various Ansible facts
    debug:
      msg: >
        The default IPv4 address of {{ ansible_facts.fqdn }}
        is {{ ansible_facts.default_ipv4.address }}

A saída a seguir mostra como o Ansible conseguiu consultar o nó gerenciado e usar a informação do sistema dinamicamente para atualizar a variável. Os fatos também podem ser usados para criar grupos dinâmicos de hosts que correspondam a critérios específicos.

[user@demo ~]$ ansible-playbook playbook.yml
PLAY ***********************************************************************
TASK [Gathering Facts] *****************************************************
ok: [demo1.example.com]
TASK [Prints various Ansible facts] ****************************************
ok: [demo1.example.com] => {
    "msg": "The default IPv4 address of demo1.example.com is
            172.25.250.10"
}
PLAY RECAP *****************************************************************
demo1.example.com    : ok=2    changed=0    unreachable=0    failed=0

Fatos do Ansible inseridos como variáveis

Antes do Ansible2.5, os fatos eram inseridos como variáveis individuais com o prefixo ansible_ em vez de fazer parte da variável ansible_facts. Por exemplo, o fato ansible_facts['distribution'] teria sido chamado de ansible_distribution.

Muitos playbooks mais antigos ainda usam fatos inseridos como variáveis, em vez da nova sintaxe com namespace na variável ansible_facts. Você pode usar um comando ad hoc para executar o módulo setup a fim de imprimir o valor de todos os fatos desse formulário. No exemplo a seguir, um comando ad hoc é usado para executar o módulo setup no host gerenciado demo1.example.com:

[user@demo ~]$ ansible demo1.example.com -m setup
demo1.example.com | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "172.25.250.10"
        ],
        "ansible_all_ipv6_addresses": [
            "fe80::5054:ff:fe00:fa0a"
        ],
        "ansible_apparmor": {
            "status": "disabled"
        },
        "ansible_architecture": "x86_64",
        "ansible_bios_date": "01/01/2011",
        "ansible_bios_version": "0.5.1",
        "ansible_cmdline": {
            "BOOT_IMAGE": "/boot/vmlinuz-3.10.0-327.el7.x86_64",
            "LANG": "en_US.UTF-8",
            "console": "ttyS0,115200n8",
            "crashkernel": "auto",
            "net.ifnames": "0",
            "no_timer_check": true,
            "ro": true,
            "root": "UUID=2460ab6e-e869-4011-acae-31b2e8c05a3b"
        }
...output omitted...

A tabela a seguir compara os nomes de fatos antigos e novos.

Formulário ansible_facts | Formulário de variáveis de fatos antigos -- | -- ansible_facts['hostname'] | ansible_hostname ansible_facts['fqdn'] | ansible_fqdn ansible_facts['default_ipv4']['address'] | ansible_default_ipv4['address'] ansible_facts['interfaces'] | ansible_interfaces ansible_facts['devices']['vda']['partitions']['vda1']['size'] | ansible_devices['vda']['partitions']['vda1']['size'] ansible_facts['dns']['nameservers'] | ansible_dns['nameservers'] ansible_facts['kernel'] | ansible_kernel

Atualmente, o Ansible reconhece tanto o novo sistema de nomenclatura de fatos (que usam ansible_facts) e o sistema de nomenclatura antigo, anterior à versão 2.5, com fatos inseridos como variáveis separadas.

Você pode desativar o sistema de nomes antigo definindo o parâmetro inject_facts_as_vars na seção [default] do arquivo de configuração do Ansible como false. No momento, a configuração padrão é true.

O valor padrão de inject_facts_as_vars provavelmente mudará para false em uma versão futura do Ansible. Se estiver configurado como false, você só poderá fazer referência a fatos do Ansible usando o novo sistema de nomenclatura ansible_facts.*. Nesse caso, as tentativas de fazer referência a fatos por meio do namespace antigo resulta no seguinte erro:

...output omitted...
TASK [Show me the facts] *************************************************
fatal: [demo.example.com]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'ansible_distribution' is undefined\n\nThe error appears to have been in
 '/home/student/demo/playbook.yml': line 5, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n  tasks:\n    - name: Show me the facts\n      ^ here\n"}
...output omitted...

Desligamento da coleta de fatos

Algumas vezes, você pode não querer coletar fatos para sua ação. Há alguns motivos por que isso pode acontecer. Pode ser que você não esteja usando fatos e queira agilizar a ação e reduzir a carga causada pela ação nos hosts gerenciados. Pode ser que os hosts gerenciados não possam executar o módulo setup por algum motivo ou precisem instalar um software de pré-requisito antes de coletar dados.

Para desativar a coleta de fatos em uma ação, defina a palavra-chave gather_facts como no:

---
- name: This play gathers no facts automatically
  hosts: large_farm
  gather_facts: no

Mesmo se gather_facts: no estiver definido para uma ação, você poderá coletar manualmente fatos a qualquer momento, executando uma tarefa que use o módulo setup:

  tasks:
    - name: Manually gather facts
      setup:
...output omitted...

Criação de fatos personalizados

Os administradores podem criar fatos personalizados, que são armazenados localmente em cada host gerenciado. Esses fatos são integrados à lista de fatos padrão coletados pelo módulo setup quando é executado no host gerenciado. Eles permitem que o host gerenciado forneça variáveis ao Ansible, o que pode ser usado para ajustar o comportamento das ações.

Fatos personalizados podem ser definidos em um arquivo estático, formatado como um arquivo INI ou usando JSON. Eles também podem ser scripts executáveis que geram saída JSON, assim como um script de inventário dinâmico.

Os fatos personalizados permitem aos administradores definir certos valores para hosts gerenciados que as ações podem usar para preencher arquivos de configuração ou executar tarefas condicionalmente. Os fatos personalizados dinâmicos permitem que os valores desses fatos ou, até mesmo, quais fatos são fornecidos, sejam determinados programaticamente quando a ação é executada.

Por padrão, o módulo setup carrega fatos personalizados de arquivos e scripts no diretório /etc/ansible/facts.d de cada host gerenciado. O nome de todos os arquivos ou scripts deve terminar em .fact para ser usado. Os scripts de fatos personalizados dinâmicos devem gerar como saída fatos formatados em JSON e devem ser executáveis.

Este é um exemplo de um arquivo de fatos personalizados estáticos gravados no formato INI. Um arquivo de fatos personalizados formatos em INI contém um nível superior definido por uma seção, seguido pelos pares de chave-valor dos fatos a serem definidos:

[packages]
web_package = httpd
db_package = mariadb-server
[users]
user1 = joe
user2 = jane

Os mesmos fatos podem ser fornecidos no formato JSON. Os fatos JSON a seguir são equivalentes aos fatos especificados pelo formato INI no exemplo anterior. Os dados JSON podem ser armazenados em um arquivo de texto estático ou impressos em saída padrão por um script executável:

{
  "packages": {
    "web_package": "httpd",
    "db_package": "mariadb-server"
  },
  "users": {
    "user1": "joe",
    "user2": "jane"
  }
}

Os arquivos de fatos personalizados não podem estar no formato YAML como um playbook. O formato JSON é o equivalente mais próximo.

Os fatos personalizados são armazenados pelo módulo setup na variável ansible_facts.ansible_local. Os fatos são organizados com base no nome do arquivo que os definiu. Por exemplo, digamos que os fatos personalizados anteriores produziram um arquivo salvo como /etc/ansible/facts.d/custom.fact no host gerenciado. Nesse caso, o valor de ansible_facts.ansible_local['custom']['users']['user1'] é joe.

Você pode inspecionar a estrutura dos seus fatos personalizados executando o módulo setup nos hosts gerenciados com um comando ad hoc.

[user@demo ~]$ ansible demo1.example.com -m setup
demo1.example.com | SUCCESS => {
    "ansible_facts": {
...output omitted...
        "ansible_local": {
            "custom": {
                "packages": {
                    "db_package": "mariadb-server",
                    "web_package": "httpd"
                },
                "users": {
                    "user1": "joe",
                    "user2": "jane"
                }
            }
        },
...output omitted...
    },
    "changed": false
}

Os fatos personalizados podem ser usados da mesma forma que os fatos padrão no playbooks:

[user@demo ~]$ cat playbook.yml
---
- hosts: all
  tasks:
  - name: Prints various Ansible facts
    debug:
      msg: >
           The package to install on {{ ansible_facts['fqdn'] }}
           is {{ ansible_facts['ansible_local']['custom']['packages']['web_package'] }}
[user@demo ~]$ ansible-playbook playbook.yml
PLAY ***********************************************************************
TASK [Gathering Facts] *****************************************************
ok: [demo1.example.com]
TASK [Prints various Ansible facts] ****************************************
ok: [demo1.example.com] => {
    "msg": "The package to install on demo1.example.com  is httpd"
}
PLAY RECAP *****************************************************************
demo1.example.com    : ok=2    changed=0    unreachable=0    failed=0

Uso de Magic Variables

Algumas variáveis não são fatos ou configuradas pelo módulo setup, mas também são definidas automaticamente pelo Ansible. Essas magic variables também podem ser úteis para obter informações específicas de um host gerenciado específico.

Quatro das mais úteis são:

hostvars

Contém as variáveis para hosts gerenciados e pode ser usada para obter os valores de outras variáveis de host gerenciado. Ela não inclui os fatos do host gerenciado se eles ainda não foram coletados para o host.

group_names

Lista todos os grupos nos quais o host gerenciado atual está.

groups

Lista todos os grupos e hosts no inventário.

inventory_hostname

Contém o nome do host gerenciado atual como configurado no inventário. Ele pode ser diferente do nome do host relatado por fatos por vários motivos.

Há também outras magic variables. Para obter mais informações, consulte https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable. Uma forma de obter informações sobre esses valores é usar o módulo debug para gerar relatórios sobre os conteúdos da variável hostvars de um host específico:

[user@demo ~]$ ansible localhost -m debug -a 'var=hostvars["localhost"]'
localhost | SUCCESS => {
    "hostvars[\"localhost\"]": {
        "ansible_check_mode": false,
        "ansible_connection": "local",
        "ansible_diff_mode": false,
        "ansible_facts": {},
        "ansible_forks": 5,
        "ansible_inventory_sources": [
            "/home/student/demo/inventory"
        ],
        "ansible_playbook_python": "/usr/bin/python2",
        "ansible_python_interpreter": "/usr/bin/python2",
        "ansible_verbosity": 0,
        "ansible_version": {
            "full": "2.7.0",
            "major": 2,
            "minor": 7,
            "revision": 0,
            "string": "2.7.0"
        },
        "group_names": [],
        "groups": {
            "all": [
                "serverb.lab.example.com"
            ],
            "ungrouped": [],
            "webservers": [
                "serverb.lab.example.com"
            ]
        },
        "inventory_hostname": "localhost",
        "inventory_hostname_short": "localhost",
        "omit": "__omit_place_holder__18d132963728b2cbf7143dd49dc4bf5745fe5ec3",
        "playbook_dir": "/home/student/demo"
    }
}
britho commented 3 years ago

Neste exercício, você reunirá fatos do Ansible de um host gerenciado e os usará em ações.

Resultados

Você deverá ser capaz de:

Reunir fatos de um host.

Criar tarefas que usem os fatos reunidos. 

Faça login na workstation como student usando a senha student.

Na workstation, execute o comando lab data-facts start. Este script cria o diretório de trabalho, data-facts, e o preenche com um arquivo de configuração e um inventário de host do Ansible.

[student@workstation ~]$ lab data-facts start

Em workstation, com o usuário student, acesse o diretório /home/student/data-facts.

[student@workstation ~]$ cd ~/data-facts
[student@workstation data-facts]$ 

O módulo setup do Ansible recupera fatos de sistemas. Execute um comando ad hoc para recuperar os fatos para todos os servidores no grupo webserver. A saída exibe todos os fatos reunidos para servera.lab.example.com em formato JSON. Revise algumas das variáveis exibidas.

[student@workstation data-facts]$ ansible webserver -m setup
...output omitted...
servera.lab.example.com | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "172.25.250.10"
        ],
        "ansible_all_ipv6_addresses": [
            "fe80::2937:3aa3:ea8d:d3b1"
        ],
...output omitted...

Em workstation, crie um arquivo de fato chamado de /home/student/data-facts/custom.fact. O arquivo de fato define o pacote a ser instalado e o serviço a ser iniciado em servera. O arquivo deverá exibir o seguinte texto:

[general]
package = httpd
service = httpd
state = started
enabled = true

Crie o playbook setup_facts.yml para fazer o diretório remoto /etc/ansible/facts.d e para salvar o arquivo custom.fact nesse diretório.

---
- name: Install remote facts
  hosts: webserver
  vars:
    remote_dir: /etc/ansible/facts.d
    facts_file: custom.fact
  tasks:
    - name: Create the remote directory
      file:
        state: directory
        recurse: yes
        path: "{{ remote_dir }}"
    - name: Install the new facts
      copy:
        src: "{{ facts_file }}"
        dest: "{{ remote_dir }}"

Execute um comando ad hoc com o módulo de setup. Procure a seção ansible_local na saída. Não deve haver nenhum fato personalizado nesse momento.

[student@workstation data-facts]$ ansible webserver -m setup 
servera.lab.example.com | SUCCESS => {
    "ansible_facts": {
...output omitted...
        "ansible_local": {}
...output omitted...
    },
    "changed": false
}

Antes de executar o playbook, verifique se a sintaxe está correta executando ansible-playbook --syntax-check. Se ela relatar algum erro, corrija-o antes de ir para a próxima etapa. Você verá uma saída semelhante à seguinte:

[student@workstation data-facts]$ ansible-playbook --syntax-check setup_facts.yml

playbook: setup_facts.yml

Execute o playbook setup_facts.yml.

[student@workstation data-facts]$ ansible-playbook setup_facts.yml

PLAY [Install remote facts] ****************************************************

TASK [Gathering Facts] *********************************************************
ok: [servera.lab.example.com]

TASK [Create the remote directory] *********************************************
changed: [servera.lab.example.com]

TASK [Install the new facts] ***************************************************
changed: [servera.lab.example.com]

PLAY RECAP *********************************************************************
servera.lab.example.com    : ok=3    changed=2    unreachable=0    failed=0

Agora é possível criar o playbook principal que usa tanto fatos padrão como do usuário para configurar o servera. Ao longo de várias etapas a seguir, você acrescentará ao arquivo do playbook. Crie o playbook playbook.yml com o seguinte:

---
- name: Install Apache and starts the service
  hosts: webserver

Continue a editar o arquivo playbook.yml criando a primeira tarefa que instala o pacote httpd. Use o fato do usuário para o nome do pacote.

  tasks:
    - name: Install the required package
      yum:
        name: "{{ ansible_facts['ansible_local']['custom']['general']['package'] }}"
        state: latest

Crie outra tarefa que usa o fato personalizado para iniciar o serviço httpd.

    - name: Start the service
      service:
        name: "{{ ansible_facts['ansible_local']['custom']['general']['service'] }}"
        state: "{{ ansible_facts['ansible_local']['custom']['general']['state'] }}"
        enabled: "{{ ansible_facts['ansible_local']['custom']['general']['enabled'] }}"

Quando todas as tarefas forem concluídas, o playbook completo deverá ter a aparência a seguir. Revise o playbook e certifique-se de que todas as tarefas estejam definidas.

---
- name: Install Apache and starts the service
  hosts: webserver

  tasks:
    - name: Install the required package
      yum:
        name: "{{ ansible_facts['ansible_local']['custom']['general']['package'] }}"
        state: latest

    - name: Start the service
      service:
        name: "{{ ansible_facts['ansible_local']['custom']['general']['service'] }}"
        state: "{{ ansible_facts['ansible_local']['custom']['general']['state'] }}"
        enabled: "{{ ansible_facts['ansible_local']['custom']['general']['enabled'] }}"

Antes de executar o playbook, use um comando ad hoc para verificar se o serviço httpd não está em execução no momento em servera.

[student@workstation data-facts]$ ansible servera.lab.example.com -m command \
> -a 'systemctl status httpd'
servera.lab.example.com | FAILED | rc=4 >>
Unit httpd.service could not be found.non-zero return code

Verifique a sintaxe do playbook usando o comando ansible-playbook --syntax-check. Se ela relatar algum erro, corrija-o antes de ir para a próxima etapa. Você verá uma saída semelhante à seguinte:

[student@workstation data-facts]$ ansible-playbook --syntax-check playbook.yml

playbook: playbook.yml

Execute o playbook usando o comando ansible-playbook. Observe a saída enquanto o Ansible instala o pacote e, em seguida, ativa o serviço.

[student@workstation data-facts]$ ansible-playbook playbook.yml

PLAY [Install Apache and start the service] ************************************

TASK [Gathering Facts] *********************************************************
ok: [servera.lab.example.com]

TASK [Install the required package] ********************************************
changed: [servera.lab.example.com]

TASK [Start the service] *******************************************************
changed: [servera.lab.example.com]

PLAY RECAP *********************************************************************
servera.lab.example.com    : ok=3    changed=2    unreachable=0    failed=0

Use um comando ad hoc para executar systemctl e determinar se o serviço httpd está agora em execução em servera.

[student@workstation data-facts]$ ansible servera.lab.example.com -m command \
> -a 'systemctl status httpd'
servera.lab.example.com | CHANGED | rc=0 >>
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
   Active: active (running) since Mon 2019-05-27 07:50:55 EDT; 50s ago
     Docs: man:httpd.service(8)
 Main PID: 11603 (httpd)
   Status: "Running, listening on: port 80"
    Tasks: 213 (limit: 4956)
   Memory: 24.1M
   CGroup: /system.slice/httpd.service
...output omitted...

Encerramento

Na workstation, execute o script lab data-facts finish para limpar este exercício.

[student@workstation ~]$ lab data-facts finish

Isso conclui o exercício orientado.

britho commented 3 years ago

Lista de verificação de desempenho

Neste laboratório, você escreverá e executará um playbook do Ansible que usa variáveis, segredos e fatos.

Resultados

Você deverá ser capaz de definir variáveis e usar fatos em um playbook, bem como usar as variáveis definidas em um arquivo criptografado.

Faça login na workstation como student usando a senha student.

Na workstation, execute o comando lab data-review start. O script cria o diretório de trabalho /home/student/data-review e o preenche com um arquivo de configuração e um inventário de host do Ansible. O host gerenciado serverb.lab.example.com está definido nesse inventário como membro do grupo de hosts webserver. Um desenvolvedor solicitou que você escrevesse um playbook do Ansible para automatizar a configuração de um ambiente de servidor web em serverb.lab.example.com, que controla o acesso dos usuários ao site usando autenticação básica.

O subdiretório files contém:

  • Um arquivo de configuração httpd.conf para o serviço web Apache para autenticação básica.

  • Um arquivo .htaccess, usado para controlar o acesso ao diretório raiz de documentos do servidor web.

  • Um arquivo htpasswd contendo credenciais para usuários permitidos.

[student@workstation ~]$ lab data-review start
  1. No diretório de trabalho, crie o playbook playbook.yml e adicione o grupo de hosts webserver como host gerenciado. Defina as seguintes variáveis de ação:

    Variável | Valores -- | -- firewall_pkg | firewalld firewall_svc | firewalld web_pkg | httpd web_svc | httpd ssl_pkg | mod_ssl httpdconf_src | files/httpd.conf httpdconf_dest | /etc/httpd/conf/httpd.conf htaccess_src | files/.htaccess secrets_dir | /etc/httpd/secrets secrets_src | files/htpasswd secrets_dest | "{{ secrets_dir }}/htpasswd" web_root | /var/www/html

    1. Mude para o diretório de trabalho /home/student/data-review.

      [student@workstation ~]$ cd ~/data-review
      [student@workstation data-review]$ 
    2. Crie o arquivo do playbook playbook.yml e altere-o em um editor de texto. O início do arquivo deve aparecer da seguinte maneira:

      ---
      - name: install and configure webserver with basic auth
        hosts: webserver
        vars:
          firewall_pkg: firewalld
          firewall_svc: firewalld
          web_pkg: httpd
          web_svc: httpd
          ssl_pkg: mod_ssl
          httpdconf_src: files/httpd.conf
          httpdconf_dest: /etc/httpd/conf/httpd.conf
          htaccess_src: files/.htaccess
          secrets_dir: /etc/httpd/secrets
          secrets_src: files/htpasswd
          secrets_dest: "{{ secrets_dir }}/htpasswd"
          web_root: /var/www/html
  • Adicione a seção tasks à ação. Escreva uma tarefa que garanta que a versão mais recente dos pacotes necessários está instalada. Esses pacotes são definidos pelas variáveis firewall_pkg, web_pkg e ssl_pkg.

    1. Defina o início da seção tasks adicionando a seguinte linha ao playbook:

        tasks:
    2. Adicione as linhas a seguir ao playbook para definir uma tarefa que use o módulo yum para instalar os pacotes necessários.

          - name: latest version of necessary packages installed
            yum:
              name:
                - "{{ firewall_pkg }}"
                - "{{ web_pkg }}"
                - "{{ ssl_pkg }}"
              state: latest
  • Adicione uma segunda tarefa ao playbook que garanta que o arquivo especificado pela variável httpdconf_src seja copiado (com o módulo copy) para o local determinado pela variável httpdconf_dest no host gerenciado. O arquivo deve ser de propriedade do usuário root e do grupo root. Também defina as permissões do arquivo como 0644.

    Adicione as linhas a seguir ao playbook para definir uma tarefa que use o módulo copy para copiar o conteúdo do arquivo definido pela variável httpdconf_src para o local especificado pela variável httpdconf_dest.

        - name: configure web service
          copy:
            src: "{{ httpdconf_src }}"
            dest: "{{ httpdconf_dest }}"
            owner: root
            group: root
            mode: 0644
  • Adicione uma terceira tarefa que use o módulo file para criar o diretório especificado pela variável secrets_dir no host gerenciado. Esse diretório contém os arquivos de senha usados para a autenticação básica dos serviços web. O arquivo deve ser de propriedade do usuário apache e do grupo apache. Defina as permissões do arquivo como 0500.

    Adicione as linhas a seguir ao playbook para definir uma tarefa que use o módulo file para criar o diretório definido pela variável secrets_dir.

        - name: secrets directory exists
          file:
            path: "{{ secrets_dir }}"
            state: directory
            owner: apache
            group: apache
            mode: 0500
  • Adicione uma quarta tarefa que use o módulo copy para posicionar um arquivo htpasswd, usado para a autenticação básica dos usuários web. A fonte deve ser definida pela variável secrets_src. O destino deve ser definido pela variável secrets_dest. O arquivo deve ser de propriedade do usuário e grupo apache. Set 0400 as the file permissions.

        - name: htpasswd file exists
          copy:
            src: "{{ secrets_src }}"
            dest: "{{ secrets_dest }}"
            owner: apache
            group: apache
            mode: 0400
  • Adicione uma quinta tarefa que use o módulo copy para criar o arquivo .htaccess no diretório raiz do documento do servidor web. Copie o arquivo especificado pela variável htaccess_src para {{ web_root}}/.htaccess. O arquivo deve ser de propriedade do usuário apache e do grupo apache. Defina as permissões do arquivo como 0400.

    Adicione as linhas a seguir ao playbook para definir uma tarefa que use o módulo copy para criar o arquivo .htaccess usando o arquivo definido pela variável htaccess_src.

        - name: .htaccess file installed in docroot
          copy:
            src: "{{ htaccess_src }}"
            dest: "{{ web_root }}/.htaccess"
            owner: apache
            group: apache
            mode: 0400
  • Adicione uma sexta tarefa que use o módulo copy para criar o arquivo de conteúdo da web index.html no diretório especificado pela variável web_root. O arquivo deve conter a mensagem HOSTNAME (IPADDRESS) has been customized by Ansible., onde HOSTNAME é o nome totalmente qualificado do host gerenciado e IPADDRESS é seu endereço IPv4. Use a opção content para o módulo copy para especificar o conteúdo do arquivo e fatos Ansible para especificar o nome do host e o endereço IP.

    Adicione as linhas a seguir ao playbook para definir uma tarefa que use o módulo copy para criar o arquivo index.html no diretório definido pela variável web_root. Preencha o arquivo com o conteúdo especificado usando os fatos do Ansible ansible_facts['fqdn'] e ansible_facts['default_ipv4']['address'] recuperados do host gerenciado.

        - name: create index.html
          copy:
            content: "{{ ansible_facts['fqdn'] }} ({{ ansible_facts['default_ipv4']['address'] }}) has been customized by Ansible.\n"
            dest: "{{ web_root }}/index.html"
  • Adicione uma sétima tarefa que use o módulo service para ativar e iniciar o serviço de firewall no host gerenciado.

    Adicione as linhas a seguir ao playbook para definir uma tarefa que use o módulo service para ativar e iniciar o serviço de firewall.

        - name: firewall service enabled and started
          service:
            name: "{{ firewall_svc }}"
            state: started
            enabled: true
  • Adicione uma oitava tarefa que use o módulo firewalld para permitir o serviço https necessário para que os usuários acessem os serviços web no host gerenciado. Essa alteração de firewall deve ser permanente e deve ocorrer imediatamente.

    Adicione as linhas a seguir ao playbook para definir uma tarefa que use o módulo firewalld para abrir a porta HTTPS para o serviço web.

        - name: open the port for the web server
          firewalld:
            service: https
            state: enabled
            immediate: true
            permanent: true
  • Adicione uma tarefa final que use o módulo service para ativar e iniciar o serviço web no host gerenciado para que todas as alterações de configuração entrem em vigor. O nome do serviço web é definido pela variável web_svc.

        - name: web service enabled and started
          service:
            name: "{{ web_svc }}"
            state: started
            enabled: true
  • Defina uma segunda ação direcionada ao localhost que testará a autenticação para o servidor web. Ela não precisa de privilégios de escalonamento. Defina uma variável chamada web_user com o valor guest.

    1. Adicione a linha a seguir para definir o início de uma segunda ação. Observe que não há recuo.

      - name: test web server with basic auth
    2. Adicione a linha a seguir para indicar que a ação se aplica ao host gerenciado localhost.

        hosts: localhost
    3. Adicione a linha a seguir para desabilitar o escalonamento de privilégios.

        become: no
    4. Adicione as linhas a seguir para definir uma lista de variáveis e a variável web_user.

        vars:
          web_user: guest
  • Adicione uma diretiva à ação que acrescenta outras variáveis de um arquivo de variáveis chamado de vars/secret.yml. Esse arquivo contém uma variável que determina a senha do usuário web. Você criará esse arquivo posteriormente no laboratório.

    Defina o início da lista de tarefas.

    1. Usando a palavra-chave vars_files, adicione as linhas a seguir ao playbook para instruir o Ansible a usar as variáveis encontradas no arquivo vars/secret.yml.

        vars_files:
          - vars/secret.yml
    2. Adicione a linha a seguir para definir o início da lista tasks.

        tasks:
  • Adicione duas tarefas à segunda ação.

    O primeiro usa o módulo uri para solicitar conteúdo de https://serverb.lab.example.com usando autenticação básica. Observe que o certificado apresentado por serverb não será confiável, portanto, será necessário evitar a validação do certificado. A tarefa deve verificar um código de status HTTP de retorno 200. Configure a tarefa para colocar o conteúdo retornado na variável de resultados da tarefa. Registre o resultado da tarefa em uma variável.

    A segunda tarefa usa o módulo debug para imprimir o conteúdo retornado do servidor web.

    1. Adicione as linhas a seguir para criar a tarefa de modo a verificar o serviço web a partir do nó de controle. Certifique-se de fazer o recuo da primeira linha com quatro espaços.

          - name: connect to web server with basic auth
            uri:
              url: https://serverb.lab.example.com
              validate_certs: no
              force_basic_auth: yes
              user: "{{ web_user }}"
              password: "{{ web_pass }}"
              return_content: yes
              status_code: 200
            register: auth_test
    2. Crie a segunda tarefa usando o módulo de depuração. O conteúdo retornado do servidor web é adicionado à variável registrada como a chave content.

          - debug:
              var: auth_test.content
    3. O playbook completo deverá ficar desta forma:

      ---
      - name: install and configure webserver with basic auth
        hosts: webserver
        vars:
          firewall_pkg: firewalld
          firewall_svc: firewalld
          web_pkg: httpd
          web_svc: httpd
          ssl_pkg: mod_ssl
          httpdconf_src: files/httpd.conf
          httpdconf_dest: /etc/httpd/conf/httpd.conf
          htaccess_src: files/.htaccess
          secrets_dir: /etc/httpd/secrets
          secrets_src: files/htpasswd
          secrets_dest: "{{ secrets_dir }}/htpasswd"
          web_root: /var/www/html
        tasks:
          - name: latest version of necessary packages installed
            yum:
              name:
                - "{{ firewall_pkg }}"
                - "{{ web_pkg }}"
                - "{{ ssl_pkg }}"
              state: latest
          - name: configure web service
            copy:
              src: "{{ httpdconf_src }}"
              dest: "{{ httpdconf_dest }}"
              owner: root
              group: root
              mode: 0644
          - name: secrets directory exists
            file:
              path: "{{ secrets_dir }}"
              state: directory
              owner: apache
              group: apache
              mode: 0500
          - name: htpasswd file exists
            copy:
              src: "{{ secrets_src }}"
              dest: "{{ secrets_dest }}"
              owner: apache
              group: apache
              mode: 0400
          - name: .htaccess file installed in docroot
            copy:
              src: "{{ htaccess_src }}"
              dest: "{{ web_root }}/.htaccess"
              owner: apache
              group: apache
              mode: 0400
          - name: create index.html
            copy:
              content: "{{ ansible_facts['fqdn'] }} ({{ ansible_facts['default_ipv4']['address'] }}) has been customized by Ansible.\n"
              dest: "{{ web_root }}/index.html"
          - name: firewall service enable and started
            service:
              name: "{{ firewall_svc }}"
              state: started
              enabled: true
          - name: open the port for the web server
            firewalld:
              service: https
              state: enabled
              immediate: true
              permanent: true
          - name: web service enabled and started
            service:
              name: "{{ web_svc }}"
              state: started
              enabled: true
      - name: test web server with basic auth
        hosts: localhost
        become: no
        vars:
          - web_user: guest
        vars_files:
          - vars/secret.yml
        tasks:
          - name: connect to web server with basic auth
            uri:
              url: https://serverb.lab.example.com
              validate_certs: no
              force_basic_auth: yes
              user: "{{ web_user }}"
              password: "{{ web_pass }}"
              return_content: yes
              status_code: 200
            register: auth_test
          - debug:
              var: auth_test.content
    4. Save and close the playbook.yml file.

  • Crie um arquivo criptografado com o Ansible Vault, chamado vars/secret.yml . Ele deve definir a variável web_pass como redhat, que será a senha do usuário web.

    1. Crie um subdiretório chamado vars no diretório de trabalho.

      [student@workstation data-review]$ mkdir vars
    2. Crie o arquivo variável criptografado, vars/secret.yml, usando o Ansible Vault. Defina a senha do arquivo criptografado para redhat.

      [student@workstation data-review]$ ansible-vault create vars/secret.yml
      New Vault password: redhat
      Confirm New Vault password: redhat
    3. Adicione a definição de variável a seguir ao arquivo.

      web_pass: redhat
    4. Salve e feche o arquivo.

  • Execute o playbook playbook.yml. Verifique se o conteúdo foi retornado com êxito do servidor web e se corresponde ao que foi configurado em uma tarefa anterior.

    1. Antes de executar o playbook, verifique se a sintaxe está correta executando ansible-playbook --syntax-check. Use a opção --ask-vault-pass que será solicitada para a senha do vault. Digite redhat quando a senha for solicitada. Se ela relatar algum erro, corrija-o antes de ir para a próxima etapa. Você verá uma saída semelhante à seguinte:

      [student@workstation data-review]$ ansible-playbook --syntax-check \
      > --ask-vault-pass playbook.yml
      Vault password: redhat
      playbook: playbook.yml
    2. Usando o comando ansible-playbook, execute o playbook com a opção --ask-vault-pass. Digite redhat quando a senha for solicitada.

      [student@workstation data-review]$ ansible-playbook playbook.yml --ask-vault-pass
      Vault password: redhat
      PLAY [Install and configure webserver with basic auth] *********************
      ...output omitted...
      TASK [connect to web server with basic auth] ***********************************
      ok: [localhost]
      TASK [debug] *******************************************************************
      ok: [localhost] => {
          "auth_test.content": "serverb.lab.example.com (172.25.250.11) has been customized by Ansible.\n"
      }
      PLAY RECAP *********************************************************************
      localhost                  : ok=3    changed=0    unreachable=0    failed=0
      serverb.lab.example.com    : ok=10   changed=8    unreachable=0    failed=0
  • Avaliação

    Execute o comando lab data-review grade em workstation para confirmar o êxito deste exercício. Corrija todas as falhas relatadas e execute novamente o script até que ele seja concluído com êxito.

    [student@workstation ~]$ lab data-review grade

    Encerramento

    Na workstation, execute o comando lab data-review finish para limpar este exercício.

    [student@workstation ~]$ lab data-review finish

    Isso conclui o laboratório.

    britho commented 3 years ago

    Neste capítulo, você aprendeu que:

    As variáveis do Ansible permitem que os administradores reutilizem valores em todos os arquivos de um projeto do Ansible.
    
    As variáveis podem ser definidas para hosts e grupos de hosts no arquivo de inventário.
    
    As variáveis podem ser definidas para playbooks usando fatos e arquivos externos. Elas também podem ser definidas na linha de comando.
    
    A palavra-chave register pode ser usada para capturar a saída de um comando em uma variável.
    
    O Ansible Vault é uma forma de proteger dados confidenciais, como hashes de senha e chaves privadas, para implantação usando playbooks do Ansible.
    
    Os fatos do Ansible são variáveis que são automaticamente descobertas pelo Ansible a partir de um host gerenciado. 
    britho commented 3 years ago

    Meta | Gerenciar erros de controle de tarefas, manipuladores e tags nos playbooks do Ansible. -- | -- Objetivos | Implementar loops para escrever tarefas eficientes para controlar quando as tarefas são executadas. Implementar uma tarefa que seja executada apenas quando outra tarefa alterar o host gerenciado. Controlar o que acontece quando há falha em uma tarefa e quais condições fazem com que uma tarefa falhe. Seções | Criação de loops e tarefas condicionais (e exercício orientado) Implementação de manipuladores (e exercício orientado) Tratamento de falhas nas tarefas (e exercício orientado) Laboratório | Implementação de controle de tarefas

    Objetivos

    Depois de concluir esta seção, você deverá ser capaz de usar loops para escrever tarefas eficientes e usar condições para controlar quando as tarefas são executadas.

    Iteração de tarefas com loops

    O uso de loops poupa os administradores de ter de escrever múltiplas tarefas que usam o mesmo módulo. Por exemplo, em vez de escrever cinco tarefas para garantir que cinco usuários existem, você pode escrever uma tarefa para iterar em uma lista de cinco usuários e garantir que todos eles existem.

    O Ansible dá suporte à iteração de uma tarefa em um conjunto de itens usando a palavra-chave loop. Você pode configurar loops para repetir uma tarefa usando cada item em uma lista, o conteúdo de cada um dos arquivos em uma lista, uma sequência gerada de números ou usando estruturas mais complexas. Esta seção abrange loops simples que são iterados em uma lista de itens. Consulte a documentação para conhecer cenários de loop mais avançados.

    Loops simples

    Um loop simples itera uma tarefa em uma lista de itens. A palavra-chave loop é adicionada à tarefa e assume como valor a lista de itens na qual a tarefa deve ser iterada. A variável de loop item mantém o valor usado durante cada iteração.

    Considere o seguinte trecho que usa o módulo service duas vezes para garantir que os dois serviços de rede estejam em execução:

    - name: Postfix is running
      service:
        name: postfix
        state: started
    - name: Dovecot is running
      service:
        name: dovecot
        state: started

    Essas duas tarefas podem ser sobrescritas para usar um loop simples, para que somente uma tarefa seja necessária para garantir que ambos os serviços estejam em execução:

    - name: Postfix and Dovecot are running
      service:
        name: "{{ item }}"
        state: started
      loop:
        - postfix
        - dovecot

    A lista usada pela tarefa loop pode ser fornecida por uma variável. No exemplo a seguir, a variável mail_services contém a lista de serviços que precisam estar em execução.

    vars:
      mail_services:
        - postfix
        - dovecot
    tasks:
      - name: Postfix and Dovecot are running
        service:
          name: "{{ item }}"
          state: started
        loop: "{{ mail_services }}"

    Loops em uma lista de hashes ou dicionários

    A lista loop não precisa ser uma lista de valores simples. No exemplo a seguir, cada item na lista é, na verdade, um hash ou um dicionário. Cada hash ou dicionário no exemplo tem duas chaves, name e groups e o valor de cada chave na variável de loop item atual pode ser recuperado com as variáveis item.name e item.groups, respectivamente.

    - name: Users exist and are in the correct groups
      user:
        name: "{{ item.name }}"
        state: present
        groups: "{{ item.groups }}"
      loop:
        - name: jane
          groups: wheel
        - name: joe
          groups: root

    O resultado da tarefa anterior é que o usuário jane está presente e é membro do grupo wheel e o usuário joe está presente e é membro do grupo root.

    Palavras-chave de loop nas versões anteriores

    Antes do Ansible2.5, a maioria dos playbooks utilizava uma sintaxe diferente para loops. Eram fornecidas várias palavras-chave de loop, com prefixos with_, seguido pelo nome de um plugin de pesquisa do Ansible (um recurso avançado não explicado em detalhes neste curso). Essa sintaxe para looping é muito comum nos playbooks existentes, mas provavelmente será descontinuada em algum momento no futuro.

    Alguns exemplos são listados na tabela abaixo:

    Palavra-chave do loop | Descrição -- | -- with_items | O comportamento é o mesmo da palavra-chave loop para listas simples, como listas de strings ou listas de hashes/dicionários. Ao contrário de loop, se forem fornecidas listas de listas para with_items, elas serão agrupadas em uma lista de nível único. A variável de loop item mantém o item da lista usado durante cada iteração. with_file | Esta palavra-chave requer a lista de nomes de arquivos do nó de controle. A variável do loop item mantém o conteúdo de um arquivo correspondente da lista de arquivos durante cada iteração. with_sequence | Em vez de exigir uma lista, esta palavra-chave requer parâmetros para gerar uma lista de valores com base em uma sequência numérica. A variável do loop item mantém o valor de um dos itens gerados na sequência gerada durante cada iteração.

    Um exemplo de with_items em um playbook é mostrado a seguir:

      vars:
        data:
          - user0
          - user1
          - user2
      tasks:
        - name: "with_items"
          debug:
            msg: "{{ item }}"
          with_items: "{{ data }}"

    A partir do Ansible2.5, a maneira recomendada de escrever loops é usar a palavra-chave loop.

    No entanto, você ainda precisa entender a antiga sintaxe, especialmente with_items, porque ela é amplamente utilizada nos playbooks existentes. É provável que você encontre playbooks e funções que continuem usando palavras-chave with_* para looping.

    Qualquer tarefa que use a sintaxe antiga pode ser convertida para usar loop com os filtros do Ansible. Você não precisa saber como usar os filtros do Ansible para fazer isso. Há uma boa referência sobre como converter os loops antigos para a nova sintaxe, bem como exemplos de como fazer o loop em itens que não são listas simples, na documentação do Ansible na seção Migração de with_X para loop do Guia do Usuário do Ansible.

    Você provavelmente encontrará tarefas de playbooks mais antigos que contenham palavras-chave with_*.

    Técnicas de looping avançadas estão fora do escopo deste curso. Todas as tarefas de iteração do curso podem ser implementadas com a palavra-chave with_items ou loop.

    Uso de variáveis de registro com loops

    A palavra-chave register também pode capturar a saída de uma tarefa que faz um loop. O trecho a seguir mostra a estrutura da variável de registro de uma tarefa que faz um loop:

    [student@workstation loopdemo]$ cat loop_register.yml
    ---
    - name: Loop Register Test
      gather_facts: no
      hosts: localhost
      tasks:
        - name: Looping Echo Task
          shell: "echo This is my item: {{ item }}"
          loop:
            - one
            - two
          register: echo_results1
        - name: Show echo_results variable
          debug:
            var: echo_results2
      | A variável echo_results é registrada. -- | --   | O conteúdo da variável echo_results é exibido na tela.

    Executar o playbook acima produz a seguinte saída:

    [student@workstation loopdemo]$ ansible-playbook loop_register.yml
    PLAY [Loop Register Test] ****************************************************
    TASK [Looping Echo Task] *****************************************************
    ...output omitted...
    TASK [Show echo_results variable] ********************************************
    ok: [localhost] => {
        "echo_results": {1
            "changed": true,
            "msg": "All items completed",
            "results": [2
                {3
                    "_ansible_ignore_errors": null,
                    ...output omitted...
                    "changed": true,
                    "cmd": "echo This is my item: one",
                    "delta": "0:00:00.011865",
                    "end": "2018-11-01 16:32:56.080433",
                    "failed": false,
                    ...output omitted...
                    "item": "one",
                    "rc": 0,
                    "start": "2018-11-01 16:32:56.068568",
                    "stderr": "",
                    "stderr_lines": [],
                    "stdout": "This is my item: one",
                    "stdout_lines": [
                        "This is my item: one"
                    ]
                },
                {4
                    "_ansible_ignore_errors": null,
                    ...output omitted...
                    "changed": true,
                    "cmd": "echo This is my item: two",
                    "delta": "0:00:00.011142",
                    "end": "2018-11-01 16:32:56.828196",
                    "failed": false,
                    ...output omitted...
                    "item": "two",
                    "rc": 0,
                    "start": "2018-11-01 16:32:56.817054",
                    "stderr": "",
                    "stderr_lines": [],
                    "stdout": "This is my item: two",
                    "stdout_lines": [
                        "This is my item: two"
                    ]
                }
            ]5
        }
    }
    ...output omitted...
      | O caractere { indica que o início da variável echo_results é composto por pares chave-valor. -- | --   | A chave results contém os resultados da tarefa anterior. O caractere [ indica o início de uma lista.   | O início dos metadados da tarefa para o primeiro item (indicado pela chave item). A saída do comando echo é encontrada na chave stdout.   | O início dos metadados de resultado da tarefa para o segundo item. ??? | O caractere ] indica o fim da lista results.

    No exemplo acima, a chave results contém uma lista. Abaixo, o playbook é modificado de forma que a segunda tarefa itere nessa lista:

    [student@workstation loopdemo]$ cat new_loop_register.yml
    ---
    - name: Loop Register Test
      gather_facts: no
      hosts: localhost
      tasks:
        - name: Looping Echo Task
          shell: "echo This is my item: {{ item }}"
          loop:
            - one
            - two
          register: echo_results
        - name: Show stdout from the previous task.
          debug:
            msg: "STDOUT from previous task: {{ item.stdout }}"
          loop: "{{ echo_results['results'] }}"

    Depois de executar o playbook acima, a saída será:

    PLAY [Loop Register Test] ****************************************************
    TASK [Looping Echo Task] *****************************************************
    ...output omitted...
    TASK [Show stdout from the previous task.] ***********************************
    ok: [localhost] => (item={...output omitted...}) => {
        "msg": "STDOUT from previous task: This is my item: one"
    }
    ok: [localhost] => (item={...output omitted...}) => {
        "msg": "STDOUT from previous task: This is my item: two"
    }
    ...output omitted...

    Execução de tarefas de forma condicional

    O Ansible pode usar condicionais para executar tarefas ou ações quando certas condições são atendidas. Por exemplo, uma condicional pode ser usada para determinar a memória disponível em um host gerenciado antes de o Ansible instalar ou configurar um serviço.

    As condicionais permitem aos administradores diferenciar entre hosts gerenciados e atribuí-los a funções práticas com base nas condições que atendem. As variáveis de playbook, as variáveis registradas e os fatos do Ansible podem ser testados com condicionais. Existem operadores disponíveis para comparar strings, dados numéricos e valores booleanos.

    Os cenários a seguir ilustram o uso de condicionais no Ansible:

    • Um limite rígido pode ser definido em uma variável (por exemplo, min_memory) e comparado à memória disponível em um host gerenciado.

    • A saída do comando pode ser capturada e avaliada pelo Ansible para determinar se uma tarefa foi concluída antes de realizar mais ações. Por exemplo, se ocorrer uma falha em um programa, um batch será ignorado.

    • Use os fatos do Ansible para determinar a configuração da rede de hosts gerenciados e decidir qual arquivo de template será enviado (por exemplo, bonding ou troncos de rede).

    • O número de CPUs pode ser avaliado para determinar como ajustar um servidor web adequadamente.

    • Compare uma variável registrada com uma variável predefinida para determinar se um serviço foi alterado. Por exemplo, teste a soma de verificação MD5 de um arquivo de configuração do serviço para ver se o serviço foi alterado.

    Sintaxe de tarefa condicional

    A instrução when é usada para executar uma tarefa de forma condicional Ela recebe como valor a condição a ser testada. Se a condição for atendida, a tarefa é executada. Se a condição não for atendida, a tarefa é ignorada.

    Uma das condições mais simples que pode ser testada é se uma variável booleana é verdadeira ou falsa. A instrução when no seguinte exemplo faz com que a tarefa seja executada apenas se run_my_task for verdadeira:

    ---
    - name: Simple Boolean Task Demo
      hosts: all
      vars:
        run_my_task: true
      tasks:
        - name: httpd package is installed
          yum:
            name: httpd
          when: run_my_task

    O próximo exemplo é um pouco mais sofisticado e testa se a variável my_service tem um valor. Se ela tiver, o valor de my_service será usado como nome do pacote a ser instalado. Se a variável my_service não estiver definida, a tarefa será ignorada sem um erro.

    ---
    - name: Test Variable is Defined Demo
      hosts: all
      vars:
        my_service: httpd
      tasks:
        - name: "{{ my_service }} package is installed"
          yum:
            name: "{{ my_service }}"
          when: my_service is defined

    A tabela a seguir mostra algumas operações que os administradores podem usar ao trabalhar com as condicionais:

    Operação | Exemplo -- | -- Igual (o valor é uma string) | ansible_machine == "x86_64" Igual (o valor é numérico) | max_memory == 512 Menor que | min_memory < 128 Maior que | min_memory > 256 Menor ou igual a | min_memory <= 256 Maior ou igual a | min_memory >= 512 Diferente de | min_memory != 512 Variável existe | min_memory is defined Variável não existe | min_memory is not defined A variável booleana é true. Os valores de 1, True ou yes são considerados como true. | memory_available A variável booleana é false. Os valores de 0, False ou no são considerados como false. | not memory_available O valor da primeira variável está presente como um valor na lista da segunda variável | ansible_distribution in supported_distros

    A última entrada da tabela anterior pode parecer confusa à primeira vista. O exemplo a seguir ilustra como funciona.

    No exemplo, a variável ansible_distribution é um fato determinado durante a tarefa Gathering Facts e identifica a distribuição do sistema operacional do host gerenciado. A variável supported_distros foi criada pelo autor do playbook e contém a lista de distribuições do sistema operacional que o playbook suporta. Se o valor ansible_distribution estiver na lista supported_distros, a condicional será aprovada e a tarefa, executada.

    ---
    - name: Demonstrate the "in" keyword
      hosts: all
      gather_facts: yes
      vars:
        supported_distros:
          - RedHat
          - Fedora
      tasks:
        - name: Install httpd using yum, where supported
          yum:
            name: http
            state: present
          when: ansible_distribution in supported_distros

    Observe o recuo da instrução when. Como a instrução when não é uma variável de módulo, ela deve ser colocada fora do módulo e recuada no nível superior da tarefa.

    Uma tarefa é um hash/dicionário YAML e a instrução when é simplesmente mais uma chave na tarefa como o nome da tarefa e o módulo que ela usa. Uma convenção comum coloca qualquer palavra-chave when que possa estar presente depois do nome e módulo da tarefa (e argumentos de módulo).

    Teste de condições múltiplas

    Uma instrução when pode ser usada para avaliar diversas condicionais. Para isso, as condicionais podem ser combinadas com as palavras-chave and ou or e agrupadas entre parênteses.

    Os trechos a seguir mostram alguns exemplos de como expressar várias condições.

    • Se uma instrução condicional deve ser atendida quando nenhuma condição for verdadeira, use a instrução or. Por exemplo, a condição a seguir será atendida se a máquina estiver executando RedHat EnterpriseLinux ou Fedora:

      when: ansible_distribution == "RedHat" or ansible_distribution == "Fedora"
    • Com a operação and, as duas condições devem ser verdadeiras para que a instrução condicional inteira seja atendida. Por exemplo, a seguinte condição é atendida se o host remoto for o host RedHat EnterpriseLinux7.5 e o kernel instalado for a versão especificada:

      when: ansible_distribution_version == "7.5" and ansible_kernel == "3.10.0-327.el7.x86_64"

      A palavra-chave when também oferece suporte ao uso de uma lista para descrever a lista de condições. Quando é fornecida uma lista para a palavra-chave when palavra-chave, todas as condicionais são combinadas usando o operador and. O exemplo abaixo demonstra outra maneira de combinar várias instruções condicionais usando o operador and:

      when:
        - ansible_distribution_version == "7.5"
        - ansible_kernel == "3.10.0-327.el7.x86_64"

      Esse formato melhora a legibilidade, uma meta fundamental para gerar playbooks do Ansible bem escritos.

    • Instruções condicionais mais complexas podem ser expressas pelo agrupamento de condições com parênteses. Isso garante que eles sejam interpretados corretamente.

      Por exemplo, a seguinte instrução condicional será atendida se a máquina estiver executando o RedHat EnterpriseLinux7 ou Fedora28: Este exemplo usa o caractere de maior que (>) para permitir a divisão da condicional longa em várias linhas no playbook, facilitando a leitura.

      when: >
          ( ansible_distribution == "RedHat" and
            ansible_distribution_major_version == "7" )
          or
          ( ansible_distribution == "Fedora" and
          ansible_distribution_major_version == "28" )

    Combinação de loops e tarefas condicionais

    É possível combinar loops e condicionais.

    No exemplo a seguir, o pacote mariadb-server será instalado pelo módulo yum se houver um sistema de arquivos montado em / com mais de 300MB livres. O fato ansible_mounts é uma lista de dicionários, cada um representando fatos sobre o sistema de arquivos montado. O loop itera em cada dicionário na lista e a instrução condicional não é atendida a não ser que um dicionário seja encontrado representando um sistema de arquivos montado no qual ambas as condições sejam verdadeiras.

    - name: install mariadb-server if enough space on root
      yum:
        name: mariadb-server
        state: latest
      loop: "{{ ansible_mounts }}"
      when: item.mount == "/" and item.size_available > 300000000

    Quando você usar when com loop em uma tarefa, a instrução when será verificada para cada item.

    Veja outro exemplo que combina condicionais e variáveis de registro. O playbook anotado a seguir reinicia o serviço httpd apenas se o serviço postfix estiver em execução.

    ---
    - name: Restart HTTPD if Postfix is Running
      hosts: all
      tasks:
        - name: Get Postfix server status
          command: /usr/bin/systemctl is-active postfix 1
          ignore_errors: yes2
          register: result3
        - name: Restart Apache HTTPD based on Postfix status
          service:
            name: httpd
            state: restarted
          when: result.rc == 04
      | O postfix está em execução? -- | --   | Caso não esteja e ocorrer uma falha no comando, não interrompa o processamento.   | Salva as informações sobre o resultado do módulo em uma variável chamada result.   | Avalia a saída da tarefa do postfix. Se o código de saída do comando systemctl for 0, o postfix está ativo e essa tarefa reiniciará o serviço httpd.
    britho commented 3 years ago

    Meta | Gerenciar erros de controle de tarefas, manipuladores e tags nos playbooks do Ansible. -- | -- Objetivos | Implementar loops para escrever tarefas eficientes para controlar quando as tarefas são executadas. Implementar uma tarefa que seja executada apenas quando outra tarefa alterar o host gerenciado. Controlar o que acontece quando há falha em uma tarefa e quais condições fazem com que uma tarefa falhe. Seções | Criação de loops e tarefas condicionais (e exercício orientado) Implementação de manipuladores (e exercício orientado) Tratamento de falhas nas tarefas (e exercício orientado) Laboratório | Implementação de controle de tarefas

    Objetivos

    Depois de concluir esta seção, você deverá ser capaz de usar loops para escrever tarefas eficientes e usar condições para controlar quando as tarefas são executadas.

    Iteração de tarefas com loops

    O uso de loops poupa os administradores de ter de escrever múltiplas tarefas que usam o mesmo módulo. Por exemplo, em vez de escrever cinco tarefas para garantir que cinco usuários existem, você pode escrever uma tarefa para iterar em uma lista de cinco usuários e garantir que todos eles existem.

    O Ansible dá suporte à iteração de uma tarefa em um conjunto de itens usando a palavra-chave loop. Você pode configurar loops para repetir uma tarefa usando cada item em uma lista, o conteúdo de cada um dos arquivos em uma lista, uma sequência gerada de números ou usando estruturas mais complexas. Esta seção abrange loops simples que são iterados em uma lista de itens. Consulte a documentação para conhecer cenários de loop mais avançados.

    Loops simples

    Um loop simples itera uma tarefa em uma lista de itens. A palavra-chave loop é adicionada à tarefa e assume como valor a lista de itens na qual a tarefa deve ser iterada. A variável de loop item mantém o valor usado durante cada iteração.

    Considere o seguinte trecho que usa o módulo service duas vezes para garantir que os dois serviços de rede estejam em execução:

    - name: Postfix is running
      service:
        name: postfix
        state: started
    - name: Dovecot is running
      service:
        name: dovecot
        state: started

    Essas duas tarefas podem ser sobrescritas para usar um loop simples, para que somente uma tarefa seja necessária para garantir que ambos os serviços estejam em execução:

    - name: Postfix and Dovecot are running
      service:
        name: "{{ item }}"
        state: started
      loop:
        - postfix
        - dovecot

    A lista usada pela tarefa loop pode ser fornecida por uma variável. No exemplo a seguir, a variável mail_services contém a lista de serviços que precisam estar em execução.

    vars:
      mail_services:
        - postfix
        - dovecot
    tasks:
      - name: Postfix and Dovecot are running
        service:
          name: "{{ item }}"
          state: started
        loop: "{{ mail_services }}"

    Loops em uma lista de hashes ou dicionários

    A lista loop não precisa ser uma lista de valores simples. No exemplo a seguir, cada item na lista é, na verdade, um hash ou um dicionário. Cada hash ou dicionário no exemplo tem duas chaves, name e groups e o valor de cada chave na variável de loop item atual pode ser recuperado com as variáveis item.name e item.groups, respectivamente.

    - name: Users exist and are in the correct groups
      user:
        name: "{{ item.name }}"
        state: present
        groups: "{{ item.groups }}"
      loop:
        - name: jane
          groups: wheel
        - name: joe
          groups: root

    O resultado da tarefa anterior é que o usuário jane está presente e é membro do grupo wheel e o usuário joe está presente e é membro do grupo root.

    Palavras-chave de loop nas versões anteriores

    Antes do Ansible2.5, a maioria dos playbooks utilizava uma sintaxe diferente para loops. Eram fornecidas várias palavras-chave de loop, com prefixos with_, seguido pelo nome de um plugin de pesquisa do Ansible (um recurso avançado não explicado em detalhes neste curso). Essa sintaxe para looping é muito comum nos playbooks existentes, mas provavelmente será descontinuada em algum momento no futuro.

    Alguns exemplos são listados na tabela abaixo:

    Palavra-chave do loop | Descrição -- | -- with_items | O comportamento é o mesmo da palavra-chave loop para listas simples, como listas de strings ou listas de hashes/dicionários. Ao contrário de loop, se forem fornecidas listas de listas para with_items, elas serão agrupadas em uma lista de nível único. A variável de loop item mantém o item da lista usado durante cada iteração. with_file | Esta palavra-chave requer a lista de nomes de arquivos do nó de controle. A variável do loop item mantém o conteúdo de um arquivo correspondente da lista de arquivos durante cada iteração. with_sequence | Em vez de exigir uma lista, esta palavra-chave requer parâmetros para gerar uma lista de valores com base em uma sequência numérica. A variável do loop item mantém o valor de um dos itens gerados na sequência gerada durante cada iteração.

    Um exemplo de with_items em um playbook é mostrado a seguir:

      vars:
        data:
          - user0
          - user1
          - user2
      tasks:
        - name: "with_items"
          debug:
            msg: "{{ item }}"
          with_items: "{{ data }}"

    A partir do Ansible2.5, a maneira recomendada de escrever loops é usar a palavra-chave loop.

    No entanto, você ainda precisa entender a antiga sintaxe, especialmente with_items, porque ela é amplamente utilizada nos playbooks existentes. É provável que você encontre playbooks e funções que continuem usando palavras-chave with_* para looping.

    Qualquer tarefa que use a sintaxe antiga pode ser convertida para usar loop com os filtros do Ansible. Você não precisa saber como usar os filtros do Ansible para fazer isso. Há uma boa referência sobre como converter os loops antigos para a nova sintaxe, bem como exemplos de como fazer o loop em itens que não são listas simples, na documentação do Ansible na seção Migração de with_X para loop do Guia do Usuário do Ansible.

    Você provavelmente encontrará tarefas de playbooks mais antigos que contenham palavras-chave with_*.

    Técnicas de looping avançadas estão fora do escopo deste curso. Todas as tarefas de iteração do curso podem ser implementadas com a palavra-chave with_items ou loop.

    Uso de variáveis de registro com loops

    A palavra-chave register também pode capturar a saída de uma tarefa que faz um loop. O trecho a seguir mostra a estrutura da variável de registro de uma tarefa que faz um loop:

    [student@workstation loopdemo]$ cat loop_register.yml
    ---
    - name: Loop Register Test
      gather_facts: no
      hosts: localhost
      tasks:
        - name: Looping Echo Task
          shell: "echo This is my item: {{ item }}"
          loop:
            - one
            - two
          register: echo_results1
        - name: Show echo_results variable
          debug:
            var: echo_results2
      | A variável echo_results é registrada. -- | --   | O conteúdo da variável echo_results é exibido na tela.

    Executar o playbook acima produz a seguinte saída:

    [student@workstation loopdemo]$ ansible-playbook loop_register.yml
    PLAY [Loop Register Test] ****************************************************
    TASK [Looping Echo Task] *****************************************************
    ...output omitted...
    TASK [Show echo_results variable] ********************************************
    ok: [localhost] => {
        "echo_results": {1
            "changed": true,
            "msg": "All items completed",
            "results": [2
                {3
                    "_ansible_ignore_errors": null,
                    ...output omitted...
                    "changed": true,
                    "cmd": "echo This is my item: one",
                    "delta": "0:00:00.011865",
                    "end": "2018-11-01 16:32:56.080433",
                    "failed": false,
                    ...output omitted...
                    "item": "one",
                    "rc": 0,
                    "start": "2018-11-01 16:32:56.068568",
                    "stderr": "",
                    "stderr_lines": [],
                    "stdout": "This is my item: one",
                    "stdout_lines": [
                        "This is my item: one"
                    ]
                },
                {4
                    "_ansible_ignore_errors": null,
                    ...output omitted...
                    "changed": true,
                    "cmd": "echo This is my item: two",
                    "delta": "0:00:00.011142",
                    "end": "2018-11-01 16:32:56.828196",
                    "failed": false,
                    ...output omitted...
                    "item": "two",
                    "rc": 0,
                    "start": "2018-11-01 16:32:56.817054",
                    "stderr": "",
                    "stderr_lines": [],
                    "stdout": "This is my item: two",
                    "stdout_lines": [
                        "This is my item: two"
                    ]
                }
            ]5
        }
    }
    ...output omitted...
      | O caractere { indica que o início da variável echo_results é composto por pares chave-valor. -- | --   | A chave results contém os resultados da tarefa anterior. O caractere [ indica o início de uma lista.   | O início dos metadados da tarefa para o primeiro item (indicado pela chave item). A saída do comando echo é encontrada na chave stdout.   | O início dos metadados de resultado da tarefa para o segundo item. ??? | O caractere ] indica o fim da lista results.

    No exemplo acima, a chave results contém uma lista. Abaixo, o playbook é modificado de forma que a segunda tarefa itere nessa lista:

    [student@workstation loopdemo]$ cat new_loop_register.yml
    ---
    - name: Loop Register Test
      gather_facts: no
      hosts: localhost
      tasks:
        - name: Looping Echo Task
          shell: "echo This is my item: {{ item }}"
          loop:
            - one
            - two
          register: echo_results
        - name: Show stdout from the previous task.
          debug:
            msg: "STDOUT from previous task: {{ item.stdout }}"
          loop: "{{ echo_results['results'] }}"

    Depois de executar o playbook acima, a saída será:

    PLAY [Loop Register Test] ****************************************************
    TASK [Looping Echo Task] *****************************************************
    ...output omitted...
    TASK [Show stdout from the previous task.] ***********************************
    ok: [localhost] => (item={...output omitted...}) => {
        "msg": "STDOUT from previous task: This is my item: one"
    }
    ok: [localhost] => (item={...output omitted...}) => {
        "msg": "STDOUT from previous task: This is my item: two"
    }
    ...output omitted...

    Execução de tarefas de forma condicional

    O Ansible pode usar condicionais para executar tarefas ou ações quando certas condições são atendidas. Por exemplo, uma condicional pode ser usada para determinar a memória disponível em um host gerenciado antes de o Ansible instalar ou configurar um serviço.

    As condicionais permitem aos administradores diferenciar entre hosts gerenciados e atribuí-los a funções práticas com base nas condições que atendem. As variáveis de playbook, as variáveis registradas e os fatos do Ansible podem ser testados com condicionais. Existem operadores disponíveis para comparar strings, dados numéricos e valores booleanos.

    Os cenários a seguir ilustram o uso de condicionais no Ansible:

    • Um limite rígido pode ser definido em uma variável (por exemplo, min_memory) e comparado à memória disponível em um host gerenciado.

    • A saída do comando pode ser capturada e avaliada pelo Ansible para determinar se uma tarefa foi concluída antes de realizar mais ações. Por exemplo, se ocorrer uma falha em um programa, um batch será ignorado.

    • Use os fatos do Ansible para determinar a configuração da rede de hosts gerenciados e decidir qual arquivo de template será enviado (por exemplo, bonding ou troncos de rede).

    • O número de CPUs pode ser avaliado para determinar como ajustar um servidor web adequadamente.

    • Compare uma variável registrada com uma variável predefinida para determinar se um serviço foi alterado. Por exemplo, teste a soma de verificação MD5 de um arquivo de configuração do serviço para ver se o serviço foi alterado.

    Sintaxe de tarefa condicional

    A instrução when é usada para executar uma tarefa de forma condicional Ela recebe como valor a condição a ser testada. Se a condição for atendida, a tarefa é executada. Se a condição não for atendida, a tarefa é ignorada.

    Uma das condições mais simples que pode ser testada é se uma variável booleana é verdadeira ou falsa. A instrução when no seguinte exemplo faz com que a tarefa seja executada apenas se run_my_task for verdadeira:

    ---
    - name: Simple Boolean Task Demo
      hosts: all
      vars:
        run_my_task: true
      tasks:
        - name: httpd package is installed
          yum:
            name: httpd
          when: run_my_task

    O próximo exemplo é um pouco mais sofisticado e testa se a variável my_service tem um valor. Se ela tiver, o valor de my_service será usado como nome do pacote a ser instalado. Se a variável my_service não estiver definida, a tarefa será ignorada sem um erro.

    ---
    - name: Test Variable is Defined Demo
      hosts: all
      vars:
        my_service: httpd
      tasks:
        - name: "{{ my_service }} package is installed"
          yum:
            name: "{{ my_service }}"
          when: my_service is defined

    A tabela a seguir mostra algumas operações que os administradores podem usar ao trabalhar com as condicionais:

    Operação | Exemplo -- | -- Igual (o valor é uma string) | ansible_machine == "x86_64" Igual (o valor é numérico) | max_memory == 512 Menor que | min_memory < 128 Maior que | min_memory > 256 Menor ou igual a | min_memory <= 256 Maior ou igual a | min_memory >= 512 Diferente de | min_memory != 512 Variável existe | min_memory is defined Variável não existe | min_memory is not defined A variável booleana é true. Os valores de 1, True ou yes são considerados como true. | memory_available A variável booleana é false. Os valores de 0, False ou no são considerados como false. | not memory_available O valor da primeira variável está presente como um valor na lista da segunda variável | ansible_distribution in supported_distros

    A última entrada da tabela anterior pode parecer confusa à primeira vista. O exemplo a seguir ilustra como funciona.

    No exemplo, a variável ansible_distribution é um fato determinado durante a tarefa Gathering Facts e identifica a distribuição do sistema operacional do host gerenciado. A variável supported_distros foi criada pelo autor do playbook e contém a lista de distribuições do sistema operacional que o playbook suporta. Se o valor ansible_distribution estiver na lista supported_distros, a condicional será aprovada e a tarefa, executada.

    ---
    - name: Demonstrate the "in" keyword
      hosts: all
      gather_facts: yes
      vars:
        supported_distros:
          - RedHat
          - Fedora
      tasks:
        - name: Install httpd using yum, where supported
          yum:
            name: http
            state: present
          when: ansible_distribution in supported_distros

    Observe o recuo da instrução when. Como a instrução when não é uma variável de módulo, ela deve ser colocada fora do módulo e recuada no nível superior da tarefa.

    Uma tarefa é um hash/dicionário YAML e a instrução when é simplesmente mais uma chave na tarefa como o nome da tarefa e o módulo que ela usa. Uma convenção comum coloca qualquer palavra-chave when que possa estar presente depois do nome e módulo da tarefa (e argumentos de módulo).

    Teste de condições múltiplas

    Uma instrução when pode ser usada para avaliar diversas condicionais. Para isso, as condicionais podem ser combinadas com as palavras-chave and ou or e agrupadas entre parênteses.

    Os trechos a seguir mostram alguns exemplos de como expressar várias condições.

    • Se uma instrução condicional deve ser atendida quando nenhuma condição for verdadeira, use a instrução or. Por exemplo, a condição a seguir será atendida se a máquina estiver executando RedHat EnterpriseLinux ou Fedora:

      when: ansible_distribution == "RedHat" or ansible_distribution == "Fedora"
    • Com a operação and, as duas condições devem ser verdadeiras para que a instrução condicional inteira seja atendida. Por exemplo, a seguinte condição é atendida se o host remoto for o host RedHat EnterpriseLinux7.5 e o kernel instalado for a versão especificada:

      when: ansible_distribution_version == "7.5" and ansible_kernel == "3.10.0-327.el7.x86_64"

      A palavra-chave when também oferece suporte ao uso de uma lista para descrever a lista de condições. Quando é fornecida uma lista para a palavra-chave when palavra-chave, todas as condicionais são combinadas usando o operador and. O exemplo abaixo demonstra outra maneira de combinar várias instruções condicionais usando o operador and:

      when:
        - ansible_distribution_version == "7.5"
        - ansible_kernel == "3.10.0-327.el7.x86_64"

      Esse formato melhora a legibilidade, uma meta fundamental para gerar playbooks do Ansible bem escritos.

    • Instruções condicionais mais complexas podem ser expressas pelo agrupamento de condições com parênteses. Isso garante que eles sejam interpretados corretamente.

      Por exemplo, a seguinte instrução condicional será atendida se a máquina estiver executando o RedHat EnterpriseLinux7 ou Fedora28: Este exemplo usa o caractere de maior que (>) para permitir a divisão da condicional longa em várias linhas no playbook, facilitando a leitura.

      when: >
          ( ansible_distribution == "RedHat" and
            ansible_distribution_major_version == "7" )
          or
          ( ansible_distribution == "Fedora" and
          ansible_distribution_major_version == "28" )

    Combinação de loops e tarefas condicionais

    É possível combinar loops e condicionais.

    No exemplo a seguir, o pacote mariadb-server será instalado pelo módulo yum se houver um sistema de arquivos montado em / com mais de 300MB livres. O fato ansible_mounts é uma lista de dicionários, cada um representando fatos sobre o sistema de arquivos montado. O loop itera em cada dicionário na lista e a instrução condicional não é atendida a não ser que um dicionário seja encontrado representando um sistema de arquivos montado no qual ambas as condições sejam verdadeiras.

    - name: install mariadb-server if enough space on root
      yum:
        name: mariadb-server
        state: latest
      loop: "{{ ansible_mounts }}"
      when: item.mount == "/" and item.size_available > 300000000

    Quando você usar when com loop em uma tarefa, a instrução when será verificada para cada item.

    Veja outro exemplo que combina condicionais e variáveis de registro. O playbook anotado a seguir reinicia o serviço httpd apenas se o serviço postfix estiver em execução.

    ---
    - name: Restart HTTPD if Postfix is Running
      hosts: all
      tasks:
        - name: Get Postfix server status
          command: /usr/bin/systemctl is-active postfix 1
          ignore_errors: yes2
          register: result3
        - name: Restart Apache HTTPD based on Postfix status
          service:
            name: httpd
            state: restarted
          when: result.rc == 04
      | O postfix está em execução? -- | --   | Caso não esteja e ocorrer uma falha no comando, não interrompa o processamento.   | Salva as informações sobre o resultado do módulo em uma variável chamada result.   | Avalia a saída da tarefa do postfix. Se o código de saída do comando systemctl for 0, o postfix está ativo e essa tarefa reiniciará o serviço httpd.
    britho commented 3 years ago

    Objetivos

    Depois de concluir esta seção, você deverá ser capaz de implementar uma tarefa que seja executada somente quando outra tarefa alterar o host gerenciado.

    Manipuladores do Ansible

    Os módulos do Ansible são projetados para ser idempotentes. Isso significa que, em um playbook escrito adequadamente, o playbook e suas tarefas podem ser executados diversas vezes sem alterar o host gerenciado, a menos que seja necessário alterar para que o host gerenciado entre no estado desejado.

    Entretanto, quando uma tarefa altera o sistema, pode ser necessário executar outra tarefa. Por exemplo, uma alteração em um arquivo de configuração do serviço pode exigir que o serviço seja recarregado para que a configuração alterada tenha efeito.

    Manipuladores são tarefas que respondem a uma notificação acionada por outras tarefas. As tarefas só notificam seus manipuladores quando a tarefa provoca alguma mudança em um host gerenciado. Cada manipulador tem um nome globalmente exclusivo e é acionado no fim de um bloco de tarefas em um playbook. Se nenhuma tarefa notificar o manipulador pelo nome, ele não será executado. Se uma ou mais tarefas notificarem o manipulador, ele será executado exatamente uma vez depois que todas as outras tarefas na ação forem concluídas. Como os manipuladores são tarefas, os administradores podem usar os mesmos módulos nos manipuladores que usariam em qualquer outra tarefa. Normalmente, os manipuladores são usados para reinicializar hosts e reiniciar serviços.

    Os manipuladores podem ser considerados tarefas inativas, que são acionadas apenas quando explicitamente invocadas usando uma instrução notify. O trecho abaixo mostra como o servidor Apache é restaurado apenas pelo manipulador restart apache quando um arquivo de configuração é atualizado e o notifica:

    tasks:
      - name: copy demo.example.conf configuration template1
        template:
          src: /var/lib/templates/demo.example.conf.template
          dest: /etc/httpd/conf.d/demo.example.conf
        notify:2
          - restart apache3
    handlers:4
      - name: restart apache5
        service:6
          name: httpd
          state: restarted
      | A tarefa que notifica o manipulador. -- | --   | A instrução notify indica que a tarefa precisa acionar um manipulador.   | O nome do manipulador a ser executado.   | A palavra-chave handlers indica o início da lista de tarefas do manipulador.   | O nome do manipulador invocado pelas tarefas.   | O módulo a ser usado para o manipulador.

    No exemplo anterior, o manipulador restart apache será acionado quando receber uma notificação da tarefa template de que ocorreu uma alteração. Uma tarefa pode chamar mais de um manipulador em sua seção notify. O Ansible trata a instrução notify como uma matriz e itera nos nomes de manipulador:

    tasks:
      - name: copy demo.example.conf configuration template
        template:
          src: /var/lib/templates/demo.example.conf.template
          dest: /etc/httpd/conf.d/demo.example.conf
        notify:
          - restart mysql
          - restart apache
    handlers:
      - name: restart mysql
        service:
          name: mariadb
          state: restarted
      - name: restart apache
        service:
          name: httpd
          state: restarted

    Descrição dos benefícios de usar manipuladores

    Como discutido na documentação do Ansible, há alguns pontos importantes a serem lembrados ao usar os manipuladores:

    • Os manipuladores sempre são executados na ordem especificada pela seção handlers da ação. Eles não são executados na ordem em que são listados pelas instruções notify em uma tarefa, nem na ordem em que as tarefas os notificam.

    • Normalmente, os manipuladores são executados após todas as outras tarefas na ação serem concluídas. Um manipulador chamado por uma tarefa na parte tasks do playbook não será executado até que todas as tarefas em tasks sejam processadas. (Existem algumas pequenas exceções em relação a isso.)

    • Os nomes de manipulador ficam em um namespace por ação. Caso dois manipuladores tenham o mesmo nome incorretamente, apenas um será executado.

    • Mesmo que mais de uma tarefa notifique um manipulador, ele é executado apenas uma vez. Se nenhuma tarefa notificar um manipulador, ele não será executado.

    • Se uma tarefa que inclui uma instrução notify não relatar um resultado changed (por exemplo, já existe um pacote instalado e a tarefa relata ok), o manipulador não será notificado. O manipulador será ignorado a não ser que outra tarefa o notifique. O Ansible notifica os manipuladores apenas se a tarefa relata o status changed.

    Os manipuladores devem executar uma ação adicional quando uma tarefa faz uma alteração em um host gerenciado. Eles não devem ser usados como substitutos para tarefas normais.

    britho commented 3 years ago

    Neste exercício, você implantará manipuladores em playbooks

    Resultados

    Você deverá ser capaz de definir manipuladores em playbooks e notificá-los de alterações de configuração.

    Em workstation, execute lab control-handlers start para configurar o ambiente para o exercício. Este script cria o diretório do projeto /home/student/control-handlers e faz o download dos arquivos de configuração e inventário de host do Ansible necessários para o exercício. O diretório do projeto também contém um playbook parcialmente concluído, configure_db.yml.

    [student@workstation ~]$ lab control-handlers start
    1. Em workstation.lab.example.com, abra um novo terminal e vá para o diretório de projetos /home/student/control-handlers.

      [student@workstation ~]$ cd ~/control-handlers
      [student@workstation control-handlers]$ 
    2. Nesse diretório, use um editor de textos para editar o arquivo do playbook configure_db.yml. Esse playbook instala e configura um servidor de banco de dados. Quando a configuração do servidor de banco de dados é alterada, o playbook aciona a reinicialização do serviço de banco de dados e configura a senha administrativa do banco de dados.

      1. Usando um editor de texto, revise o playbook configure_db.yml. Ele começa com a inicialização de algumas variáveis:

        ---
        - name: MariaDB server is installed
          hosts: databases
          vars:
            db_packages: 1
              - mariadb-server
              - python3-PyMySQL
            db_service: mariadb 2
            resources_url: http://materials.example.com/labs/control-handlers 3
            config_file_url: "{{ resources_url }}/my.cnf.standard" 4
            config_file_dst: /etc/my.cnf 5
          tasks:
          | db_packages: define o nome dos pacotes a serem instalados para o serviço de banco de dados. -- | --   | db_service: define o nome do serviço de banco de dados.   | resources_url: representa o URL do diretório de recursos em que os arquivos de configuração remota estão localizados.   | config_file_url: representa o URL do arquivo de configuração do banco de dados a ser instalado.   | config_file_dst: local do arquivo de configuração instalado nos hosts gerenciados.
      2. No arquivo configure_db.yml defina uma tarefa que usa o módulo yum para instalar os pacotes de banco de dados necessários como definido pela variável db_packages. Se a tarefa alterar o sistema, o banco de dados não será instalado e você precisará notificar o manipulador set db password para definir seu usuário inicial e senha do banco de dados. Lembre-se de que a tarefa do manipulador, se ele for notificado, não será executada até que todas as tarefas da seção tasks sejam executadas.

        A tarefa deve ser a seguinte:

          tasks:
            - name: "{{ db_packages }} packages are installed"
              yum:
                name: "{{ db_packages }}"
                state: present
              notify:
                - set db password
      3. Adicione uma tarefa para iniciar e ativar o serviço de banco de dados. A tarefa deve ser a seguinte:

            - name: Make sure the database service is running
              service:
                name: "{{ db_service }}"
                state: started
                enabled: true
      4. Adicione uma tarefa para baixar de my.cnf.standard para /etc/my.cnf no host gerenciado usando o módulo get_url. Adicione uma condição que notifique o manipulador restart db service para reiniciar o serviço de banco de dados após uma alteração no arquivo de configuração. A tarefa deve ser a seguinte:

            - name: The {{ config_file_dst }} file has been installed
              get_url:
                url: "{{ config_file_url }}"
                dest: "{{ config_file_dst }}"
                owner: mysql
                group: mysql
                force: yes
              notify:
                - restart db service
      5. Adicione a palavra-chave handlers para determinar o início da lista de tarefas do manipulador. Defina o primeiro manipulador restart db service, que reinicia o serviço mariadb. O resultado deve ser este:

          handlers:
            - name: restart db service
              service:
                name: "{{ db_service }}"
                state: restarted
      6. Defina o segundo manipulador set db password, que define a senha administrativa do serviço de banco de dados. O manipulador usa o módulo mysql_user para executar o comando. O manipulador deverá ficar assim:

            - name: set db password
              mysql_user:
                name: root
                password: redhat

      Quando concluído, o playbook deverá ficar desta forma:

      ---
      - name: MariaDB server is installed
        hosts: databases
        vars:
          db_packages:
            - mariadb-server
            - python3-PyMySQL
          db_service: mariadb
          resources_url: http://materials.example.com/labs/control-handlers
          config_file_url: "{{ resources_url }}/my.cnf.standard"
          config_file_dst: /etc/my.cnf
        tasks:
          - name: "{{ db_packages }} packages are installed"
            yum:
              name: "{{ db_packages }}"
              state: present
            notify:
              - set db password
          - name: Make sure the database service is running
            service:
              name: "{{ db_service }}"
              state: started
              enabled: true
          - name: The {{ config_file_dst }} file has been installed
            get_url:
              url: "{{ config_file_url }}"
              dest: "{{ config_file_dst }}"
              owner: mysql
              group: mysql
              force: yes
            notify:
              - restart db service
        handlers:
          - name: restart db service
            service:
              name: "{{ db_service }}"
              state: restarted
          - name: set db password
            mysql_user:
              name: root
              password: redhat
    3. Antes de executar o playbook, verifique se a sintaxe está correta executando ansible-playbook com a opção --syntax-check. Se ela relatar algum erro, corrija-o antes de ir para a próxima etapa. Você verá uma saída semelhante à seguinte:

      [student@workstation control-handlers]$ ansible-playbook configure_db.yml \
      > --syntax-check
      playbook: configure_db.yml
    4. Execute o playbook configure_db.yml. A saída mostra que os manipuladores estão sendo executados.

      [student@workstation control-handlers]$ ansible-playbook configure_db.yml
      PLAY [Installing MariaDB server] *********************************************
      TASK [Gathering Facts] *******************************************************
      ok: [servera.lab.example.com]
      TASK [['mariadb-server', 'python3-PyMySQL'] packages are installed] **********
      changed: [servera.lab.example.com]
      TASK [Make sure the database service is running] *****************************
      changed: [servera.lab.example.com]
      TASK [The /etc/my.cnf file has been installed] *******************************
      changed: [servera.lab.example.com]
      RUNNING HANDLER [restart db service] *****************************************
      changed: [servera.lab.example.com]
      RUNNING HANDLER [set db password] ********************************************
      changed: [servera.lab.example.com]
      PLAY RECAP *******************************************************************
      servera.lab.example.com    : ok=6    changed=5    unreachable=0    failed=0
    5. Execute o playbook novamente.

      [student@workstation control-handlers]$ ansible-playbook configure_db.yml
      PLAY [Installing MariaDB server] *********************************************
      TASK [Gathering Facts] *******************************************************
      ok: [servera.lab.example.com]
      TASK [['mariadb-server', 'python3-PyMySQL'] packages are installed] **********
      ok: [servera.lab.example.com]
      TASK [Make sure the database service is running] *****************************
      ok: [servera.lab.example.com]
      TASK [The /etc/my.cnf file has been installed] *******************************
      ok: [servera.lab.example.com]
      PLAY RECAP *******************************************************************
      servera.lab.example.com    : ok=4    changed=0    unreachable=0    failed=0

      Nesse momento, os manipuladores são ignorados. Caso o arquivo de configuração remoto seja alterado no futuro, a execução do playbook acionará o manipulador restart db service, mas não o manipulador set db password.

    Encerramento

    Em workstation, execute o script lab control-handlers finish para limpar os recursos criados neste exercício.

    [student@workstation ~]$ lab control-handlers finish

    Isso conclui o exercício orientado.

    britho commented 3 years ago

    Objetivos

    Depois de concluir esta seção, você deverá ser capaz de controlar o que acontece quando há falha em uma tarefa e quais condições fazem com que uma tarefa falhe. Gerenciamento de erros de tarefas em ações

    O Ansible avalia o código de retorno de cada tarefa para determinar se a tarefa foi bem-sucedida ou apresentou erro. Normalmente, quando ocorre uma falha em uma tarefa, o Ansible imediatamente aborta a ação nesse host, ignorando todas as tarefas subsequentes.

    Entretanto, algumas vezes, você quer que a ação de um playbook prossiga mesmo que ocorra uma falha na tarefa. Por exemplo, você pode esperar que uma tarefa em particular poderia falhar e pode desejar recuperá-la executando alguma outra tarefa de forma condicional. Há diversos recursos do Ansible que podem ser usados para gerenciar os erros em tarefas.

    Ignorar falhas em tarefas

    Por padrão, se ocorrer uma falha em uma tarefa, a ação é abortada. Entretanto, esse comportamento pode ser substituído por ignorar as tarefas que falharem. Você pode usar a palavra-chave ignore_errors em uma tarefa para conseguir isso.

    O trecho a seguir mostra como usar ignore_errors em uma tarefa para prosseguir a execução do playbook no host mesmo que ocorra uma falha na tarefa. Por exemplo, se o pacote notapkg não existir, ocorre uma falha no módulo yum. Porém, definir ignore_errors como yes permite que a execução continue.

    Execução forçada de manipuladores após a falha da tarefa

    Normalmente, quando uma tarefa falha e a ação é abortada no host, qualquer manipulador que tiver sido notificado por tarefas anteriores no host não será executado. Se você configurar a palavra-chave force_handlers: yes na ação, os manipuladores notificados são chamados, mesmo que a ação tenha sido abortada devido a uma falha de uma tarefa posterior.

    O trecho abaixo mostra como usar a palavra-chave force_handlers em uma ação para forçar a execução do manipulador mesmo que ocorra uma falha em uma tarefa:


    Lembre-se de que os manipuladores são notificados quando uma tarefa relata um resultado changed, mas não são notificados quando ela relata um resultado ok ou failed.

    Especificação de condições de falha de tarefas

    Você pode usar a palavra-chave failed_when em uma tarefa para especificar quais condições indicam que ocorreu uma falha na tarefa. Isso é frequentemente usado com módulos de comando que podem executar com êxito um comando, mas a saída do comando indica uma falha.

    Por exemplo, você pode executar um script que tenha como saída uma mensagem de erro e usar essa mensagem para definir o estado de falha da tarefa. O seguinte trecho mostra como a palavra-chave failed_when pode ser usada em uma tarefa:

    tasks:

    O módulo fail também pode ser usado para forçar a falha de uma tarefa. Como alternativa, o cenário acima pode ser escrito como duas tarefas:

    tasks:

    Você pode usar o módulo fail para fornecer uma mensagem de falha clara para a tarefa. Essa abordagem também permite atrasar a falha, possibilitando a execução de tarefas intermediárias para concluir ou reverter outras alterações.

    Especificação de quando uma tarefa relata resultados changed

    Quando uma tarefa faz uma alteração em um host gerenciado, ela relata o estado changed e notifica os manipuladores. Quando uma tarefa não precisa fazer uma alteração, ela relata ok e não notifica os manipuladores.

    A palavra-chave changed_when pode ser usada para controlar quando uma tarefa relata que ela foi alterada. Por exemplo, o módulo shell no próximo exemplo está sendo usado para obter credenciais do Kerberos que serão usadas por tarefas subsequentes. Normalmente, ela sempre relataria changed quando fosse executada. Para suprimir essa alteração, a opção changed_when: false é configurada para que relate apenas ok ou failed.

    O seguinte exemplo usa o módulo shell para relatar changed com base na saída do módulo que é coletado por uma variável registrada:

    tasks:

    handlers:

    Os blocos e o tratamento de erros do Ansible

    Nos playbooks, blocos são cláusulas que agrupam tarefas de forma lógica e podem ser usadas para controlar como as tarefas são executadas. Por exemplo, um bloco de tarefas pode ter a palavra-chave when para aplicar uma condicional a múltiplas tarefas:

    Os blocos também permitem o tratamento de erros em combinação com as instruções rescue e always. Se ocorrer uma falha em qualquer tarefa em um bloco, as tarefas em seu bloco rescue são executadas para fazer a recuperação. Depois que as tarefas na cláusula block forem executadas, assim como as tarefas na cláusula rescue se houver uma falha, as tarefas na cláusula always serão executadas. Para resumir:

    block: define as principais tarefas a serem executadas.
    
    rescue: define as tarefas que serão executadas se ocorrer uma falha naquelas definidas na cláusula block.
    
    always: define as tarefas que serão sempre executadas, independentemente do êxito ou da falha das tarefas definidas nas cláusulas block e rescue. 

    O exemplo a seguir mostra como implementar um bloco em um playbook. Mesmo que ocorra uma falha nas tarefas definidas na cláusula block, as tarefas definidas nas cláusulas rescue e always são executadas.

    tasks:

    A condição when em uma cláusula block também se aplica às cláusulas rescue e always, se existentes.

    Error Handling in Playbooks — Ansible Documentation

    Error Handling — Blocks — Ansible Documentation

    britho commented 3 years ago

    Neste exercício, você explorará diferentes maneiras de controlar falhas de tarefas em um playbook do Ansible.

    Resultados

    Você deverá ser capaz de:

    Ignorar comandos com falha durante a execução dos playbooks.
    
    Forçar a execução dos manipuladores.
    
    Substituir o que constituir uma falha nas tarefas.
    
    Substituir o estado changed das tarefas.
    
    Implementar block, rescue e always em playbooks. 

    Em workstation, execute o script de início do laboratório para confirmar se o ambiente está pronto para que o laboratório comece. Esse script cria o diretório de trabalho, /home/student/control-errors.

    [student@workstation ~]$ lab control-errors start

    Em workstation.lab.example.com, altere para o diretório de projetos /home/student/control-errors.
    
    [student@workstation ~]$ cd ~/control-errors
    [student@workstation control-errors]$ 
    
    O script do laboratório criou um arquivo de configuração do Ansible e um arquivo de inventário que contém o servidor servera.lab.example.com no grupo databases. Revise o arquivo antes de continuar.
    
    Crie o playbook playbook.yml que contém uma ação com duas tarefas. Escreva a primeira tarefa com um erro deliberado que cause falha.
    
        Abra o playbook em um editor de texto. Defina três variáveis: web_package com o valor http, db_package com o valor mariadb-server e db_service com o valor mariadb. Essas variáveis serão usadas para instalar os pacotes necessários e iniciar o servidor.
    
        O valor http é um erro intencional no nome do pacote. O arquivo deverá exibir o seguinte texto:
    
        ---
        - name: Task Failure Exercise
          hosts: databases
          vars:
            web_package: http
            db_package: mariadb-server
            db_service: mariadb
    
        Defina duas tarefas que usam o mesmo módulo yum e as duas variáveis, web_package e db_package. As tarefas instalarão os pacotes necessários. As tarefas devem ser as seguintes:
    
          tasks:
            - name: Install {{ web_package }} package
              yum:
                name: "{{ web_package }}"
                state: present
    
            - name: Install {{ db_package }} package
              yum:
                name: "{{ db_package }}"
                state: present
    
    Execute o playbook e observe a saída da ação.
    
    [student@workstation control-errors]$ ansible-playbook playbook.yml
    
    PLAY [Task Failure Exercise] ***************************************************
    
    TASK [Gathering Facts] *********************************************************
    ok: [servera.lab.example.com]
    
    TASK [Install http package] ****************************************************
    fatal: [servera.lab.example.com]: FAILED! => {"changed": false, "failures": ["No package http available."], "msg": "Failed to install some of the specified packages", "rc": 1, "results": []}
    
    PLAY RECAP *********************************************************************
    servera.lab.example.com    : ok=1    changed=0    unreachable=0    failed=1 
    
    Ocorreu uma falha na tarefa porque não há um pacote existente chamado http. Como ocorreu uma falha na primeira tarefa, a segunda tarefa não foi executada.
    
    Atualize a primeira tarefa para que ignore erros adicionando a palavra-chave ignore_errors. As tarefas devem ser as seguintes:
    
      tasks:
        - name: Install {{ web_package }} package
          yum:
            name: "{{ web_package }}"
            state: present
          ignore_errors: yes
    
        - name: Install {{ db_package }} package
          yum:
            name: "{{ db_package }}"
            state: present
    
    Execute o playbook novamente e observe a saída da ação.
    
    [student@workstation control-errors]$ ansible-playbook playbook.yml
    
    PLAY [Task Failure Exercise] ***************************************************
    
    TASK [Gathering Facts] *********************************************************
    ok: [servera.lab.example.com]
    
    TASK [Install http package] ****************************************************
    fatal: [servera.lab.example.com]: FAILED! => {"changed": false, "failures": ["No package http available."], "msg": "Failed to install some of the specified packages", "rc": 1, "results": []}
    ...ignoring
    
    TASK [Install mariadb-server package] ******************************************
    changed: [servera.lab.example.com]
    
    PLAY RECAP *********************************************************************
    servera.lab.example.com    : ok=3    changed=1    unreachable=0    failed=0
    
    Apesar de ter ocorrido uma falha na primeira tarefa, o Ansible executou a segunda.
    
    Nesta etapa, configuraremos uma palavra-chave block para que você teste como ela funciona.
    
        Atualize o playbook aninhando a primeira tarefa em uma cláusula block. Remova a linha que define ignore_errors: yes. O bloco deve ficar assim:
    
            - name: Attempt to set up a webserver
              block:
                - name: Install {{ web_package }} package
                  yum:
                    name: "{{ web_package }}"
                    state: present
    
        Aninhe a tarefa que instala o pacote mariadb-server em uma cláusula rescue. A tarefa será executada se ocorrer uma falha na tarefa listada na cláusula block. A cláusula block deve ficar assim:
    
              rescue:
                - name: Install {{ db_package }} package
                  yum:
                    name: "{{ db_package }}"
                    state: present
    
        Por fim, adicione uma cláusula always para iniciar o servidor de banco de dados após a instalação usando o módulo service. A cláusula deve ser a seguinte:
    
              always:
                - name: Start {{ db_service }} service
                  service:
                    name: "{{ db_service }}"
                    state: started
    
        A seção da tarefa concluída deve ficar assim:
    
          tasks:
            - name: Attempt to set up a webserver
              block:
                - name: Install {{ web_package }} package
                  yum:
                    name: "{{ web_package }}"
                    state: present
              rescue:
                - name: Install {{ db_package }} package
                  yum:
                    name: "{{ db_package }}"
                    state: present
              always:
                - name: Start {{ db_service }} service
                  service:
                    name: "{{ db_service }}"
                    state: started
    
    Agora, execute o playbook novamente e observe a saída.
    
        Execute o playbook. Ocorrerá uma falha na tarefa no bloco que garante que web_package está instalada, o que fará com que a tarefa no bloco rescue seja executada. Então, a tarefa no bloco always é executada.
    
        [student@workstation control-errors]$ ansible-playbook playbook.yml
    
        PLAY [Task Failure Exercise] ***************************************************
    
        TASK [Gathering Facts] *********************************************************
        ok: [servera.lab.example.com]
    
        TASK [Install http package] ****************************************************
        fatal: [servera.lab.example.com]: FAILED! => {"changed": false, "failures": ["No package http available."], "msg": "Failed to install some of the specified packages", "rc": 1, "results": []}
    
        TASK [Install mariadb-server package] ******************************************
        ok: [servera.lab.example.com]
    
        TASK [Start mariadb service] ***************************************************
        changed: [servera.lab.example.com]
    
        PLAY RECAP *********************************************************************
        servera.lab.example.com    : ok=3    changed=1    unreachable=0    failed=1
    
        Edite o playbook, corrigindo o valor da variável web_package para que leia httpd. Isso fará com que a tarefa no bloco seja bem-sucedida da próxima vez que você executar o playbook.
    
          vars:
            web_package: httpd
            db_package: mariadb-server
            db_service: mariadb
    
        Execute o playbook novamente. Desta vez, não ocorrerá falha na tarefa do bloco. Isso faz com que a tarefa na seção rescue seja ignorada. A tarefa em always ainda será executada.
    
        [student@workstation control-errors]$ ansible-playbook playbook.yml
    
        PLAY [Task Failure Exercise] ***************************************************
    
        TASK [Gathering Facts] *********************************************************
        ok: [servera.lab.example.com]
    
        TASK [Install httpd package] ***************************************************
        changed: [servera.lab.example.com]
    
        TASK [Start mariadb service] ***************************************************
        ok: [servera.lab.example.com]
    
        PLAY RECAP *********************************************************************
        servera.lab.example.com    : ok=3    changed=1    unreachable=0    failed=0
    
    Esta etapa explora como controlar a condição que faz com que uma tarefa seja relatada como changed para o host gerenciado.
    
        Edite o playbook para que adicione duas tarefas no início da ação, precedendo o block. A primeira tarefa usa o módulo command para executar o comando date e registrar o resultado na variável command_result. A segunda tarefa usa o módulo debug para imprimir a saída padrão do comando da primeira tarefa.
    
          tasks:
            - name: Check local time
              command: date
              register: command_result
    
            - name: Print local time
              debug:
                var: command_result.stdout
    
        Execute o playbook. Você verá que a primeira tarefa que executa o módulo command relatará changed, mesmo se ela não tiver alterado o sistema remoto. Ela só coletou informações sobre o tempo. Isso se deve ao fato de o módulo command não saber distinguir entre um comando que coleta dados e um comando que altera o estado.
    
        [student@workstation control-errors]$ ansible-playbook playbook.yml
    
        PLAY [Task Failure Exercise] ***************************************************
    
        TASK [Gathering Facts] *********************************************************
        ok: [servera.lab.example.com]
    
        TASK [Check local time] ********************************************************
        changed: [servera.lab.example.com]
    
        TASK [Print local time] ********************************************************
        ok: [servera.lab.example.com] => {
            "command_result.stdout": "mié mar 27 08:07:08 EDT 2019"
        }
    
        TASK [Install httpd package] ***************************************************
        ok: [servera.lab.example.com]
    
        TASK [Start mariadb service] ***************************************************
        ok: [servera.lab.example.com]
    
        PLAY RECAP *********************************************************************
        servera.lab.example.com    : ok=5    changed=1    unreachable=0    failed=0
    
        Se você executar o playbook novamente, a tarefa Check local time relatará changed novamente.
    
        Essa tarefa command não deve relatar changed toda vez que for executada porque ela não está alterando o host gerenciado. Como você sabe que a tarefa nunca alterará o host gerenciado, adicione a linha changed_when: false à tarefa para suprimir a alteração.
    
          tasks:
            - name: Check local time
              command: date
              register: command_result
              changed_when: false
    
            - name: Print local time
              debug:
                var: command_result.stdout
    
        Execute o playbook mais uma vez e observe se a tarefa agora relata ok, mas ainda está sendo executada e salvando o tempo na variável.
    
        [student@workstation control-errors]$ ansible-playbook playbook.yml
    
        PLAY [Task Failure Exercise] ***************************************************
    
        TASK [Gathering Facts] *********************************************************
        ok: [servera.lab.example.com]
    
        TASK [Check local time] ********************************************************
        ok: [servera.lab.example.com]
    
        TASK [Print local time] ********************************************************
        ok: [servera.lab.example.com] => {
            "command_result.stdout": "mié mar 27 08:08:36 EDT 2019"
        }
    
        TASK [Install httpd package] ***************************************************
        ok: [servera.lab.example.com]
    
        TASK [Start mariadb service] ***************************************************
        ok: [servera.lab.example.com]
    
        PLAY RECAP *********************************************************************
        servera.lab.example.com    : ok=5    changed=0    unreachable=0    failed=0
    
    Como exercício final, edite o playbook para explorar como a palavra-chave failed_when interage com as tarefas.
    
        Edite a tarefa Install {{ web_package }} package para que ela relate como se tivesse ocorrido uma falha quando web_package tiver o valor httpd. Já que este é o caso, a tarefa relatará uma falha quando você executar a ação.
    
        Tenha cuidado com seu recuo para garantir que a palavra-chave esteja corretamente configurada na tarefa.
    
            - block:
                - name: Install {{ web_package }} package
                  yum:
                    name: "{{ web_package }}"
                    state: present
                  failed_when: web_package == "httpd"
    
        Execute o playbook.
    
        [student@workstation control-errors]$ ansible-playbook playbook.yml
    
        PLAY [Task Failure Exercise] ***************************************************
    
        TASK [Gathering Facts] *********************************************************
        ok: [servera.lab.example.com]
    
        TASK [Check local time] ********************************************************
        ok: [servera.lab.example.com]
    
        TASK [Print local time] ********************************************************
        ok: [servera.lab.example.com] => {
            "command_result.stdout": "mié mar 27 08:09:35 EDT 2019"
        }
    
        TASK [Install httpd package] ***************************************************
        fatal: [servera.lab.example.com]: FAILED! => {"changed": false, "failed_when_result": true, "msg": "Nothing to do", "rc": 0, "results": ["Installed: httpd"]}
    
        TASK [Install mariadb-server package] ******************************************
        ok: [servera.lab.example.com]
    
        TASK [Start mariadb service] ***************************************************
        ok: [servera.lab.example.com]
    
        PLAY RECAP *********************************************************************
        servera.lab.example.com    : ok=5    changed=0    unreachable=0    failed=1
    
        Analise cuidadosamente a saída. A tarefa Install httpd package relata que ocorreu uma falha, mas ela, na verdade, foi executada e garantiu que o pacote fosse instalado primeiro. A palavra-chave failed_when altera o status que a tarefa relatar depois que a tarefa for executada, mas não altera o comportamento da tarefa em si.
    
        Contudo, a falha relatada pode alterar o comportamento do resto da ação. Já que a tarefa estava em um bloco e relatou que ocorreu uma falha, a tarefa Install mariadb-server package na seção rescue do bloco foi executada. 

    Encerramento

    Em workstation, execute o script lab control-errors finish para limpar os recursos criados neste exercício.

    [student@workstation ~]$ lab control-errors finish

    Isso conclui o exercício orientado.

    britho commented 3 years ago

    Lista de verificação de desempenho

    Neste laboratório, você instalará o servidor web Apache e o protegerá usando mod_ssl. Você usará condições, manipuladores e controle de falhas de tarefas no seu playbook para implantar o ambiente.

    Resultados

    Você deverá ser capaz de definir condicionais nos playbooks do Ansible, configurar loops que iteram em elementos, definir manipuladores em playbooks e controlar erros de tarefas.

    Faça login como o usuário student na workstation e execute lab control-review start. Esse script garante que o host gerenciado, serverb, seja acessível na rede. Isso também garante que o arquivo de configuração Ansible e o inventário corretos estejam instalados no nó de controle.

    [student@workstation ~]$ lab control-review start

    Na workstation, mude para o diretório do projeto /home/student/control-review.
    
    [student@workstation ~]$ cd ~/control-review
    [student@workstation control-review]$ 

    O diretório de projeto contém um playbook parcialmente concluído, playbook.yml. Usando um editor de texto, adicione uma tarefa que use o módulo failed no comentário #Fail Fast Message. Forneça um nome apropriado para a tarefa. Ela deverá ser executada somente quando o sistema remoto não atender aos requisitos mínimos.

    Os requisitos mínimos para o host remoto estão listados abaixo:

    Tem pelo menos a quantidade de RAM especificada pela variável min_ram_mb. A variável min_ram_mb é definida no arquivo vars.yml e tem o valor 256.
    
    Está executando o RedHat EnterpriseLinux. 

    A tarefa concluída corresponde a:

    tasks:

    Fail Fast Message

    - name: Show Failed System Requirements Message
      fail:
        msg: "The {{ inventory_hostname }} did not meet minimum reqs."
      when: >
        ansible_memtotal_mb < min_ram_mb or
        ansible_distribution != "RedHat"

    Adicione uma única tarefa ao playbook no comentário #Install all Packages para instalar a versão mais recente dos pacotes ausentes. Os pacotes obrigatórios são especificados pela variável packages, que é definida no arquivo vars.yml.

    O nome da tarefa deve ser Ensure required packages are present.

    A tarefa concluída corresponde a:

    #Install all Packages
    - name: Ensure required packages are present
      yum:
        name: "{{ packages }}"
        state: latest

    Adicione uma única tarefa ao playbook no comentário #Enable and start services para iniciar todos os serviços. Todos os serviços especificados pela variável services, que é definida no arquivo vars.yml, devem ser iniciados e ativados. Forneça um nome apropriado para a tarefa.

    A tarefa concluída corresponde a:

    #Enable and start services
    - name: Ensure services are started and enabled
      service:
        name: "{{ item }}"
        state: started
        enabled: yes
      loop: "{{ services }}"

    Adicione um bloco de tarefas ao playbook no comentário #Block of config tasks. Esse bloco contém duas tarefas:

    Uma tarefa para garantir que o diretório especificado pela variável ssl_cert_dir existe no host remoto. Esse diretório armazena os certificados do servidor web.
    
    Uma tarefa para copiar todos os arquivos especificados pela variável web_config_files para o host remoto. Examine a estrutura da variável web_config_files no arquivo vars.yml. Configure a tarefa para copiar cada arquivo para o destino correto no host remoto.
    
    Esta tarefa deverá acionar o manipulador restart web service se algum desses arquivos for alterado no servidor remoto. 

    Além disso, uma tarefa de depuração será executada se uma das duas tarefas acima falhar. Nesse caso, a tarefa imprimirá a mensagem: One or more of the configuration changes failed, but the web service is still active.

    Forneça um nome apropriado para todas as tarefas.

    O bloco de tarefas concluído corresponde a:

    #Block of config tasks
    - name: Setting up the SSL cert directory and config files
      block: 
        - name: Create SSL cert directory
          file:
            path: "{{ ssl_cert_dir }}"
            state: directory
    
        - name: Copy Config Files
          copy:
            src: "{{ item.src }}"
            dest: "{{ item.dest }}"
          loop: "{{ web_config_files }}"
          notify: restart web service
    
      rescue:
        - name: Configuration Error Message
          debug:
            msg: >
              One or more of the configuration
              changes failed, but the web service
              is still active.

    O playbook configura o host remoto para ouvir solicitações HTTPS padrão. Adicione uma única tarefa ao playbook no comentário #Configure the firewall para configurar firewalld.

    Essa tarefa deve garantir que o host remoto permita conexões HTTP e HTTPS padrão. As alterações de configuração devem entrar em vigor imediatamente e persistir após uma reinicialização do sistema. Forneça um nome apropriado para a tarefa.

    A tarefa concluída corresponde a:

    #Configure the firewall
    - name: ensure web server ports are open
      firewalld:
        service: "{{ item }}"
        immediate: true
        permanent: true
        state: enabled
      loop:
        - http
        - https

    Defina o manipulador restart web service.

    Quando for acionada, essa tarefa deve reiniciar o serviço web definido pela variável web_service, definida no arquivo vars.yml.

    A seção handlers é adicionada ao final do playbook.

    handlers:

    O playbook completo contém:


    No diretório do projeto, ~/control-review, execute o playbook playbook.yml. O playbook deve ser executado sem erros e acionar a execução da tarefa do manipulador.

    [student@workstation control-review]$ ansible-playbook playbook.yml

    PLAY [Playbook Control Lab] **

    TASK [Gathering Facts] *** ok: [serverb.lab.example.com]

    TASK [Show Failed System Requirements Message] *** skipping: [serverb.lab.example.com]

    TASK [Ensure required packages are present] ** changed: [serverb.lab.example.com]

    TASK [Ensure services are started and enabled] *** changed: [serverb.lab.example.com] => (item=httpd) ok: [serverb.lab.example.com] => (item=firewalld)

    TASK [Create SSL cert directory] ***** changed: [serverb.lab.example.com]

    TASK [Copy Config Files] ***** changed: [serverb.lab.example.com] => (item={'src': 'server.key', 'dest': '/etc/httpd/conf.d/ssl'}) changed: [serverb.lab.example.com] => (item={'src': 'server.crt', 'dest': '/etc/httpd/conf.d/ssl'}) changed: [serverb.lab.example.com] => (item={'src': 'ssl.conf', 'dest': '/etc/httpd/conf.d'}) changed: [serverb.lab.example.com] => (item={'src': 'index.html', 'dest': '/var/www/html'})

    TASK [ensure web server ports are open] ** changed: [serverb.lab.example.com] => (item=http) changed: [serverb.lab.example.com] => (item=https)

    RUNNING HANDLER [restart web service] **** changed: [serverb.lab.example.com]

    PLAY RECAP *** serverb.lab.example.com : ok=7 changed=6 unreachable=0 failed=0

    Verifique se o servidor web agora responde a solicitações HTTPS, usando o certificado personalizado autoassinado para criptografar a conexão. A resposta do servidor web deve corresponder à string Configured for both HTTP and HTTPS.

    [student@workstation control-review]$ curl -k -vvv https://serverb.lab.example.com

    Avaliação

    Execute o comando lab control-review grade em workstation para confirmar o êxito deste exercício. Corrija todas as falhas relatadas e execute novamente o script até que ele seja concluído com êxito.

    [student@workstation ~]$ lab control-review grade

    Encerramento

    Execute o comando lab control-review finish para fazer uma limpeza após o laboratório.

    [student@workstation ~]$ lab control-review finish

    Isso conclui o laboratório.

    britho commented 3 years ago

    Neste capítulo, você aprendeu que:

    Os loops são usados para iterar em um conjunto de valores, por exemplo, uma lista simples de strings ou uma lista de hashes ou dicionários.
    
    As condicionais são usadas para executar tarefas ou ações apenas quando certas condições forem atendidas.
    
    Manipuladores são tarefas especiais e são executados ao final da ação se notificados por outras tarefas.
    
    Os manipuladores são notificados apenas quando uma tarefa informa que alterou algo em um host gerenciado.
    
    As tarefas são configuradas para controlar condições de erro ignorando uma falha de tarefa, forçando a chamada de manipuladores mesmo que uma tarefa apresente falha, marcando uma tarefa como com falha quando ela teve êxito ou substituindo o comportamento que faz com que uma tarefa seja marcada como alterada.
    
    Os blocos são usados para agrupar tarefas como uma unidade e executar outras tarefas dependendo do êxito ou falha das tarefas no bloco.