Quem administra múltiplos servidores Linux no dia a dia sabe que rotinas manuais de provisionamento de contas e controle de privilégios (sudo/wheel) são portas abertas para erros operacionais e inconsistências.
Em ambientes híbridos, onde parte das máquinas roda sob painéis como WHM/cPanel e parte opera em distribuições Linux puras, o desafio é ainda maior: como garantir que a mesma rotina de criação e remoção de usuários funcione de forma padronizada, segura e auditável em dezenas de servidores?
Neste artigo, compartilho a evolução prática de uma ferramenta de automação: desde a criação de um script Bash híbrido com auto-configuração de logrotate até a sua orquestração distribuída via Ansible sem precisar reescrever a lógica original.
1. O ponto de partida: o script Bash híbrido#
O objetivo inicial foi construir um utilitário CLI (jvx_mngr) capaz de automatizar a criação (-a) e a remoção (-d) de contas administrativas, adaptando-se automaticamente ao ambiente de destino.
Requisitos técnicos do script:#
- Validação de Execução e Parâmetros: Checar privilégios de
roote validar argumentos viagetopts. - Abordagem Híbrida (WHM API vs. Linux Nativo):
- Se o utilitário
whmapi1estiver presente no sistema, invocar a API nativa do WHM (createacctcomreseller_without_domain=1ouremoveacct) e aplicar listas de controle de acesso (ACLs). - Se o servidor for Linux padrão (sem WHM), utilizar comandos nativos do sistema operacional (
useradd,chpasswd,chmod 711,userdel -re inclusão no grupowheel/sudo).
- Proteção Contra Erros Humanos: Um array de contas protegidas (
USUARIO_PROTEGIDO=(admin_master backup_user root_corp)) que bloqueia imediatamente qualquer tentativa de exclusão acidental. - Auditoria Centralizada: Gravação de logs com data, hora, analista executor (
whoami) e hostname em/var/log/jvx_mngr.log.
Auto-provisionamento inteligente do logrotate#
Para evitar que o log crescesse indefinidamente e sem exigir que a equipe configurasse regras manuais em cada máquina, incluí uma função interna de auto-provisionamento do logrotate:
# --- Configuração do Logrotate ---
function configurar_logrotate() {
local LOGROTATE_CONFIG="/etc/logrotate.d/jvx_mngr"
if [[ -f "${LOGROTATE_CONFIG}" ]]; then
return 0
fi
print_info "Criando arquivo de configuração para o logrotate em ${LOGROTATE_CONFIG}..."
cat <<'EOF' > "${LOGROTATE_CONFIG}"
# Configuração do Logrotate para o script jvx_mngr
/var/log/jvx_mngr.log {
monthly
rotate 6
compress
delaycompress
missingok
notifempty
create 640 root root
}
EOF
if [[ $? -eq 0 ]]; then
chmod 644 "${LOGROTATE_CONFIG}"
print_success "Arquivo de configuração do logrotate criado com sucesso."
log "Criada configuração do logrotate em ${LOGROTATE_CONFIG}."
else
print_error "Falha ao criar o arquivo de configuração do logrotate."
log "ERRO: Falha ao criar a configuração do logrotate em ${LOGROTATE_CONFIG}."
fi
}
Ao rodar essa função no início da execução principal (main), o script garante idempotência: se o arquivo já existir em /etc/logrotate.d/, ele segue silencioso; se não existir, cria a regra de rotação mensal com compressão, retenção de 6 ciclos e permissão 640.
2. O desafio de escalar: orquestrar sem reescrever#
Com o script testado e homologado localmente, o passo seguinte foi rodar essa mesma operação em múltiplos servidores simultaneamente usando Ansible.
Muitas equipes caem na tentação de tentar converter toda a lógica procedural do Bash para dezenas de tarefas nativas do Ansible. Na prática, essa reescrita gera riscos de regressão em chamadas complexas de API (como a whmapi1) e fallbacks de terminal. A abordagem mais inteligente é adotar o Ansible como o orquestrador/maestro e manter o script Bash como a ferramenta especialista.
Divisão em dois playbooks#
Para manter o ambiente desacoplado e limpo:
- Playbook de Instalação (
instalar_jvx_mngr.yml): Copia o script para/usr/local/bin(ou caminho padronizado na infraestrutura) e define a permissão0755. É executado apenas no provisionamento do servidor ou em atualizações de versão. - Playbook de Operação Diária (
usar_jvx_mngr.yml): Responsável por interagir com o operador no terminal e disparar o comando existente nos servidores remotos.
3. Resolvendo desafios de interface no Ansible#
Durante a criação do playbook operacional, surgiram dois obstáculos visuais e de fluxo de entrada:
Problema 1: Banner ASCII quebrado no módulo debug#
Ao exibir um banner de boas-vindas com o módulo nativo debug: msg:, o Ansible interpretou as quebras de linha como caracteres escapados (\n) dentro de um envelope JSON:
TASK [Mostrando o banner de execução do Ansible] **************************************
ok: [localhost] => {
"msg": "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⢴⣃\n⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⢴⣫⢗⡯⡖..."
}
Solução: O módulo debug formata variáveis, não arte textual crua. A solução foi executar uma tarefa em localhost usando o módulo shell com um Here Document (cat <<'EOF'), que envia o fluxo diretamente ao stdout do terminal:
- name: Mostrando o banner com o módulo shell
shell: |
cat <<'EOF'
[ARTE ASCII AQUI]
EOF
args:
warn: false
Problema 2: Exibir instruções antes do vars_prompt#
O vars_prompt do Ansible é bloqueante e dispara antes de qualquer task do play. Para exibir orientações (como avisar que na opção de deletar -d basta teclar [Enter] nos campos de e-mail e nível), estruturamos a execução em dois plays encadeados no mesmo arquivo YAML:
- Play 1 (
hosts: localhost): Executa na máquina local, imprime o banner e o quadro textual de instruções. - Play 2 (
hosts: servidores): Entra em seguida, aciona ovars_promptcom o operador já instruído e executa o binário nos hosts remotos.
4. O playbook operacional completo#
# usar_jvx_mngr.yml
# --- Play 1: Interface e Instruções na Máquina Local ---
- name: Exibir Banner e Instruções
hosts: localhost
gather_facts: no
tasks:
- name: Mostrando o banner
shell: |
cat <<'EOF'
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⢴⣃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⢴⣫⢗⡯⡖⠀⠀⠀⠀⠀⢠⡄⠀⠀⠀⠀⠀⠀⠀⠀⢠⡤⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⢨⢷⡹⢮⣳⠇⠀⠀⠀⠀⠀⠈⠁⠀⠀⠀⠀⠀⠀⠀⠀⠈⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠠⠐⣀⠂⡀⢸⢧⡻⣝⢮⡏⠀⠀⠀⠀⠀⢸⡇⢀⣾⠟⠿⠻⠿⣷⠀⢸⣏⠀⣿⡟⠿⠻⠿⣶⡀⢸⣿⠀⠀⠀⢀⣿⠃⢸⡏⠀⠙⢿⣦⣀⣼⡟⠁⠀⠀
⠀⠀⠤⠑⡈⢡⠀⠆⡁⢢⣉⠓⢯⡳⡇⠀⠀⠀⠀⠀⢸⡇⠨⣿⠀⠀⠀⠀⣿⡁⢸⡧⠀⣿⡂⠀⠀⠀⢿⡃⢸⡷⠀⠀⢠⣾⠋⠀⢸⡗⠀⠀⠀⣹⣿⣇⠀⠀⠀⠀
⠀⠀⠀⠀⠁⠂⡌⠐⡄⢡⠢⡙⢤⠉⠇⠀⠀⠀⠀⠀⢸⡇⠈⣿⣤⣤⣤⣴⡿⠁⢸⡧⠀⣿⡅⠀⠀⠀⢿⡇⢘⣿⣤⡾⠟⠁⠀⠀⢸⡧⠀⢠⣾⠟⠈⢻⣦⡀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠡⠐⢨⡑⠘⠀⠀⠀⠀⠀⠀⠀⠀⣸⡇⠀⠀⠉⠉⠉⠈⠁⠀⠈⠁⠀⠉⠀⠀⠀⠀⠉⠁⠀⠉⠁⠀⠀⠀⠀⠀⠈⠁⠀⠉⠁⠀⠀⠀⠉⠉⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠿⠻⠟⠟⠁⠀Gerenciamento de Usuários via Ansible
EOF
args:
warn: false
- name: Mostrando as instruções de uso
shell: |
cat <<'EOF'
------------------------------------------------------------------------------------
INSTRUÇÕES:
- A seguir, informe os dados para a operação nos servidores de destino.
- Para a ação de DELETAR (-d), você pode pressionar [Enter] nos campos "email" e "nível".
------------------------------------------------------------------------------------
EOF
args:
warn: false
# --- Play 2: Coleta de Dados e Execução Remota nos Servidores ---
- name: Usar o script jvx_mngr para gerenciar usuários
hosts: servidores_alvo
become: yes
vars_prompt:
- name: "acao"
prompt: "Qual ação deseja executar? ('-a' para adicionar, '-d' para deletar)"
private: no
- name: "usuario"
prompt: "Digite o nome do usuário"
private: no
- name: "email"
prompt: "Digite o email (pressione Enter se estiver deletando)"
private: no
default: ""
- name: "nivel"
prompt: "Digite o nível de ACL (n1, n2, n3) (pressione Enter se estiver deletando)"
private: no
default: ""
tasks:
- name: Executando jvx_mngr nos hosts remotos
command:
cmd: "/usr/local/bin/jvx_mngr {{ acao }} {{ usuario }} {{ email }} {{ nivel }}"
register: command_output
- name: Exibir a saída da execução remota
debug:
var: command_output.stdout_lines
Lições aprendidas e boas práticas#
- Evite o Refactoring Desnecessário: Scripts consolidados em Bash com tratamento fino de APIs legadas (como
whmapi1) funcionam muito bem quando combinados com a capacidade de entrega e paralelismo do Ansible. - Desacople Instalação de Uso: Separar o playbook de implantação do playbook de rotina operacional economiza tráfego de rede e torna o uso diário mais rápido e direto.
- Ergonomia no Terminal Importa: Formatar saídas de forma legível e exibir avisos antes de campos de entrada evita falhas humanas em manutenções em lote.
Este artigo foi útil?
Deixe uma reação rápida para apoiar o conteúdo:
Este post está licenciado sob CC BY-NC.



Comentários
Participe da discussão abaixo.
0 comentários