Máquinas remotas via SSH
O --host executa um comando ironflock em outra máquina via SSH em vez de nesta. Com ele, você gerencia dispositivos a partir do seu notebook, inclusive de um Mac, sem instalar o ironflock neles. Informado mais de uma vez, ou com um arquivo de hosts, ele executa o comando em muitas máquinas ao mesmo tempo.
ironflock --host [user@]machine <command> [flags]
ironflock --host [user@]machine --host [user@]machine ... <command> [flags]
ironflock --hosts <file> [--parallel <n>] <command> [flags]Todo comando exceto completion roda em outra máquina dessa forma. --host, --hosts e --parallel são flags globais: podem vir antes ou depois do nome do comando.
Uma máquina
O --host [user@]machine executa o mesmo comando com as mesmas flags nessa máquina. O que ele imprime volta como está, stdout para o stdout e stderr para o stderr, e o mesmo vale para o código de saída.
$ ironflock --host pi@device-17 version
ironflock 2.0.2 linux/arm64
$ ironflock --host pi@device-17 agent remove --yes --json 2>/dev/null
{"action":"removed","removed":[...]}O que a outra máquina precisa ter
- Linux em amd64, arm64 ou ARM de 32 bits (v5 a v7). Outro sistema termina com o código de saída 3.
- Um servidor SSH que executa comandos. Não é preciso
scpnem SFTP. - Um shell de login POSIX: sh, bash, dash ou zsh. csh, tcsh e fish terminam com o código de saída 3 e uma mensagem que diz isso.
- Login como root, ou
sudo, para os comandos que precisam de root (veja Root na outra máquina).
A máquina não precisa ter o ironflock instalado: cada execução leva o seu próprio binário.
Configurações de SSH
O --host usa o ssh desta máquina, então o seu ~/.ssh/config, as suas chaves, o agente SSH e os jump hosts funcionam como funcionam com o ssh. Ele desativa o que o comando não precisa: encaminhamento de agente e de X11, encaminhamentos de porta, um RemoteCommand e um LocalCommand.
O --host aceita [user@]machine e nada mais. Uma porta ou outras opções vão no ~/.ssh/config:
Host device-*
User pi
Port 2222
StrictHostKeyChecking accept-newCom isso, ironflock --host device-17 status faz login como pi na porta 2222, e o ssh aceita a chave de host de um dispositivo que ele ainda não conhece. Um valor de --host que começa com - é recusado, assim como um que tenha outros caracteres além de letras, dígitos, ., _, - e o : e o % de um endereço IPv6.
Uma única conexão SSH atende a toda a execução quando o caminho do seu socket de controle é curto o bastante; o socket é criado na pasta temporária, senão em /tmp. Nesse caso, o ssh pede a senha uma vez. Caso contrário, cada etapa da execução abre a sua própria conexão, e o ssh pede a senha de novo em cada uma.
Um dispositivo configurado pelo ironflock agent install ou pelo IronFlockOS tem um usuário SSH para o proprietário do projeto, que faz login com a chave do arquivo .flock do dispositivo. Acesso SSH mostra o nome do usuário e como extrair a chave do arquivo.
O que acontece na máquina
- O binário. A máquina recebe o binário que roda aqui quando tem a mesma plataforma. Caso contrário, o
ironflockbaixa o binário para a plataforma da máquina de<download base>/cli/<os>/<arch>/<version>/ironflocke o verifica aqui antes de usá-lo: a sua assinatura (.asc) com a chave de release da IronFlock que este binário traz, e as suas informações de build, que precisam indicar o programaironflock, a plataforma da máquina e a mesma revisão de código-fonte deste binário. O download é guardado na sua pasta de cache (~/.cache/ironflockno Linux,~/Library/Caches/ironflockem um Mac) e verificado novamente a cada uso. - A pasta. O binário vai para uma pasta nova que só o usuário de login pode ler (
mktemp -d), em${TMPDIR:-/tmp}na máquina, ou na pasta pessoal do usuário de login quando um programa não pode rodar na pasta temporária (um sistema de arquivos montado comnoexec). Quando ele não pode rodar em nenhuma das duas, o comando termina com o código de saída 3 e indica as duas. Antes de executar qualquer coisa da pasta, a máquina verifica se a pasta e o binário pertencem ao usuário de login e não são links simbólicos, e se o binário é da versão e da plataforma esperadas. - Os arquivos. Os arquivos indicados nas flags do comando vão junto (veja Arquivos indicados em flags).
- O comando. Ele roda como o usuário de login, ou via
sudo(veja Root na outra máquina). - A limpeza. Quando o comando termina, a máquina remove a pasta com o binário e as cópias: também depois de uma falha, de uma conexão perdida e dos sinais HUP, INT, QUIT, TERM, PIPE, USR1 e USR2.
O --host não deixa nenhum ironflock na máquina, também depois de agent install. Continue a partir daqui com --host, ou instale o ironflock na máquina com a linha de instalação, que sem argumentos apenas o instala. O self-update com --host atualiza esse /usr/local/bin/ironflock da máquina, não o binário da execução (ironflock self-update).
Uma pasta ironflock.* fica na máquina em dois casos:
- Depois de uma queda de energia ou de um
kill -9na máquina enquanto o comando roda. A pasta contém o binário e as cópias. - Quando a conexão se perde depois da cópia e antes de o comando começar, ou quando a execução é interrompida aqui enquanto a etapa que inicia o comando se conecta. A pasta contém o binário e também as cópias, quando você executou o comando em um terminal.
A cópia de um arquivo .flock contém o segredo do dispositivo, a de um arquivo de senha de WiFi, a senha do WiFi, e a de um arquivo de senha de proxy, a senha do proxy. Só o usuário de login e o root podem lê-las. Remova uma pasta assim manualmente.
Arquivos indicados em flags
| Flag | Comandos |
|---|---|
-c, --config (o arquivo .flock) | agent install, agent configure, doctor, os flash, os install, os reset |
--wifi-password-file | os flash |
--proxy-password-file | agent install, agent configure, os install |
Cada arquivo é lido aqui, e um caminho relativo é relativo à pasta de trabalho desta máquina. Um arquivo de senha de WiFi ou de proxy pode ser um pipe (/dev/stdin), que é lido uma vez. O conteúdo vai para a máquina pela entrada padrão da conexão SSH. Nem o arquivo nem o seu tamanho ficam em uma linha de comando, aqui ou na máquina, onde todo usuário pode ler as linhas de comando. A máquina compara cada tamanho com o maior que o comando aceita e, depois, verifica se tudo chegou.
Na máquina, a cópia é <folder>/1/device.flock: em uma pasta própria (modo 0700) dentro da pasta da execução, com o nome que tem aqui e modo 0600. O comando lá recebe esse caminho, por exemplo --config=/tmp/ironflock.k3Xf9QpL2m/1/device.flock, de modo que um erro sobre o conteúdo do arquivo indica a cópia.
Estes casos encerram o comando nesta máquina:
- Código de saída 1 — um arquivo que não é um arquivo regular (um arquivo de senha de WiFi ou de proxy também pode ser um pipe), ou um arquivo maior do que o comando aceita: 5 MiB para um arquivo
.flock, 4096 bytes para um arquivo de senha de WiFi ou de proxy. - Código de saída 2 — um nome de arquivo com um caractere de controle.
- Código de saída 2 —
--image-filee--outputdeos flash. O--hostnão copia nenhuma imagem para a máquina e não traz nenhum arquivo de volta. Execute esse comando aqui sem--host, ou na própria máquina. Sem--image-file, a própria máquina baixa a imagem.
Root na outra máquina
- Um comando que precisa de root roda via
sudoquando o usuário de login não é root. Umsudosem senha e sem terminal funciona em qualquer situação. version,os imageseos drivesrodam como o usuário de login.statusedoctorleem mais com root. Eles rodam como root quando o usuário de login é root ou pode usarsudosem senha e sem terminal. Caso contrário, rodam como o usuário de login, sem perguntar, e a dica deles indica o comando com--host root@machine.agent logslê um arquivo do root e roda viasudo.- Quando o
sudopede uma senha, ou a configuração dele exige um terminal (requiretty), ele precisa de um terminal na máquina. Para isso, é preciso um terminal no stdin, no stdout e no stderr aqui. Sem ele, o comando termina com o código de saída 3 antes que algo seja copiado. Nesse caso, faça login como root, permita que o usuário de login usesudosem senha e sem terminal, ou execute o comando em um terminal sem redirecionamento. - Um
sudoque recusa quando o comando está prestes a rodar também termina com o código de saída 3.
O que o comando lá diz para executar em seguida indica um comando para este lado, sem sudo, já que o --host obtém root sozinho: ironflock --host pi@device-17 agent start.
Terminal, perguntas e saída
- Com um terminal aqui, o comando também recebe um na máquina, para poder fazer as suas perguntas. O stdout e o stderr dele voltam então juntos, no seu terminal.
- Sem terminal aqui (um pipe,
--jsonpara um programa, CI), o stdout e o stderr ficam separados, e o comando não pergunta nada:--yesconfirma. O que os arquivos do usuário de login na máquina imprimem, como um.bashrcque faz echo, é descartado do stdout, para que o stdout traga apenas o resultado do comando. --yes,--jsone as flags do comando vão junto. A base de download vai junto como--download-base: a flag, ou oIRONFLOCK_DL_BASEdesta máquina. Uma base de download com credenciais (https://user:[email protected]/dl) termina com o código de saída 2 antes que qualquer máquina seja alcançada, pois na máquina ela ficaria em uma linha de comando que todo usuário ali pode ler.--help,help, um grupo sem comando ecompletionsão respondidos aqui: o que imprimem é o mesmo em toda máquina.- O que a máquina envia no stdout antes de o comando rodar (as suas respostas e o texto dos arquivos do usuário de login) é lido até 64 KiB. Mais do que isso encerra a execução com o código de saída 1 antes que o comando rode lá.
Ctrl-C e conexões perdidas
O Ctrl-C aqui chega ao comando lá como chegaria um Ctrl-C no próprio terminal dele, e uma conexão perdida chega a ele como um hangup, com e sem terminal aqui. Depois do Ctrl-C, o --host espera até 15 segundos para que a máquina diga que o comando lá terminou, com o seu código de saída (130 quando o Ctrl-C o encerrou). Quando a máquina não diz isso a tempo, ou a conexão termina antes, o --host termina com 130 e diz que o comando ainda pode estar rodando lá. Uma execução cujo comando ainda não tinha começado quando veio o Ctrl-C não o inicia.
O os install com --host tem regras próprias: depois que a sua pergunta é respondida, uma conexão perdida não o interrompe mais, e o comando espera aqui até que a máquina volte como IronFlockOS; veja ironflock os install.
Códigos de saída e erros
Os códigos de saída são os do comando (Códigos de saída). O --host acrescenta estes:
| Código | Significado |
|---|---|
| 255 | o ssh falhou: sem conexão, login ou chave de host recusados, uma conexão que caiu |
| 3 | a máquina não pode executar o comando: outro sistema ou CPU, um shell de login que não é um shell POSIX, nenhuma pasta onde um programa possa rodar, um sudo que não permite o usuário de login |
| 130 | uma interrupção, aqui (Ctrl-C) ou do comando na máquina (um hangup, uma interrupção ou um sinal de término lá) |
Uma falha do próprio --host é um erro como qualquer outro: uma linha Error: no stderr ou, com --json, o objeto de erro no stdout. A única exceção: quando a saída do comando já tinha chegado, essa saída é o resultado, e o erro é apenas a linha Error: no stderr, também com --json.
Várias máquinas
O --host informado mais de uma vez, ou --hosts <file>, executa o comando em cada máquina, como o --host o executa em uma. As máquinas de --host vêm primeiro, depois as do arquivo. Um arquivo de hosts com uma só máquina roda como rodam várias máquinas.
$ ironflock --host pi@vm1 --host pi@vm2 --host pi@vm3 status
pi@vm2: Agent: installed in /opt/ironflock/device-agent
pi@vm2: Version: 1.6.9
pi@vm2: Service: running (ironflock-device-agent.service)
pi@vm3: ssh: connect to host vm3 port 22: Connection timed out
pi@vm3: Error: the SSH connection to pi@vm3 failed
pi@vm1: Agent: installed in /opt/ironflock/device-agent
...
Summary of "status" on 3 machines, exit code 255: 2 done, 1 ssh.
pi@vm1 done
pi@vm2 done
pi@vm3 255 ssh: the SSH connection to pi@vm3 failed (ssh: connect to host vm3 port 22: Connection timed out)O arquivo de hosts
O arquivo indica um [user@]machine por linha. Um # inicia um comentário, que vai até o fim da linha, e linhas vazias são ignoradas. O arquivo também pode ser um pipe, como --hosts <(...), e tem no máximo 1 MiB.
# Linha de embalagem 3
pi@device-17
pi@device-18
pi@device-19 # the spare unit# Mostrar o estado de cada máquina do arquivo, 20 por vez
ironflock --hosts line3.txt --parallel 20 status
# Atualizar o agente em cada máquina do arquivo; o agent update pergunta, então --yes é necessário
ironflock --hosts line3.txt agent update --yes
# Dar aos dispositivos de um local uma única conta de proxy; a senha vem de um arquivo
ironflock --hosts site-a.txt agent configure --https-proxy http://[email protected]:3128 --proxy-password-file proxy-password.txt --yesEstes casos terminam com o código de saída 2 antes que algo rode, e o erro indica o arquivo e a linha:
- uma linha com mais de uma palavra;
- uma máquina que o
--hostrecusaria; - uma máquina indicada duas vezes. Também conta como duas vezes a mesma máquina com dois usuários, pois o comando rodaria nela duas vezes ao mesmo tempo. Um endereço e um nome da mesma máquina não são reconhecidos como iguais.
Execuções paralelas
No máximo --parallel máquinas rodam ao mesmo tempo: 10 sem a flag, de 1 a 100. Elas começam na ordem informada, e a próxima começa quando uma termina. --parallel sem várias máquinas termina com o código de saída 2.
SSH sem perguntas
Nenhuma máquina recebe um terminal, e o ssh não pergunta nada (BatchMode=yes). Estes casos falham nessa máquina com o código de saída 255 e as palavras do próprio ssh, e as outras máquinas continuam:
- um usuário de login que exige senha;
- uma chave cuja senha não está no agente SSH;
- uma chave de host que o
sshainda não conhece.
Conecte-se uma vez com o ssh para aceitar uma nova chave de host, ou defina StrictHostKeyChecking accept-new para essas máquinas no ~/.ssh/config, como no exemplo acima. O ssh desiste de conectar após 30 segundos (ConnectTimeout=30, independentemente do que diga o ~/.ssh/config), então uma máquina desligada é informada nesse momento. Um sudo lá que exige senha ou terminal termina com o código de saída 3 nessa máquina; status e doctor rodam então como o usuário de login.
Saída de várias máquinas
- Cada linha que uma máquina escreve chega inteira, com
<host>:na frente: o stdout dela no stdout, o stderr dela no stderr. As linhas das máquinas se misturam na ordem em que chegam. - Uma última linha sem quebra de linha recebe uma. Uma linha com mais de 64 KiB chega em partes de 64 KiB, cada uma com o host na frente.
- Caracteres de controle além do tab chegam escapados (
\x1b,\r), nas linhas e no resumo, para que nenhuma máquina mova o cursor ou escreva por cima da linha de outra máquina. Um retorno de carro no fim de uma linha é descartado. - Uma execução que falha aqui acrescenta a sua linha
Error:com o host na frente, como o--hosta escreve para uma máquina. - No fim, o stderr recebe um resumo: o código de saída e quantas máquinas terminaram de cada forma, depois uma linha para cada máquina na ordem informada. A linha diz
done, ou o código de saída, o seu tipo e o motivo: o erro aqui (para 255, com as palavras do própriossh) ou a linhaError:do comando. Uma máquina que não confirmou o fim do seu comando depois do Ctrl-C aparece comointerrupted, may still run.
Código de saída com várias máquinas
O comando termina com o pior código de saída entre as máquinas: 0 quando todas as máquinas terminaram com 0. Caso contrário, a partir do pior:
- 130 — interrompido, aqui ou em uma máquina.
- 1 — o comando falhou em uma máquina, o que pode tê-la deixado parcialmente alterada, seja qual for o código com que terminou lá.
- 255 — uma máquina não foi alcançada, ou a conexão caiu.
- 3 — uma máquina não estava no estado de que o comando precisa, ou não pode executá-lo.
- 4 — uma pergunta foi respondida com não.
O código de saída 2 é uma linha de comando incorreta aqui, como em todo comando.
Linhas JSON
Com --json, o stdout recebe uma linha para cada máquina quando o comando dela termina, na ordem em que terminam, e nada mais. Um programa lê as linhas à medida que chegam.
{"host":"pi@vm1","state":"done","exit_code":0,"result":{...}}| Campo | Significado |
|---|---|
host | a máquina como o --host ou o arquivo de hosts a indica |
state | done: o comando terminou com 0. failed: terminou com outro código lá, ou a execução falhou aqui. interrupted: a execução foi interrompida, e a máquina disse que o comando terminou. may_still_run: a execução foi interrompida aqui, e a máquina não disse, dentro do tempo de espera, que o comando terminou. not_started: a execução foi interrompida antes de chegar a vez da máquina; nada rodou lá. |
exit_code | como o comando terminou na máquina, ou como a execução terminou aqui: 255 quando a máquina não foi alcançada ou a conexão caiu, 3 quando a máquina não pode executar o comando, 130 quando a execução foi interrompida. Outro código, como 137 depois de um kill, é o da máquina, sem alteração, com o estado failed. |
result | o que o comando escreveu com --json, como a página do comando o descreve. Para agent logs, o array das suas linhas; no máximo 16 MiB são mantidos. Um comando que escreve o seu resultado e termina com 1 (doctor, agent update) também o tem. |
error | por que o comando não terminou com 0, com kind e message: o erro da execução aqui (tipo ssh para uma máquina que não foi alcançada, com a mensagem terminando com as palavras do ssh entre parênteses), senão o objeto de erro do comando, senão um objeto montado a partir do código de saída dele e da sua última linha no stderr |
output | o que o comando escreveu no stdout que não é JSON; ou, quando escreveu mais de 16 MiB, uma frase que diz isso |
O stderr tem as linhas das máquinas, entre elas a linha Error: própria de um comando que a escreve com --json (agent update), e o resumo. Os erros das execuções aqui estão apenas nas linhas do stdout.
# As máquinas em que o status não terminou com 0
ironflock --hosts line3.txt status --json 2>/dev/null | jq -r 'select(.state != "done") | .host'Ctrl-C em várias máquinas
Ctrl-C, SIGTERM ou SIGHUP encerra as execuções como encerra uma execução em uma máquina: cada comando lá o recebe, e cada máquina tem 15 segundos para confirmar que o seu comando terminou. Uma máquina que não confirma fica como may_still_run. As máquinas cuja vez ainda não chegou não executam nada. O resumo as lista como not started, e o comando termina com 130.
Quais comandos rodam em várias máquinas
| Comandos | Em várias máquinas |
|---|---|
version, status, doctor, os images, os drives, agent restart, agent start | sempre |
agent logs | sempre; com --follow, não com --json, pois a linha de uma máquina chega quando o comando dela termina, e o --follow não termina |
agent stop, agent update, agent configure, agent remove, os update, os rollback, self-update | com --yes: eles perguntam, e em várias máquinas ao mesmo tempo ninguém é perguntado |
completion | respondido aqui e em nenhuma máquina, como o --help |
agent install, os install, os flash, os reset | nunca: o arquivo .flock deles indica um único dispositivo, ou eles apagam um disco, uma unidade ou os dados de um dispositivo depois de uma pergunta que indica a única máquina |
Uma flag que indica um arquivo nesta máquina é recusada com várias máquinas, pois o arquivo iria para todas elas: o -c de doctor e de agent configure indica um único dispositivo. A exceção é o --proxy-password-file de agent configure, para uma única conta de proxy para as máquinas de um local.
Uma linha de comando que não roda em várias máquinas termina com o código de saída 2 e diz por quê, antes que o arquivo de hosts seja lido e antes que qualquer máquina seja alcançada.