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: 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