Tenho um cluster de Raspberry Pis em casa rodando Docker Swarm. Para manter tudo em ordem, todos usam a mesma configuração – usuários, versões do Docker, etc.
Às vezes, algumas atualizações exigem rodar a mesma coisa em todos os nós do cluster – por exemplo – criar uma nova rede macvlan do Docker.
Para fazer isso, é preciso rodar os mesmos comandos em todos os nós manualmente, entrando via ssh em cada um deles, executando os comandos e passando para o próximo.
Como estou tentando reduzir meu trabalho a longo prazo e deixar tudo o mais organizado possível, comecei a procurar maneiras de rodar comandos em todos os nós ao mesmo tempo.
Iteração 1: Script Python customizado
A primeira iteração foi criar um script Python customizado. Por um lado, era para aprender um pouco melhor Python; por outro, eu não tinha encontrado uma forma boa de rodar os comandos de um jeito mais nativo.
Como era de se esperar (ei, ainda tenho pouca experiência com a linguagem 🙂 ), ele virou uma bagunça inchada muito rápido e quebrava com facilidade.
Eu precisava achar outro jeito de fazer isso, sem ter que reaprender o que eu fiz 3 semanas atrás e o que quebrou da última vez.
Iteração 2: pssh
Pesquisando por aí, esbarrei no [pssh](https://linux.die.net/man/1/pssh), que consegue rodar coisas em paralelo via SSH.
Considerando tudo, foi bem fácil colocá-lo para funcionar.
O problema era que, para rodar algumas das coisas, eu precisava executá-las via sudo. Ficar passando senhas por aí não era o ideal, então tive que pesquisar de novo para descobrir como enviar a senha do sudo quando o servidor remoto a pedisse.
Acontece que é bem fácil se você topar com o comentário certo no StackOverflow.
A versão resumida (TL;DR;) é:
stty -echo; printf "Password: "; read PASS; stty echo; echo "${PASS}" | \
pssh -h <HOSTFILE> -o /tmp/output -t 0 -I "`cat ./commands.sh`"O -I "`cat ./commands.sh`" precisa ser feito exatamente assim (entre aspas e crases desse jeito); caso contrário, ele não executa os comandos direito. A senha vai ser enviada como um comando separado, e não captada como entrada do sudo.
A outra pegadinha é que, por causa de como isso está montado, é preciso rodar o sudo com o parâmetro -S, para que ele leia a senha corretamente.