ANSIBLE SERIES: YML … add sudo(ers) >> no prompt or ask

Olá! Como vai? Muito prazer, Victor é o meu nome … Ou @vicrlda, se preferir … Navegando pela internet em busca de inspiração, situações, exemplos práticos para exercitar e solucionar via ANSIBLE ??? É um sysadmin ou desenvolvedor que anseia o cargo de Engenheiro Devops / SRE ?? Por favor, peço que me deixe cumprimentá-lo e lhe dar os parabéns, pois o caro leitor (você) veio ao lugar certo! Seja mais do que bem-vindo ao @machinesbecomeservices.com … A partir de hoje, serei o seu humilde anfitrião / companheiro / fiel escudeiro nessa incrível jornada que chamo de “estrada para a automação”

Em contrapartida, se por acaso você é um veterano, não pera (…) Melhor dizendo, se já é um velho conhecido meu e do BLOG, por favor pule para a próxima etapa … Ops! Quero dizer, seção (hahaha)

Ambiente: Máquinas e Pré-requisitos

Para total compreensão e sentido, por favor, peço que…

Recém-chegados, leiam o seguinte post, e partam desse princípio:

https://machinesbecomeservices.com/2021/09/21/vicrlda-dual-boot-pop_os-gnome-boxes-vpn-checkpoint-e-novo-workflow/

Longa datas, revisem esse outro post, e iniciem suas VMs do ponto exato em que paramos:

https://machinesbecomeservices.com/2020/12/01/ansible-series-hands-on-01-modo-cli-e-hello-yml-1st-playbook/

Quem ainda não entendeu nada, acompanhe a śerie ANSIBLE desde o começo 😉

https://machinesbecomeservices.com/?s=ansible

GNOME Boxes, uma solução All-in-One: Download nativo de ISOs + Criação das instâncias + Uso integrado

Com o Boxes, não é mais necessário sair da ferramenta em busca de outros meios/softwares para baixar, instalar, configurar, usar máquinas virtuais. Destaque principalmente, e especialmente, para a primeira etapa que é fazer o download das ISOs, onde normalmente acessaríamos os respectivos sites oficiais de cada uma, e obteríamos via métodos tradicionais como o próprio GET ou até mesmo TORRENT. Bem, dito isso, vamos abri-lo agora para conhecê-lo um pouco melhor e ver como as coisas transcorrem, além de claro, testemunhar toda a sua simplicidade, praticidade e comodidade. Teclado e mouse em mãos, vem comigo!

Uma vez baixado via loja de aplicativos linux favorita (deb, rpm, flatpak, snapp), abra-o pela primeira vez e verá a seguinte tela:

Figura 01: GNOME Boxes v.40.2

Clique no ícone + para iniciar o processo de criação. Observe que a janela aberta traz consigo três opções principais, que são: (a) os sistemas operacionais mais baixados naquele momento, por outros usuários da plataforma; (b) lista de todos os outros SOs que não aparecem pois não figuram no ranking Top 3 anterior; e (c) finalmente instalar a partir de um arquivo .ISO previamente baixado e disponível localmente.

Figura 02. Opções e formas de iniciar o processo

Escolha a segunda opção, “Navegue e pesquise sistemas operacionais para instalar”.

Figura 03. Listagem dos Sistemas Operacionais

Procure por ‘centos’ na barra de pesquisa:

Figura 04. Busca por ‘centos’

Simularemos um ambiente heterogêneo, então isso significa distros variadas, com versões diferentes. Selecione CentOS 7 x86_64 (netinst) :

Figura 05. Download automático da ISO

Aguarde a conclusão do download, iniciado automaticamente, para logo em seguida começar o que o Boxes chama de “instalação expressa”. Informe um nome de usuário, e abaixo clique em adicionar senha, digitando a mesma no campo aberto:

Figura 06. Instalação Expressa / Usuário e senha

Na próxima tela, revisar e criar, defina a quantidade de RAM e tamanho máximo do HD, ambos virtuais. Para efeitos de teste, e considerando que essas máquinas serão sempre “descartáveis”, ou seja, meros templates clonados de um git, GitHub ou GitLAB via Ansible/AWX/Tower … Sinta-se livre para escolher a configuração que mais lhe agrada, e que seu hardware atual permite. Mas, tenha em mente que apenas 512 MB de RAM e 10 GB de HD, são o “mínimo” e mais do que suficientes para rodar um Linux em modo texto. Portanto, esta será a minha escolha de configuração para a maioria dos servidores-alvo (nós) que iremos criar eventualmente, ao longo da série:

Figura 07. Instalação expressa / RAM e HD virtuais

Feito! Agora basta esperar até que o sistema seja criado e pronto! Ressaltando que o ícone da imagem é uma espécie de olho que fica girando (bolinha fazendo círculos) :

Figura 08. Instalação expressa / SO sendo preparado

Caso a instalação demore e comece a achar meio estranho, faça como eu, seja curioso, e dê um simples clique em cima da bolinha. Talvez se depara com isso, um terminal bugado que por algum motivo não conseguiu finalizar o processo sozinho:

Figura 09. Instalação expressa / Kernel panic !!!

Seguindo a própria recomendação exibida em tela, digite journalctl no terminal para depurar o log e reunir mais informações sobre o possível erro.

Buscando a circunstância para tamanha anomalia, ou quem sabe com sorte, pelo menos alguma pista que levasse até o principal suspeito … Encontrei várias linhas no arquivo de log informando que “a partição X não foi montada”; “a partição Y não existe”; “a Z não possui espaço suficiente”; e coisas desse tipo … Meu primeiro palpite foi de que o particionamento automático da instalação expressa está bugando ao dimensionar, formatar e levantar o esqueleto de diretórios necessário ao sistema operacional. Cheguei ao ponto de aumentar o tamanho do disco virtual querendo testar o algoritmo de fracionamento em diferentes quantidades e valores de armazenamento, pois talvez aqueles exatos 10,7 GB iniciais estivessem sendo pulverizados em tantas micro partições, que no final uma ou outra não tivesse espaço disponível para continuar, quebrando assim toda a instalação. Outros testes realizados foram: aumentar memória, reiniciar a máquina, apagar a VM e recomeçar do zero. Nada! Sem êxito nenhum! Quase perdendo as esperanças, resolvi usar outra imagem, o CentOS 8. Além disso, ainda desconfiado de haver algum BUG no meio, desativei o processo de instalação expressa, simplesmente clicando e desmarcando a caixa de seleção. Dedos cruzados, e na torcida!!! Veremos o que nos espera adiante:

Figura 10. Repetindo o processo com CentOS 8
Figura 11. A-ha! Sem erros!!! Conclusão: instalação expressa do Boxes momentaneamente bugada

Siga em frente, definindo seus próprios parâmetros e configurações da VM, contudo sabendo que em muitas das vezes os padrões pré-selecionados de fábrica já satisfazem o nosso objetivo, salvo eventuais exceções a serem modificadas posteriormente, sem dano algum a integridade do sistema. Não explicarei em detalhes pois não cabe aqui, tão pouco é o objetivo desse POST, como instalar e configurar um CentOS. Isso porque no futuro pretendo abordar esse assunto, em particular, trazendo as possibilidades de cenários e suas variantes. Ok?

Pop_OS! : Executando o Ansible

Apostando no conhecimento prévio adquirido nos posts antecessores, vou direto ao ponto e mostro como transformar o seu Pop_OS! em um nó controlador do Ansible. Essa e tantas outras nomenclaturas, podem ser revistas a qualquer momento. Na dúvida sobre determinado termo, busque aqui no BLOG e releia! Pois cada um deles conta e todos são igualmente importantes, sem exceção.

sudo apt update
Figura 12. Atualizando a última versão dos repositórios atuais
sudo apt install software-properties-common
Figura 13. Instalando o pacote de softwares para python
sudo add-apt-repository --yes --update ppa:ansible/ansible
Figura 14. Adicionando o PPA (repo) oficial do Ansible
sudo apt install ansible
Figura 15. Instalando o pacote ‘ansible’ e suas dependências
ansible --version
Figura 16. Verificando qual versão foi instalada
ansible-config init --disabled > ansible.cfg
ansible --version
Figura 17. Criando o arquivo de configuração

LAB : Adicionando usuário e senha pré-definidos

Tarefa recorrente no cotidiano de um administrador de sistemas, informar novos usuários aos servidores linux pode ser divertido ou entediante, dependendo de como enxerga … Se não gosta de aventura, emoção ou coisas novas, então: (a) escreva um shell script, (b) copie-o para todas as máquinas em que o usuário necessita acesso, (c) execute o mesmo localmente, (d) digite o nome/senha, e por fim, repita os passos C e D até o número X de hosts envolvidos. Por outro lado, se busca tempo livre para novas demandas, novos projetos, novas habilidades, ou somente para tomar aquele cafezinho na copa com toda a calma, conversando e saboreando … Então, aprenda YAML, playbooks, Ansible: aqui, agora !!! 😉

Vamos lá! Para começar, armazenar senhas em texto plano é considerado uma falha de segurança. Qualquer atacante (externo ou interno) teria fácil acesso a esse segredo, usando-o a favor dele, e consequentemente, contra você. Por isso, dados críticos ou informações sigilosas devem sempre apresentar certo nível de criptografia, nunca expostos totalmente. Em nosso caso, utilizaremos a biblioteca passlib do python para gerar o hash de uma senha aleatória forte, sendo esse dado a constar no código-fonte, e não a credencial em si. Para tal abra o editor de texto e, sem olhar, digite algumas teclas aleatoriamente. Feito? Ótimo! Agora no terminal execute os seguintes comandos:

pip3 install passlib
python3 -c "from passlib.hash import sha512_crypt; import getpass; print(sha512_crypt.using(rounds=5000).hash(getpass.getpass()))"
CTRL-C (gedit) + CTRL-V (bash) + ENTER (tecla) = HASH (ctrl-c + ctrl-v + ctrl-s)

Salve o resultado (hash) no mesmo bloco de notas, ao lado da senha que criou há pouco. Assim você terá as duas informações, enquanto escreve o playbook, repassando apenas a última.

Com isso, ainda no terminal, monte a estrutura necessária:

mkdir awx
mkdir -p awx/inventories awx/playbooks
ls -lhR awx/
Figura 18.
cd awx/
touch inventories/hosts
touch playbooks/add-sudo-no-prompt-or-ask.yml
Figura 19.
ls -lhR awx/
Figura 20.

Edite o arquivo hosts conforme o conteúdo abaixo:

vim awx/inventories/hosts
##CENTOS-a ansible_host=10.10.2.141
##CENTOS-b ansible_host=10.10.2.143

Depois abra o playbook e cole o seguinte:

vim awx/playbooks/add-sudo-no-prompt-or-ask.yml
---
- hosts: all
  become: yes
    
  tasks:
  - name: Adiciona usuario e entrega poderes de ROOT
    ansible.builtin.user:
        name: "bob"
        state: present
        password: "$6$XxSTRcR6la4KKUl1$R7XqBVSTOTCNq8PeBpPHL5gK9x1xy8D7oICVHgc2StH7/7wuheM2rPdpw9WD4QkM.Sh1BaDaBq70kE8ScY0jd."
        update_password: on_create
        groups: wheel
        append: yes
...

1ª linha: Todo playbook, na prática um arquivo com extensão .yml ou .yaml, deve começar com três hifens (traços) para sinalizar a sintaxe da sua natureza, a linguagem YAML.

2ª linha: YAML suporta vários tipos de estruturas de dados. Quando trabalhamos com ANSIBLE as mais comuns são listas e dicionários. Uma lista pode ser um conjunto de itens, separados por linha e iniciados com hífen + espaço (“- “) cada. Já um dicionário pode ser um grupo de mapas, composto por chave:valor cada linha e nomeado exclusivamente. Também é possível misturá-los, o que acaba resultando em listas de dicionários ou dicionários com listas muitas vezes. Para encurtar, particularmente nesse caso, estamos dizendo ao Ansible que a lista “hosts” é composta por todas as entradas (sem exceção) do inventário padrão, de mesmo nome. Dessa forma, o playbook será executado em TODOS os servidores listados.

3 ª linha: Equivalente ao su/sudo, aqui definimos o método de escalonamento na máquina remota. O valor YES implica que o usuário escolhido foi o root do sistema ( become: yes = become_user: root )

5ª linha: Dicionário que contém todas as tasks daquela play em questão.

6ª linha: String que nomeia a primeira task do playbook, podendo ser uma frase, palavra, ou caractere de escolha livre.

7ª linha: Módulo ansible utilizado para cumprir aquela tarefa.

8ª linha: Parâmetro name do módulo user para informar o login de usuário.

9ª linha: Parâmetro que remove (absent) ou adiciona (present) o login anterior.

10ª linha: Parâmetro que recebe o valor da senha no formato hash, gerado em etapas superiores.

11ª linha: Parâmetro que atualiza para uma nova senha ou mantém a mesma em casos de preexistência.

12ª linha: Parâmetro que dita qual (is) grupo (s) aquela credencial será membro.

13ª linha: Parâmetro que defini se o grupo é só mais um apêndice ou substituto único e exclusivo para aquele usuário.

14ª linha: Fim do playbook (três pontos).

RUN PLAYBOOK , RUN ! ! !

Últimos metros da maratona, faltando apenas uma etapa para que tudo funcione perfeitamente … Bem, conforme dito no passado, Ansible trata-se de uma ferramenta agentless (sem agente) que faz uso do SSH para comunicação entre as partes. E sendo assim, não poderíamos esquecer de gerar o seu par de chaves correspondente. Para isso, logado como usuário SUDO (comum às duas máquinas: local e remota), no controlador execute:

ssh-keygen -t rsa -b 4096
Figura 21.
ssh-copy-id [usuario_remoto]@[ip_ou_hostname_do_alvo]
Figura 22.
ssh user@machine
Figura 23.
[password]
Figura 24.
exit or logout
ansible -i awx/inventories/hosts -m ping all
Figura 25.
ansible-playbook -i awx/inventories/hosts awx/playbooks/add-sudo-no-prompt-or-ask.yml --ask-become-pass
Figura 26.
Figura 27. ANTES e DEPOIS¹
Figura 28. ANTES e DEPOIS²

REFERÊNCIAS:

https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html

https://www.redhat.com/en/topics/automation/what-is-yaml

https://www.tutorialspoint.com/yaml/yaml_basics.htm

https://rollout.io/blog/yaml-tutorial-everything-you-need-get-started/

ANSIBLE SERIES: h.t.wrt* … tasks, plays e books: failures! (or error handling)

De tempos em tempos, a humanidade é testemunha de um curioso, engraçado e certo tipo de evento: erros que se transformam em felizes acertos! Não faz sentido pra você? Tudo bem, sem problemas! Eu lhe apresento 🥁🥁🥁 a penicilina e a coca-cola 🤭 rsrs! Então, voltando … O mesmo pode acontecer no Ansible. Eventualmente, um código de retorno com valor não-zero (diferente de zero), seja vindo de um comando ou de uma falha em determinado módulo, pode ser exatamente o que você busca no momento e por isso, não vai querer que o Ansible pare a execução naquele host e siga para o próximo. Não, muito pelo contrário. Tal código não-zero indica para você, e sua demanda/tarefa, um verdadeiro baita de um sucesso! Portanto, nada mais lógico do que tratá-lo … Correto? Bom, antes de iniciar os trabalhos, um exemplo básico de situação hipotética para ilustrar melhor: numa bela e ensolarada manhã, seu chefe propõe a você que, caso um host apresente uma falha, o Ansible pare/encerre instantaneamente a execução em todos os outros. Fim!

Agora sim, adiante! Vamos a aula de hoje, com o seu respectivo sumário listado a seguir:

  • Ignorando comandos com falha;
  • Ignorando erros de host inacessíveis;
  • Redefinindo hosts inacessíveis;
  • Manipuladores e falha;
  • Definindo falha;
  • Definindo “alterado”;
  • Garantindo o sucesso para o comando e shell;
  • Abortando uma reprodução em todos os hosts;
  • Controle de erros em blocos;

07-a. Ignorando comandos com falhas

O comportamento padrão, quando uma task qualquer falha num host particular, é puro e simplesmente parar a execução das outras tarefas no mesmo, não importando a quantidade que faltava ou em qual task ele estava (ex: a primeira, a do meio, ou a última). Dessa forma, o Ansible pularia para o próximo host sem piscar duas vezes. Contudo, é totalmente possível continuar naquele host específico apesar dos apesares, ou melhor dizendo, da(s) falha(s). Basta utilizar a palavra-chave ignore_errors:

- name: Do not count this as a failure
  ansible.builtin.command: /bin/false
  ignore_errors: yes

Mas, atenção aqui! Tenha cuidado! Pois essa regra somente funcionará com tarefas capazes de retornar o valor 'failed' (“falhou”). Sendo assim, o Ansible jamais/nunca ignora erros de: variáveis indefinidas, falhas de conexão, problemas de execução, pacotes ausentes ou até mesmo erros de sintaxe.

07-b. Ignorando erros de hosts inacessíveis

Em sua jornada diária, quantas e quantas vezes aquele seu colega sysadmin da infra/operação moveu uma VM de lugar, acrescentou uma nova regra de firewall, ou desligou um grupo de máquinas sem nenhum aviso prévio? Eu sei, talvez sua resposta seja: muitas, várias vezes … Certo? 😥 Mas calma! Por favor, peço que não brigue com ele! Afinal o dia-a-dia de um admin/ops pode ser um pouco cheio e meio estressante, de tanto deveres, rotinas e tarefas. E por isso, eis que trago a solução para os seus problemas (ou erros, neste caso). Se uma task abortar dado ao status do host ser ‘UNREACHABLE’, use ignore_unreachable. Assim o Ansible ignora os erros da tarefa atual, mas permanecendo disponível para executar eventuais futuras tarefas no host que está inacessível no momento 🤩

À nível de task:

- name: This executes, fails, and the failure is ignored
  ansible.builtin.command: /bin/true
  ignore_unreachable: yes

- name: This executes, fails, and ends the play for this host
  ansible.builtin.command: /bin/true

À nível de playbook:

- hosts: all
  ignore_unreachable: yes
  tasks:
  - name: This executes, fails, and the failure is ignored
    ansible.builtin.command: /bin/true

  - name: This executes, fails, and ends the play for this host
    ansible.builtin.command: /bin/true
    ignore_unreachable: no

07-c. Redefinindo hosts inacessíveis

Se o Ansible não puder se conectar a um host, ele marca esse host como ‘UNREACHABLE’ e o remove da lista de hosts ativos para a execução. Você pode usar meta: clear_host_errors para reativar todos os hosts, para que as tarefas subsequentes possam tentar alcançá-los novamente. ( Top demais! 👌💯 )

07-d. Manipuladores e falhas

Ansible executa handlers no final de cada play … Desde a nossa aula passada isso já é fato conhecido! PORÉM, e se uma tarefa notifica um manipulador, mas aí vem uma falha e faz o mesmo, logo em seguida ou posteriormente, na execução do playbook? O que acontece? Bem, o esperado e padrão é o manipulador não ser executado naquele host, o que pode deixar o host em um estado inesperado. Por exemplo, uma tarefa pode atualizar um arquivo de configuração e notificar um manipulador para reiniciar algum serviço. Se uma tarefa posterior na mesma execução falhar, o arquivo de configuração pode ser alterado, mas o serviço não será reiniciado.

Para evitar, reverter ou burlar (nomeie como quiser!) tal comportamento basta usar a opção de linha de comando --force-handlers, incluindo force_handlers: True em uma play, ou adicionando force_handlers = True ao ansible.cfg. Quando os manipuladores são forçados, o Ansible executará todos os manipuladores notificados em todos os hosts, até mesmo hosts com tarefas com falha. (Observe que certos erros ainda podem impedir a execução do handler, como um host inacessível.)

07-e. Definindo uma falha

O Ansible permite definir o que “falha” significa em cada tarefa usando a condição failed_when. Como acontece nas outras condicionais do Ansible, listas com várias condições failed_when são unidas com um and implícito, o que refletindo na tarefa em si, já que a mesma só falha quando todas as condições são atendidas. Caso deseje o oposto disso, que é uma “falha” quando qualquer uma das condições for atendida, você deve definir as condições em uma string com um operador oR explícito.

Você pode verificar se há falhas pesquisando uma palavra ou frase na saída de um comando:

- name: Fail task when the command error output prints FAILED
  ansible.builtin.command: /usr/bin/example-command -x -y -z
  register: command_result
  failed_when: "'FAILED' in command_result.stderr"

Ou baseado no código de retorno:

- name: Fail task when both files are identical
  ansible.builtin.raw: diff foo/file1 bar/file2
  register: diff_cmd
  failed_when: diff_cmd.rc == 0 or diff_cmd.rc >= 2

+ 1 exemplo: combinar múltiplas condições para definir uma “falha”

- name: Check if a file exists in temp and fail task if it does
  ansible.builtin.command: ls /tmp/this_should_not_be_here
  register: result
  failed_when:
    - result.rc == 0
    - '"No such" not in result.stdout'

07-f. Definindo “alterado”

O Ansible permite definir quando uma tarefa específica “mudou” um nó remoto usando a condição changed_when. Isso permite determinar, com base em códigos de retorno ou saída, se uma alteração deve ser relatada nas estatísticas Ansible e se um manipulador deve ser acionado ou não. Como acontece com todas as condicionais em Ansible, listas de várias condições changed_when são unidas com um AND implícito, o que significa que a tarefa só relata uma mudança quando todas as condições são atendidas. Se quiser relatar uma mudança quando qualquer uma das condições for atendida, você deve definir as condições em uma string com um operador OR explícito. Por exemplo:

tasks:

  - name: Report 'changed' when the return code is not equal to 2
    ansible.builtin.shell: /usr/bin/billybass --mode="take me to the river"
    register: bass_result
    changed_when: "bass_result.rc != 2"

  - name: This will never report 'changed' status
    ansible.builtin.shell: wall 'beep'
    changed_when: False

07-g. Garantindo o sucesso para o comando e shell

Os módulos de comando e shell se preocupam com os códigos de retorno, portanto, se você tiver um comando cujo código de saída bem-sucedido não seja zero, você pode fazer o seguinte:

tasks:
  - name: Run this command and ignore the result
    ansible.builtin.shell: /usr/bin/somecommand || /bin/true

07-h. Abortando uma execução em todos os hosts

Às vezes, você deseja que uma falha em um único host, ou falhas em uma certa porcentagem de hosts, aborte a execução inteira em todos os hosts. Você pode interromper a execução da reprodução após a primeira falha acontecer com any_errors_fatal. Para um controle mais refinado, você pode usar max_fail_percentage para abortar a execução após uma determinada porcentagem de hosts falhar.

07-i. Controle de erros em blocos

Veja detalhes e exemplos em https://docs.ansible.com/ansible/latest/user_guide/playbooks_blocks.html#block-error-handling

REFERÊNCIAS:

https://docs.ansible.com/ansible/latest/user_guide/playbooks_error_handling.html#playbooks-error-handling

ANSIBLE SERIES: h.t.wrt* … tasks, plays e books: handlers

CONT. 🔝

🔙 ANTERIOR: BLOCKS

Visto no final do post passado, numa breve participação coadjuvante, e já tendo aparecido em outras oportunidades aqui no BLOG, chegou a hora de conhecer um pouco mais sobre os handlers (traduzindo para o português: manipuladores). Objetiva e diretamente, são um tipo de tarefa que apenas se auto executa quando recebe uma notificação. Por exemplo, reiniciar determinado serviço (daemon) se, e somente se, alguma task modificou sua configuração. Em oposição, não fazer absolutamente nada enquanto tal permanecer inalterada. Outro fato importante, e assim como as variáveis, cada handler precisa ser nomeado exclusivamente.

  • Exemplo;
  • Controlando a execução de um handler (WHEN);
  • Usando variáveis com handlers;

06-a. Handler Example

A seguir, o playbook verify-apache.yml, apresentando uma play com handler simples:

---
- name: Verify apache installation
  hosts: webservers
  vars:
    http_port: 80
    max_clients: 200
  remote_user: root
  tasks:
  - name: Ensure apache is at the latest version
    ansible.builtin.yum:
      name: httpd
      state: latest

  - name: Write the apache config file
    ansible.builtin.template:
      src: /srv/httpd.j2
      dest: /etc/httpd.conf
    notify:
    - Restart apache

  - name: Ensure apache is running
    ansible.builtin.service:
      name: httpd
      state: started

  handlers:
    - name: Restart apache
      ansible.builtin.service:
        name: httpd
        state: restarted

Continuando, mais um playbook. Entretanto, agora é a vez de uma task (anteriormente foi uma play) ser responsável por notificar. Serve para demonstrar que uma única task é capaz de notificar mais de um handler simultaneamente:

- name: Template configuration file
  ansible.builtin.template:
    src: template.j2
    dest: /etc/foo.conf
  notify:
    - Restart memcached
    - Restart apache

  handlers:
    - name: Restart memcached
      ansible.builtin.service:
        name: memcached
        state: restarted

    - name: Restart apache
      ansible.builtin.service:
        name: apache
        state: restarted

06-b. Controlando a execução de um handler (WHEN)

Devido a sua concepção, manipuladores são executados depois que todas as tarefas em uma determinada play foram concluídas. Tal método é eficiente pois o manipulador é executado apenas uma vez, independentemente de quantas tarefas o notificam. Por exemplo, se várias tarefas atualizam um arquivo de configuração e notificam um manipulador para reiniciar o Apache, o Ansible pula o Apache apenas uma vez para evitar reinicializações desnecessárias.

Caso necessite que os handlers sejam executados bem antes do final da execução, basta adicionar uma task que os liberte para tal. Faça uso do ‘meta module’ presente no ansible-base, chamando-o para que o Ansible execute ações:

tasks:
  - name: Some tasks go here
    ansible.builtin.shell: ...

  - name: Flush handlers
    meta:flush_handlers

  - name: Some other tasks
    ansible.builtin.shell: ...

A tarefa meta: flush_handlers aciona todos os manipuladores que foram notificados naquele ponto da play em específico.

06-c. Usando variáveis com handlers

Talvez queira que seus manipuladores usem variáveis. Por exemplo, se o nome de um serviço variar ligeiramente de distro para distro, você espera que sua saída mostre o nome exato do serviço reiniciado para cada máquina de destino. Por isso, evite colocar variáveis no nome do manipulador. Como os nomes do manipulador são modelados desde o início, o Ansible pode não ter um valor disponível para um nome como este aqui:

handlers:
# This handler name may cause your play to fail!
- name: Restart "{{ web_service_name }}"

Se a variável usada no nome do manipulador não estiver disponível, toda a execução falhará. E antes que pense, não! Alterar essa variável “durante” não resultará em um manipulador recém-criado.

Em vez disso, coloque variáveis nos parâmetros de tarefa de seu manipulador. Você pode carregar os valores usando include_vars como este:

tasks:
  - name: Set host variables based on distribution
    include_vars: "{{ ansible_facts.distribution }}.yml"

handlers:
  - name: Restart web service
    ansible.builtin.service:
      name: "{{ web_service_name | default('httpd') }}"
      state: restarted

Os manipuladores também podem “ouvir” tópicos genéricos e as tarefas podem notificar esses tópicos da seguinte maneira:

handlers:
  - name: Restart memcached
    ansible.builtin.service:
      name: memcached
      state: restarted
    listen: "restart web services"

  - name: Restart apache
    ansible.builtin.service:
      name: apache
      state: restarted
    listen: "restart web services"

tasks:
  - name: Restart everything
    ansible.builtin.command: echo "this task will restart the web services"
    notify: "restart web services"

Isso torna muito mais fácil acionar vários manipuladores. Ele também desacopla os manipuladores de seus nomes, facilitando o compartilhamento de manipuladores entre playbooks e roles (especialmente ao usar funções de terceiros de uma fonte compartilhada como o Ansible Galaxy).

REFERÊNCIAS:

https://docs.ansible.com/ansible/latest/user_guide/playbooks_handlers.html#handlers

ANSIBLE SERIES: h.t.wrt* … tasks, plays e books: blocks

UPDATE! / DISCLAIMER: Depois de muitas idas e vindas ao banco … buscas e mais buscas à procura de documentos pessoais que não via há tanto tempo … cópias, xerox, pdf’s, assinaturas … e por fim, infinitas caixas/pacotes para organizar, mofo/poeira para limpar, caminhão da mudança, lavar o piso novo, desempacotar e remontar 😫😓 (…) Estou vivo, de volta e escrevendo da minha própria casa, cujo foi comprada em JUN/2021, também conhecido como ‘mês passado’. Esse foi o real motivo para o BLOG ter ficado tão parado nessas últimas semanas, caros e estimados leitores. Sendo assim, peço desculpas a todos! Espero que não fiquem chateados comigo 😥 MAS, é como dizem por aí: o show não pode parar! Então, retomando do ponto exato aonde paramos, a seguir, +1 capítulo da série ANSIBLE:

CONT. 🔝

🔙 ANTERIOR: CONDITIONALS

Analogamente (ou equivalente, se preferir) a um grupo de linhas dentro do código-fonte, blocos no contexto ‘ansible’ são formas/maneiras de lidar/tratar dois tipos de elemento básico: (a) tasks e (b) erros! Na prática, blocos acabam criando grupos lógicos, sejam micro tarefas que partilham determinado objetivo maior, sejam erros advindos de uma tarefa mal executada, displicentemente planejada. Em ambos os casos, podemos fazer um paralelo com o tratamento de exceções, observadas em outras linguagens de programação.

  • Agrupando tasks com blocos;
  • Tratando erros com blocos;

05-a. Agrupando tasks com blocos

A herança de dados, diretivas, ocorre e se aplica a todas as tarefas comuns (aninhadas) em um mesmo nível de bloco. Ou seja, a diretiva propriamente dita não afeta o bloco em si, mas sim as tasks delimitadas (contidas) por ele. Para exemplificar: uma vez validada e satisfeita a condição imposta pelo when, aplica-se a mesma numa única tacada para as diversas tarefas presentes no bloco em questão. O que é bem diferente de aplicar a ele mesmo, como pode ser levado a crer, e assim, induzido ao erro. A única exceção aqui são os loops. Esteja sempre atento!

tasks:
   - name: Install, configure, and start Apache
     block:
       - name: Install httpd and memcached
         ansible.builtin.yum:
           name:
           - httpd
           - memcached
           state: present

       - name: Apply the foo config template
         ansible.builtin.template:
           src: templates/src.j2
           dest: /etc/foo.conf

       - name: Start service bar and enable it
         ansible.builtin.service:
           name: bar
           state: started
           enabled: True
     when: ansible_facts['distribution'] == 'CentOS'
     become: true
     become_user: root
     ignore_errors: yes

Resumidamente: a condição é avaliada ANTES e TODA VEZ que “alcançamos” um host diferente. Se passar, aí sim serão executadas as três tarefas informadas no bloco, para aquele node específico (e aprovado). O escalonamento e privilégio de root também são herdados, e por tabela, executados na sequência. Por fim, a última linha ignore_errors: yes serve apenas para que o Ansible dê continuidade ao playbook em casos de falhas nas tasks.

**Names for blocks have been available since Ansible 2.3. We recommend using names in all tasks, within blocks or elsewhere, for better visibility into the tasks being executed when you run the playbook.

05-b. Tratando erros com blocos

Trechos do código identificados como blocos, e marcados com as palavras rescue e always, são chamados (igualmente definidos) de sessões. Elas são peças-chave, fundamentais para controlar as respostas direcionadas a possíveis erros de tarefa.

Blocos rescue ditam novas tasks a serem executadas quando uma task anterior (do mesmo bloco) falhar. Tal abordagem é muito parecida com o tratamento de exceções presente em diversas outras linguagens de programação. É importante frisar aqui a seguinte informação: o Ansible somente executa blocos de resgate após uma tarefa retornar estado de FALHA (failed). Tasks definidas incorretamente ou hosts inacessíveis não irão disparar/acionar nenhum bloco de resgate.

tasks:
 - name: Handle the error
   block:
     - name: Print a message
       ansible.builtin.debug:
         msg: 'I execute normally'

     - name: Force a failure
       ansible.builtin.command: /bin/false

     - name: Never print this
       ansible.builtin.debug:
         msg: 'I never execute, due to the above task failing, :-('
   rescue:
     - name: Print when errors
       ansible.builtin.debug:
         msg: 'I caught an error, can do stuff here to fix it, :-)'

Dentro de um bloco também podem haver sessões always. A partir desse ponto, tarefas serão executadas independentemente do status anterior, ou seja, da task anterior.

- name: Always do X
   block:
     - name: Print a message
       ansible.builtin.debug:
         msg: 'I execute normally'

     - name: Force a failure
       ansible.builtin.command: /bin/false

     - name: Never print this
       ansible.builtin.debug:
         msg: 'I never execute :-('
   always:
     - name: Always do this
       ansible.builtin.debug:
         msg: "This always executes, :-)"

Misturados, esses dois fornecem um belo tratamento para erros um pouco mais complexos.

- name: Attempt and graceful roll back demo
  block:
    - name: Print a message
      ansible.builtin.debug:
        msg: 'I execute normally'

    - name: Force a failure
      ansible.builtin.command: /bin/false

    - name: Never print this
      ansible.builtin.debug:
        msg: 'I never execute, due to the above task failing, :-('
  rescue:
    - name: Print when errors
      ansible.builtin.debug:
        msg: 'I caught an error'

    - name: Force a failure in middle of recovery! >:-)
      ansible.builtin.command: /bin/false

    - name: Never print this
      ansible.builtin.debug:
        msg: 'I also never execute :-('
  always:
    - name: Always do this
      ansible.builtin.debug:
        msg: "This always executes"

As tarefas do bloco são executadas normalmente. Se alguma tarefa no bloco retornar failed, a seção de resgate executa tarefas para se recuperar do erro. A seção always é executada independentemente dos resultados das seções block e rescue.

Se ocorrer um erro no bloco e a tarefa de resgate for bem-sucedida, o Ansible reverterá o status de falha da tarefa original para a execução e continuará a executar a reprodução como se a tarefa original tivesse sido bem-sucedida. A tarefa resgatada é considerada bem-sucedida e não aciona configurações max_fail_percentage ou any_errors_fatal. No entanto, Ansible ainda relata uma falha nas estatísticas do playbook.

Use blocos com flush_handlers em uma tarefa de resgate para garantir que todos os manipuladores sejam executados mesmo se ocorrer um erro:

 tasks:
   - name: Attempt and graceful roll back demo
     block:
       - name: Print a message
         ansible.builtin.debug:
           msg: 'I execute normally'
         changed_when: yes
         notify: run me even after an error

       - name: Force a failure
         ansible.builtin.command: /bin/false
     rescue:
       - name: Make sure all handlers run
         meta: flush_handlers
 handlers:
    - name: Run me even after an error
      ansible.builtin.debug:
        msg: 'This handler runs even on error'

**New in version 2.1

**Ansible provides a couple of variables for tasks in the rescue portion of a block:

ansible_failed_task

The task that returned ‘failed’ and triggered the rescue. For example, to get the name use ansible_failed_task.name.

ansible_failed_result

The captured return result of the failed task that triggered the rescue. This would equate to having used this var in the register keyword.

REFERÊNCIAS:

https://docs.ansible.com/ansible/latest/user_guide/playbooks_blocks.html#playbooks-blocks

ANSIBLE SERIES: h.t.wrt* … tasks, plays e books: building loops

CONT.

👈 ANTERIOR: BECOME

O que fazer quando é necessário repetir determinada ação mais de uma vez ??? Automatizar, é claro, você diria … Tudo bem, já entendi que pegou o espírito da coisa 🙃 E fico deveras feliz por isso, diga-se de passagem! Mas, o que eu quis dizer é como fazê-lo em pormenores? Como executar valendo-se da lógica da programação? Há duas respostas válidas, contudo uma é mais inteligente e menos trabalhosa, e a outra é mais lenta (para não desmerecê-la 😬 haha) e braçal. A primeira delas seria utilizar um monte de IF’s e ELSE’s para cada entrada, interação ou condição. Em contrapartida, a segunda seria criar um laço (daí seu nome loop, em inglês) com uma variável “contador” interna. Essa controlaria a execução do mesmo em N vezes, e até que a condição X fosse satisfeita. Resultado? Um código mais bonito, limpo, enxuto, com menos linhas, e mais otimizado.

No contexto do Ansible, ou de qualquer outra ferramenta de automação, tais ações “repetitivas” abrangeriam desde adicionar vários usuários, replicar uma configuração em um pool de máquinas, até mudar a propriedade/permissão (ou dono) de uma série de arquivos e pastas, por exemplo. Para tal o ansible nos fornece duas palavras-chave: loop e with_<lookup> (lookup em português pode ser traduzido como busca, pesquisa, chave ou valor).

Antes de expor e debater os tópicos a seguir, cabe aqui, e quero destacar algumas notas acerca do recurso loop :

  • Foi introduzido a partir do Ansible 2.5
  • Está presente em todas as versões sucessoras (2.5+)
  • Ainda não substitui completamente o with_<lookup>, embora a ideia seja exatamente essa no futuro.
  • Na maioria dos casos recomenda-se, e satisfaz muito bem, o uso do loop . Somente em situações extremamente específicas o with_<lookup> dá pleno suporte, o que acaba “vencendo” seu concorrente amigo, e portanto o uso dele é o único meio viável para solucionar.
  • Não está obsoleta ou tão pouco depreciada a sintaxe do with_lookup, continuando assim totalmente válida, embora isso possa mudar no médio-longo prazo.
  • O loop encontra-se em constante mudança visando principalmente seu aperfeiçoamento. Para atualizações e alterações do mesmo, por favor consultar o CHANGELOG https://github.com/ansible/ansible/tree/devel/changelogs

02-a. Comparativo entre loop e with_*

As únicas palavras-chave capazes de complementar o with_ são aquelas que estão disponíveis em https://docs.ansible.com/ansible/latest/plugins/lookup.html#lookup-plugins Ou seja, na prática, qualquer uma delas quando utilizadas correspondem ao asterisco (presente no título desta sessão). Para refrescar a memória, * é conhecido também como o caractere-curinga na computação, especificamente quando falamos em interpretadores de comandos nos sistemas operacionais.

A palavra loop é o mesmo que usar a expressão with_list, sendo a primeira uma melhor escolha para loops que não possuem tanta complexidade. Porém, o loop não aceita como entrada nenhuma ‘string’. Veja mais em https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#query-vs-lookup

Genericamente, e simplificando bastante, qualquer with_* pode facilmente ser trocado por loop. Claro que salva as devidas proporções e ressalvas, todas essas descritas aqui https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#migrating-to-loop

02-b. Loops Tradicionais (ou padrão/modelos)

! ! ! Interagindo sobre uma lista simples ! ! !

Se uma task precisa ser executada mais de uma vez em determinado host, recomenda-se usar como padrão o próprio loop, assim este agiria de acordo e sobre uma lista de strings, por exemplo. Em outras palavras, defina a lista diretamente, de uma vez só e já estando dentro da task em questão:

- name: Add users and give them root powers
  ansible.builtin.user:
    name: "{{ item }}"
    state: present
    group: "wheel"
  loop:
     - victor
     - viktor
     - vitor
     - vicrlda

O código acima ☝ seria equivalente ao de baixo 👇 (só que mais elegante! e com menos tec-tec-tec-tec 🔉💻💬)

- name: Add user vitor
  ansible.builtin.user:
    name: "vitor"
    state: present
    groups: "wheel"

- name: Add user vicrlda
  ansible.builtin.user:
    name: "vicrlda"
    state: present
    groups: "wheel"

.
.

.
.

! ! ! Interagindo sobre uma lista de hashes ! ! !

Caso tenha uma lista de hashes para trabalhar, utilize referências no formato de chave:subchave dentro do loop.

- name: Add multiple users
  ansible.builtin.user:
    name: "{{ item.name }}"
    state: present
    groups: "{{ item.groups }}"
  loop:
    - { name: 'victor', groups: 'wheel' }
    - { name: 'viktor', groups: 'root' }

! ! ! Interagindo sobre um dictionary ! ! !

Neste caso, simplesmente use o dict2items https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html#dict-filter :

- name: Using dict2items
  ansible.builtin.debug:
    msg: "{{ item.key }} - {{ item.value }}"
  loop: "{{ tag_data | dict2items }}"
  vars:
    tag_data:
      Environment: dev
      Application: payment

02-c. Registrando variáveis com um loop

Esse artifício é comumente usado na lógica da programação, em termos genéricos, e desde sempre, remontando ao seu início e concepção. Naturalmente, por tabela, também é observado nas linguagens. Em outras palavras, o que temos é, basicamente um evento partilhado ocorrendo tanto no macro quanto no micro ecossistema. Respeitando, é claro, as particularidades de cada um (limitações, capacidades e sintaxe).

E com os playbooks não poderia ser diferente. Somos capazes de armazenar a saída de um loop dentro de uma variável. Por exemplo,

- name: Register loop output as a variable
  ansible.builtin.shell: "echo {{ item }}"
  loop:
    - "apple"
    - "banana"
  register: echo

Loops que vem logo após a variável registrada, com o intuito de inspecionar eventuais resultados, talvez se assemelhem ao trecho a seguir:

- name: Fail if return code is not 0
  ansible.builtin.fail:
    msg: "The command ({{ item.cmd }}) did not have a 0 return code"
  when: item.rc != 0
  loop: "{{ echo.results }}"

Por padrão, o comportamento da variável durante a execução/interação do loop é sempre armazenar o valor do item atual, indiferente se são números, strings ou caracteres.

- name: Place the result of the current item in the variable
  ansible.builtin.shell: echo "{{ item }}"
  loop:
    - one
    - two
  register: echo
  changed_when: echo.stdout != "one"

02-d. Loops Complexos

! ! ! LISTAS ANINHADAS ! ! !

Aninhado(a), conceitualmente restrito ao universo da programação, implica dizer que um dado elemento está contido em outro elemento. Se preferir mais sinônimos, seria o mesmo que alojado, hospedado, instalado. Isso compreende desde funções, sub-rotinas, até vetores e matrizes. Exemplo: um vetor de tamanho três [0, 1, 2] cujas posições na memória são na verdade ponteiros para outros três vetores distintos. Talvez o mais importante aqui, e que vale destacar, é o tamanho da jurisprudência do primeiro ou o limite imposto ao segundo … ❓❓❓ Certo, certo, eu explico. Vamos imaginar que os sujeitos (elementos) em questão sejam rotinas e sub-rotinas. Então, partindo do pressuposto que apresentei, uma sub-rotina “filha” somente poderia ser chamada para rodar durante o programa única e exclusivamente por sua rotina “mãe”. Caso uma rotina “madrasta”, por exemplo, tentasse invocar essa mesma sub-rotina “filha”, não haveria êxito algum. Isso porque, de antemão, a primeira (madrasta) nunca iria enxergar a segunda (filha) pois ela apenas fica visível para a terceira (mãe). Isso é o que determinados autores chamam de “fazer sentido localmente”, e que é considerada uma forma de encapsulamento.

Ufa! 🥴 Agora sim, voltando ao contexto dos playbooks, e finalizando esse tópico antes de passar para o próximo (…)

Em situações de listas aninhadas recomenda-se o uso de expressões Jinja2 para melhor tratá-las. Como segue abaixo, um loop que combina várias listas:

- name: Give users access to multiple databases
  community.mysql.mysql_user:
    name: "{{ item[0] }}"
    priv: "{{ item[1] }}.*:ALL"
    append_privs: yes
    password: "foo"
  loop: "{{ ['alice', 'bob'] |product(['clientdb', 'employeedb', 'providerdb'])|list }}"

! ! ! INVENTÁRIOS ! ! !

Mais uma opção para uso dos loops no Ansible ocorre quando se trata de arquivos de inventário. Isso nos possibilita varrê-los ou construí-los sem sair do laço. E melhor, não é obrigatório usar todo o arquivo e sim apenas uma parte dele, caso prefira assim. Para tal, basta informar a palavra-chave loop com a variável ansible_play_batch ou a variável groups

- name: Show all the hosts in the inventory
  ansible.builtin.debug:
    msg: "{{ item }}"
  loop: "{{ groups['all'] }}"

- name: Show all the hosts in the current play
  ansible.builtin.debug:
    msg: "{{ item }}"
  loop: "{{ ansible_play_batch }}"

02-e. Adicionando controles aos loops

(A partir da versão 2.1+)

(Palavra-chave: loop_control)

! ! ! LIMITANDO A TELA/SAÍDA DO LOOP ! ! !

Para estruturas de dados muito complexas, executar um laço pode ser algo extenso, e consequentemente, a saída gerada (console) se torna igualmente enorme. Evite dores de cabeça e olhos cansados utilizando a diretriz label com loop_control :

- name: Create servers
  digital_ocean:
    name: "{{ item.name }}"
    state: present
  loop:
    - name: server1
      disks: 3gb
      ram: 15Gb
      network:
        nic01: 100Gb
        nic02: 10Gb
        ...
  loop_control:
    label: "{{ item.name }}"

! ! ! Pausa dentro de um loop ! ! !

Controle o tempo, aqui medido em segundos, entre a execução de cada item dentro de uma loop task (tarefa repetitiva). Use a diretriz pause com a palavra loop_control

# main.yml
- name: Create servers, pause 3s before creating next
  community.digitalocean.digital_ocean:
    name: "{{ item }}"
    state: present
  loop:
    - server1
    - server2
  loop_control:
    pause: 3

! ! ! Definindo nomes internos e externos ao loop com loop_var ! ! !

Você pode aninhar duas tarefas de loop usando include_tasks. No entanto, por padrão, Ansible define o item de variável de loop para cada loop. Isso significa que o loop interno aninhado sobrescreverá o valor do item do loop externo. Você pode especificar o nome da variável para cada loop usando loop_var com loop_control:

# main.yml
- include_tasks: inner.yml
  loop:
    - 1
     - 2
     - 3
  loop_control:
    loop_var: outer_item

# inner.yml
- name: Print outer and inner items
  ansible.builtin.debug:
    msg: "outer item={{ outer_item }} inner item={{ item }}"
  loop:
    - a
     - b
     - c

CONTINUA (…)

Próximo post >>> WHERE TASKS RUN?

REFERÊNCIAS:

https://docs.ansible.com/core.html

https://docs.ansible.com/ansible/latest/user_guide/index.html

https://docs.ansible.com/ansible/latest/user_guide/index.html#writing-tasks-plays-and-playbooks

https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#playbooks-loops

ANSIBLE SERIES: h.t.wrt* … tasks, plays e books: como escrevê-los?

* Sigla para: < How To Write >

Recapitulando o que vimos até o momento acerca do Ansible:

  • Teoria
    • DevOps: conceito, história, curiosidades ✅
    • Por que automatizar com ansible? ✅
    • 5 conceitos fundamentais ✅
  • Prática
    • Linha de comando, hello.YML e Ad-Hoc ✅
    • Web console: AWX/TOWER ✅
    • Como executar um JOB graficamente em tempo real ✅

Poxa vida! 😲 Eu diria um bocado não é mesmo? Sendo ou não, o que importa é que a estrada ainda se encontra a nossa frente e aos poucos, devagar, mas com passos firmes vamos progredindo no ROADMAP de um DEVOPS. Portanto, e acho que todos já estão acostumados com as minhas deixas (ou chamados) para iniciar um POST do blog … Hey Ho! Let’s go!

Muito bem jovens, ao que interessa então. Se você já buscou material, ou até mesmo cursou algum tipo de preparatório para o Ansible, as chances do professor ter abordado logo no começo (imediatamente após o briefing/overview) esses itens que vou mostrar é muito grande. Em outras palavras, e simplificando, acredito que tenha sido dessa forma: 1. o que é ansible? / 2. definições e termos / 3. prompt, módulos e comandos ad-hoc / para finalmente chegar em 4. como escrever playbooks. Por último é que eles mostram o AWX, boas práticas, roles, hosts windows, network e paramiko, etc. Mas e daí Victor? Eu sei, não há nada de errado com isso. Cada um ministra e monta seu plano de aulas da maneira que achar melhor aos estudantes. E tudo bem, ok. Mas no nosso caso, vocês e eu, quis inverter um pouco as coisas e adiantar logo a parte gráfica do ansible, ou seja, o tower/awx. Na verdade o meu intuito era “cativar” a todos apresentando de cara as duas faces do mesmo: linha de comando e interface web. Assim cada pessoa poderia escolher a melhor forma de trabalhar, de acordo com seu gosto e afinidade. Gosta de terminal? Ótimo, vá de CLI e seja feliz! Não, prefiro botões, gráficos e menus. Maravilha, pegue a GUI e curta a vida! O que quero dizer aqui é não existe método certo ou errado, melhor ou pior. Não, pelo contrário, há vantagens e desvantagens em cada um deles. Cabe tão somente a você pesar os prós e contras e escolher sua forma de operar. Lembrando sempre que é possível combiná-las tá? Por exemplo, tal tarefa é mais rápido e comodo se fizer via bash, já aquela outra é necessário maior controle de usuários e permissões, então farei por meio da web. Entenderam? Ou enrolei demais? 🤔

POOL DE INFORMAÇÕES

https://docs.ansible.com/

Desde sempre admirei empresas de tecnologia, bem antes de entrar na faculdade. Talvez por isso que enveredei para este ramo. Google, Microsoft, IBM, Facebook, e tantas outras (ora gigantes, ora um pouco mais modestas) foram alguns exemplos de modelo a perseguir, almejar e quem sabe um dia entrar no time… Uma vez imerso nesse grande oceano, chamado TI, passei a ter bastante contato com Linux e suas distros. Além de ter curtido, comecei a ficar de olho, meio que acompanhar notícias e bastidores das empresas idealizadoras/responsáveis. Foi assim que fiquei maravilhado com todo o trabalho por trás de cada uma dessas distribuições. Digo, não apenas o resultado final: o lançamento periódico de novas versões. Mas sim o suporte, divulgação, comunidades, fóruns oficiais, documentação, e afins. Também vale um destaque especial, o principal “cartão de visita” dessas empresas: os websites. Falo sério, você já acessou a Canonical, Red Hat, Suse e System76 ?? É verdadeiro deleite, e de encher os olhos, devido a tanto primor e cuidado com o design e layout. São muito bonitos, sem exceção!!!

E como prova disso, trago a seguir uma captura de tela da página INDEX da documentação do ansible. Podemos dizer que ela é uma espécie de hub central, uma vitrine, para orientar sobre tudo que o mesmo é capaz, e como fazer. Confiram:

Figura 01. Docs INDEX page

Acima devidamente circulado está o nosso foco: a documentação base, ou seja, relacionada ao núcleo, chamado de ansible-core. Pelas próximas semanas vamos nos debruçar sobre a sintaxe, lógica, melhores práticas, organização de pastas e arquivos, reuso de código, otimização, e muito mais. Para isso, irei sempre pontuar já no título do POST em questão, o que vamos aprender nele. Ex: loops, variáveis, templates, roles, e assim por diante.

Qualquer dúvida ou lacuna que porventura tenha deixado, acessem o link e vão direto na fonte para saná-las. Até porque não pretendo abordar absolutamente tudo que está lá, ok? Senão o que estaria fazendo é um simples CTRL-C + CTRL-V do referido conteúdo. E isso não quero, e tão é algo ético. Resumindo: antes de ler aqui, recomendo dar uma estudada pela oficial, por favor. Embora prometo fazer o meu melhor para se aproximar ao máximo dos mestres da Red Hat 🎩

01-a. BECOME: acesso, usuários e permissões

Ansible utiliza meios de escalonamento de privilégios pré-existentes na máquina remota. Isso é o que eles chamam de become. Ele seria o equivalente ao su, sudo, runas e similares. O objetivo é tanto permitir quanto executar tarefas locais nos alvos (nodes), usando privilégios de root ou qualquer outra permissão já criada dentro do nó. O efeito prático disso é torna-se outro usuário¹ dentro do host² em questão, sendo o primeiro completamente diferente daquele que usou para entrar no segundo.

i ) Usando o become

É possível controlá-lo através de tasks, plays, variáveis de conexão ou linha de comando. Em caso de duas ou mais ao mesmo tempo (sim, isso é válido e às vezes comum) consulte atentamente as regras de precedência para as mesmas. Leia mais aqui: https://docs.ansible.com/ansible/latest/reference_appendices/general_precedence.html#general-precedence-rules

! ! ! Diretivas do become ! ! !

Estabeleça como definir o become, controlando o mesmo à nível de task ou play. Variáveis e diretivas são independentes entre si. Por exemplo, definir become_user não é a mesma coisa que “só” become.

become: defina para 'yes' e ative o escalonamento de privilégios
become_user : defina o usuário com os privilégios desejados. ou seja, a credencial que você pretende se tornar e não o usuário que fez login.
become_method : (à nível de play ou task) sobrescreve o método padrão definido em ansible.cfg
become_flags :(à nível de play ou task) permite o uso de flags específicas para uma tarefa ou play. bastante comum quando se quer mudar o usuário para 'nobody' em casos de 'shell' setado para 'nologin'

Por exemplo,

Gerenciar um serviço (daemon) que requer privilégios de root … Em um cenário onde o usuário conectado não é root … Neste caso, utilizamos o valor padrão de become_user, que é justamente ‘root’

- name: Ensure the httpd service is running
  service:
    name: httpd
    state: started
  become: yes

Executar algo como ‘nobody’ quando o shell (terminal) está configurado para ‘nologin’

- name: Run a command as nobody
  command: somecommand
  become: yes
  become_method: su
  become_user: nobody
  become_flags: '-s /bin/sh'

To specify a password for sudo, run ansible-playbook with --ask-become-pass (-K for short). If you run a playbook utilizing become and the playbook seems to hang, most likely it is stuck at the privilege escalation prompt. Stop it with CTRL-c, then execute the playbook with -K and the appropriate password.

! ! ! Variáveis de conexão ! ! !

Nós e grupos suportam diversas, e distintas, opções ‘become’. Em cada gerenciável existe a possibilidade de defini-las em um arquivo inventário, ou usá-las como se fossem variáveis comuns.

São elas,

ansible_become: em termos de finalidade, praticamente uma cópia da diretiva become. ou seja, define se o escalonamento de privilégio será utilizado ou não.
ansible_become_method: escolhe qual forma de privilégio será usada.
ansible_become_user: dita qual usuário você irá se tornar via método de escalonamento. não é a mesma coisa que ansible_become: yes
ansible_become_password: senha do usuário citado anteriormente. é possível, mas não aconselhável, passar segredos em texto plano. aprenda formas mais seguras em https://docs.ansible.com/ansible/latest/user_guide/vault.html#playbooks-vault
! ! ! Opções na linha de comando ! ! !
--ask-become-pass OU -K
Solicita a senha "privilegiada" ... É usada para todos os hosts
--become OU -b
Executa as instruções com o become ... Não necessariamente haverá sempre uma senha
--become-method=BECOME_METHOD
Método utilizado ... Padrão = SUDO ... Outros [su | pbrun | pfexec | doas | dzdo | ksu | runas | machinectl]
--become-user=BECOME_USER
Rode os comandos como este 'usuário' ... Padrão = ROOT ... Não é o mesmo que --become ou -b

ii ) RISCOS E LIMITAÇÕES DO BECOME

Intuitivo mas não perfeito, o become apresenta certas limitações em sua capacidade. O que gera algumas questões “interessantes” a serem avaliadas, para que não se transformem em “desagradáveis”. Todas elas podem ser estudadas no link a seguir:

https://docs.ansible.com/ansible/latest/user_guide/become.html#risks-and-limitations-of-become

  • Riscos de se tornar um usuário sem privilégios
  • Não compatível com todos os plug-ins de conexão
  • Apenas um método pode ser habilitado por host
  • O escalonamento de privilégios deve ser generalista
  • Talvez não seja possível acessar variáveis de ambiente preenchidas por pamd_systemd

CONTINUA (…)

Próximo post >>> LOOPS

REFERÊNCIAS:

https://docs.ansible.com/

https://docs.ansible.com/core.html

https://docs.ansible.com/ansible/latest/

https://docs.ansible.com/ansible/latest/user_guide/index.html

https://docs.ansible.com/ansible/latest/user_guide/index.html#writing-tasks-plays-and-playbooks

https://docs.ansible.com/ansible/latest/user_guide/become.html#become

ANSIBLE Series: Web … Observando a execução de um JOB em tempo real

<head>
       Dedico esse post às mulheres 🌷 Especialmente para todas as  devs,
       sysadmins, engenheiras, pesquisadoras e cientistas 👩🏻‍🔬👩🏻‍💻👩🏻‍🏫👩🏻‍🎓 da computação
       ao redor do globo
</head>

E estamos aqui novamente, de volta ao Ansible. Mais precisamente continuando a parte gráfica, batizada de AWX/Tower. Preciso que resgatem na memória o que vimos no post ANSIBLE Series: Lab … Modo GUI = Web Console

Um resumo rápido e para ajudá-los…

1ª parte – Teoria: o que é AWX, por que foi criado, funções principais, e explicação sobre cada componente integrante da arquitetura.

2ª parte – HOW TO: como instalá-lo usando o método docker-compose.

3ª parte – Mão na massa: adicionar usuários, inventários, hosts, criar projetos e templates na interface web.

Portanto, sendo assim, não pretendo repetir ou me alongar demais nas explicações de cada coisa, seja item ou subitem, seja menu ou submenu, seja aba ou opção. Para que isso ocorra e todos compreendam recomendo a leitura do já citado ANSIBLE Series: Lab … Modo GUI = Web Console … Basta pesquisar no blog ou retroceder alguns artigos, ok? 😏

O que verão a seguir serão apenas telas já com os campos preenchidos por mim, de acordo com as minhas definições e configurações, ou seja, hosts, iventário, chave SSH, repositório GIT, etc. Se por acaso os nomes que você utilizou no laboratório diferem dos meus (o que é bem provável e possível), preste atenção e preencha os campos de acordo com eles.

Ultima chamada e reforço antes da prática de hoje: Caso queira saber/localizar aonde deve clicar selecionar ou digitar em cada passo/etapa no AWX, pare agora, leia e só retorne após o ANSIBLE Series: Lab … Modo GUI… Aaaaahhhhh, vocês já sabem muito bem o quê 😂😂😂😂 Chega de enrolar!!! rsrs

IF (TIMEOUT=TRUE) OR (ERROR=TRUE) THEN:

Control-A

# firewall-cmd --zone=public --add-masquerade --permanent
# firewall-cmd --permanent --add-service=http
# firewall-cmd --permanent --add-service=https
# firewall-cmd --reload

Node-01, Node-02

# systemctl status firewalld
# systemctl stop firewalld
# iptables -L

CRIANDO UMA ORGANIZAÇÃO (…)

Figura 01

ADICIONANDO UM USUÁRIO (…)

Figura 02

DEFININDO INVETÁRIO (…)

Figura 03

ACRESCENTANDO HOSTS (…)

Figura 04

ESTABELENCENDO CREDENCIAL (…)

Figura 05

INICIANDO UM PROJETO (…)

Figura 06

CRIANDO TEMPLATE (…)

Figura 07

RUNNING A JOB (!!!)

Figura 08

(**) Legendas:

Verde -> Sucesso -> OK!
Laranja -> Modificações/Alterações!
Vermelho -> Avisos/Falhas -> ERROR!

https://www.linuxtechi.com/install-ansible-awx-docker-compose-centos-8/

https://en.wikipedia.org/wiki/Margaret_Hamilton_(software_engineer)

https://pt.wikipedia.org/wiki/Margaret_Hamilton_(cientista_da_computa%C3%A7%C3%A3o)

Margareth Hamilton & Apollo 11

Happy women’s day 🙂

ANSIBLE Series: Teoria … 5-V Conceitos Fundamentais

Meados de janeiro (na verdade um pouco além), verão no hemisfério sul, e menos de um mês para o meu aniversário (25 dias precisamente)… Não dá pra reclamar, concordam? 🤔Brincadeiras à parte, e apesar dos pesares que estamos enfrentando localmente e globalmente, só quis encontrar um bom início para nossa conversa de hoje. Algo mais leve. Não é insensibilidade de minha parte, mas sim um artifício para quebrar o gelo, tirar momentaneamente a cabeça dos noticiários e manchetes (segunda onda da Covid-19, aumento de casos e óbitos), e perguntar: o que estão fazendo? como estão?

Pensando na pauta do dia, decidi retomar o Ansible. Não houve motivo específico. Apenas porque gosto, é considerado a ponta do iceberg para vários devops iniciantes, e uma das ferramentas mais legais que conheci nos últimos anos. Sendo assim, o lógico seria continuar de onde paramos, certo? (hands-on, LAB's, aprendizado prático, AWX/Tower) ERRADO! Refleti melhor e achei por bem fazer uma pequena revisão do que já abordei sobre a teoria e reforçar quatro conceitos básicos da automação em TI.

A seguir, faço um compilado bem geral e bastante rápido acerca do que foi discutido em ANSIBLE Series: Teoria … Um papo sobre DevOps

RECAPITULANDO

  • O termo DevOps surge em 2009, na Velocity Conference, um evento da O’Reilly
  • Dois engenheiros da Flickr
  • Palestra “10+ Deploys Per Day: Dev and Ops Cooperation”
  • Em teoria, é uma filosofia, algo maior e mais abrangente
  • Na prática, é a boa e velha empatia, atitude de se colocar no lugar do outro
  • Devs ❤ Sysadmins, e vice-versa
  • Sem muros e barreiras — “já fiz a minha parte”, “o problema não é meu”, “na minha máquina funciona”
  • Gerenciamento de configurações — Escola GCONF, CFEngine, Gerência de Estados
  • Orquestração — Containers, Docker, Kubernetes
  • Ansible — Orquestrador ou Gerenciador?
  • Cartilha GCONF não é totalmente respeitada, ENTÃO
  • Majoritariamente um orquestrador, que eventualmente incorpora e acumula funções de gerenciamento de configuração (opinião deste autor, eu)

RED HAT BLOG … TAG #RedHatShares

https://www.redhat.com/en/blog/tag/red-hat-shares

Newsletter… Ou em bom português: boletim informativo. É exatamente isso que o link acima representa. É o que ele é na verdade, em sua essência mais básica, bem lá no fundo, no seu íntimo. Resumidamente, e conceitualmente, newsletter pode abranger desde uma simples publicação, passando por um editorial, chegando até mesmo em um conteúdo formatado (artigos, notícias, infografias, etc). Para ser chamado assim, ele precisa ter: (a) periocidade; (b) viés / linha / ponto de vista da empresa ou do presente redator/autor; (c) comunicação visual atrativa; e (d) elementos gráficos amigáveis e não exagerados [modelo simples, cores suaves, uso consciente de imagens]. Caso tenha desejo em aprofundar e conhecer um pouco mais, recomendo a seguir dois textos, muito interessantes, que tratam do assunto… Como funciona, como elaborar, dicas e truques, estratégia de marketing/divulgação, entre outros tantos. É rápido e indolor (rsrs!), então confere lá ok? 😉

Muito bem. Voltando. No site oficial da Red Hat, é possível encontrar a parte correspondente ao blog da empresa. São diversos posts categorizados por softwares, produtos e canais. Para buscar, basta acionar os filtros: listando, separando e refinando por tema/tópico/solução/ferramenta.

Cuidado! Alerta de Spoiler!!! Não se assuste com a quantidade de tags e posts no canto lateral esquerdo… Eu sei. Parece uma infinidade. Mas vale a pena cada clique.

Foi assim que descobri uma tag em particular: RED HAT SHARES. Nela foi publicada uma página dedicada exclusivamente sobre ‘automação’ e seus conceitos “satélites”, aqueles que orbitam esse mundo. Daí surgiu o nome do post que escrevo no momento, pois existem 5 conceitos fundamentais para melhor compreensão e prática da automação em TI. Alguns de vocês (inclusive eu) talvez já tenha falado ou escutado tais palavras e ficou na dúvida — “será que estou certo na definição?”, “esqueci alguma coisa?”, ou “simplesmente não sei”. Ressalto que minha intenção não é exaurir o assunto, tão pouco ser perfeccionista ao mínimo dos mínimos detalhes. Não, não se trata disso. Somente quero sintetizar dando uma noção geral de cada um deles, para que não se perca ou passe vergonha numa conversa entre devops, sejam programadores ou sysadmins ou ambos (hahahaha).

I) Provisionamento

Nada mais é do que o processo de configurar a infraestrutura de TI. Sendo este apenas metade do conceito. Explicando melhor, seria uma de duas definições possíveis. Outra abordagem diz que, provisionar é executar as etapas necessárias para: (i) gerenciar o acesso aos dados/recursos, e (ii) torná-los disponíveis para usuários/sistemas.

Independente do significado escolhido, é muito importante não confundir PROVISIONAMENTO com CONFIGURAÇÃO. Eles não são a mesma coisa, e sim etapas no processo de IMPLANTAÇÃO. Para que fique mais claro, uma frase: Depois que algo foi provisionado, a próxima etapa é a configuração.

Quando utilizado o termo “provisionamento”, uma gama de tipos vem à tona: provisionamento de servidor, de rede, de usuário, de serviço e por aí vai.

De servidor…

É o processo de configuração de uma máquina servidora a ser usada dentro de uma rede com base em recursos disponíveis.

Inclui: A – configuração de hardware B – Instalação de software (apps e S.O.) C – Conexão com middleware, outras redes, e armazenamento (bancos de dados).

De usuário…

É um tipo de gerenciamento de identidade que monitora direitos de acesso e privilégios de autorização.

Um usuário é atribuído a um grupo, um grupo é atribuído a funções e uma função é composta de permissões.

Geralmente é acordado entre os setores de TI e recursos humanos.

De rede…

É a configuração de uma rede para ser acessada por usuários, servidores, contêineres, dispositivos IoT, entre outros.

De serviço…

É a configuração de um serviço e o gerenciamento dos dados relacionados a ele.

Para ilustrar, um exemplo. Os usuários obtêm serviços em nuvem por meio de um portal de autoatendimento, sem a necessidade da ajuda da equipe de TI.

II) Gerenciamento de Configuração

Responsável por manter (varredura), e também adequar (correção), sistemas, servidores e softwares em um estado pré-definido. É o processo de garantia para que determinado sistema funcione conforme o esperado, e para que alterações sejam feitas ao longo do tempo, controlando assim todo o planejamento inicial.

Estado desejado, ou estado pré-definido, é uma maneira de fazer referência/alusão à configuração modelo (template) do servidor (ou sistema, ou programa) em questão. Modelo porque se trata do alvo/objetivo/meta a ser perseguido, buscado.

Por que gerenciar configurações?

Evita que pequenas ou grandes modificações sejam executadas erroneamente no ambiente. Uma configuração não documentada, execução manual por alguém desavisado (novato, por exemplo), auto sabotagem, podem ser algumas das circunstâncias que levam a configurações incorretas, e consequentemente, a um desempenho pífio, não satisfatório. Além disso, podem gerar inconsistências que impactam negativamente as operações e a segurança do negócio. Instabilidade e inatividade são alguns do efeitos colaterais sentidos por usuários e clientes.

Do lado técnico, a falta de gerenciamento, documentação, manutenção e controle, acaba levando administradores e desenvolvedores para uma escuridão total, já que os mesmos não são capazes de informar o que há em um servidor específico e qual software nele foi atualizado.

III) Orquestração

Engloba toda a configuração, o gerenciamento e a coordenação de sistemas, aplicativos e serviços. Dentro da TI a mesma auxilia em tarefas e fluxos de trabalho muito complexos, trazendo consigo mais facilidade na gerência.

Sob o guarda-chuva de engenheiros, analistas e programadores, existe um imenso mar de servidores e aplicativos. Gerenciá-los de forma braçal (manual) não é muito inteligente, além de nada escalonável. Maior a complexidade de um ambiente/sistema, maior o esforço para gerenciar as partes envolvidas. Portanto, eis que surge a necessidade de combinar várias tarefas automatizadas e suas configurações dentro de grupos de sistemas ou máquinas. E é exatamente neste ponto que a orquestração entra em cena.

Pausa. Um parênteses importante: automação e orquestração são por definição totalmente diferentes. Ou seja, eles não são o mesmo conceito, tão pouco sinônimos, mas estão sim relacionados. Explicando melhor:

AUTOMAÇÃO

É ponto mais alto do mundo corporativo. Ocorre quando um negócio ou empresa atinge a máxima eficiência e celeridade no processo produtivo, tendo como resultado menor custo e menos erros em sua cadeia de atividades. Geralmente, está ligada à uma única tarefa. Em contraste com a orquestração que lida com um processo ou fluxo de trabalho, mas esse possui várias etapas em vários sistemas distintos. O ideal é criar automação em seus processos para no final orquestrá-los e executá-los automaticamente, com pouca ou nenhuma intervenção humana.

Candidatos: processos automatizados para orquestrar

Provisionamento de servidor , gerenciamento de incidentes, orquestração em nuvem, gerenciamento de banco de dados, orquestração de aplicativos e muitas outras tarefas e fluxos de trabalho.

Ferramentas de orquestração

Os desafios da TI contemporânea são numerosos, difíceis, e distribuídos (guarde bem essa palavra! será relevante no futuro do BLOG). Aplicativos em cluster, múltiplos datacenters, nuvens públicas, privadas e híbridas, softwares com dependências complexas, são apenas alguns exemplos. Ordem correta é a palavra-chave aqui e por isso a importância da ferramenta escolhida.

Atualmente, procurando no mercado, é possível se deparar com inúmeras soluções. Citando três: CHEF, PUPPET e DOCKER. A própria Red Hat oferece duas opções, dependendo da finalidade para uso. Ilustrando melhor, será dito logo abaixo da seguinte maneira:

Cenário/Caso — Plataforma — Tarefas/Ações

Orquestração em nuvem — Ansible — Implantar servidores; Atribuir armazenamento; Criar VMs; Gerência de rede

Orquestração de contêineres — Kubernetes — Dimensionamento de aplicativos; Gerenciar serviços disponibilizados via contêineres

IV) Implantação de Aplicação

Minuciosa demais para ser resumida ou até mesmo cortada. Cada detalhe conta, sua eventual ausência compromete todo o raciocínio e linha de pensamento. Portanto, sendo assim, a teoria completa pode ser lida aqui… É quase meio que obrigatório para uma total compreensão do assunto.

https://www.redhat.com/en/resources/ansible-continuous-integration-delivery-whitepaper

V) Segurança e Conformidade

Ufa! 😓 Eu sei, eu sei… Quase lá. Chegamos no último item (rsrs!) Basicamente é formada por um conjunto de iniciativas. São elas: (A) Definição das políticas de segurança (B) Gerenciamento de risco (C) Identificação e correção de problemas (D) Conversão para etapas totalmente automatizadas (E) Pró-atividade plena, alcançada graças a automação (F) Auditoria e novos requisitos facilmente implementáveis.

Obrigado por sua atenção e companhia ao longo desse post … Mais conceitual do que prático. Forte abraço a todos e até breve 🙂