Macchine remote via SSH
--host esegue un comando ironflock su un’altra macchina via SSH invece che su questa. Lo usi per gestire i dispositivi dal tuo laptop, anche da un Mac, senza installarvi ironflock. Indicato più volte, o con un file degli host, esegue il comando su molte macchine contemporaneamente.
ironflock --host [user@]machine <command> [flags]
ironflock --host [user@]machine --host [user@]machine ... <command> [flags]
ironflock --hosts <file> [--parallel <n>] <command> [flags]Ogni comando tranne completion può essere eseguito in questo modo su un’altra macchina. --host, --hosts e --parallel sono flag globali: possono stare prima o dopo il nome del comando.
Una macchina
--host [user@]machine esegue lo stesso comando con gli stessi flag su quella macchina. Ciò che stampa torna così com’è, stdout su stdout e stderr su stderr, e lo stesso vale per il suo codice di uscita.
$ 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":[...]}Cosa serve sull’altra macchina
- Linux su amd64, arm64 o ARM a 32 bit (da v5 a v7). Un altro sistema termina con il codice di uscita 3.
- Un server SSH che esegue comandi. Non servono né
scpné SFTP. - Una shell di login POSIX: sh, bash, dash o zsh. csh, tcsh e fish terminano con il codice di uscita 3 e un messaggio che lo indica.
- Un utente di login root, oppure
sudo, per i comandi che richiedono root (vedi Root sull’altra macchina).
Sulla macchina non serve che ironflock sia installato: ogni esecuzione porta con sé il proprio binario.
Impostazioni SSH
--host usa l’ssh di questa macchina, quindi il tuo ~/.ssh/config, le chiavi, l’agente SSH e i jump host funzionano come con ssh. Disattiva ciò che non serve al comando: l’inoltro dell’agente e di X11, gli inoltri di porta, un RemoteCommand e un LocalCommand.
--host accetta [user@]machine e nient’altro. Una porta o altre opzioni vanno in ~/.ssh/config:
Host device-*
User pi
Port 2222
StrictHostKeyChecking accept-newCosì ironflock --host device-17 status accede come pi sulla porta 2222, e ssh accetta la chiave host di un dispositivo che non conosce ancora. Un valore di --host che inizia con - viene rifiutato, così come uno che contiene caratteri diversi da lettere, cifre, ., _, - e dai : e % di un indirizzo IPv6.
Una sola connessione SSH serve l’intera esecuzione quando il percorso del suo socket di controllo è abbastanza corto; il socket viene creato nella cartella temporanea, altrimenti in /tmp. In quel caso ssh chiede la password una sola volta. Altrimenti ogni passo dell’esecuzione apre una propria connessione, e ssh la chiede di nuovo per ciascuna.
Un dispositivo configurato da ironflock agent install o da IronFlockOS ha un utente SSH per il proprietario del progetto, che accede con la chiave del file .flock del dispositivo. Accesso SSH mostra il nome utente e come estrarre la chiave dal file.
Cosa succede sulla macchina
- Il binario. La macchina riceve il binario in esecuzione qui quando ha la stessa piattaforma. Altrimenti
ironflockscarica il binario per la piattaforma della macchina da<download base>/cli/<os>/<arch>/<version>/ironflocke lo verifica qui prima di usarlo: la sua firma (.asc) con la chiave di release di IronFlock contenuta in questo binario, e le sue informazioni di build, che devono indicare il programmaironflock, la piattaforma della macchina e la stessa revisione dei sorgenti di questo binario. Il download viene conservato nella tua cartella della cache (~/.cache/ironflocksu Linux,~/Library/Caches/ironflocksu un Mac) e verificato di nuovo a ogni utilizzo. - La cartella. Il binario va in una nuova cartella leggibile solo dall’utente di login (
mktemp -d), sotto${TMPDIR:-/tmp}sulla macchina, oppure nella home dell’utente di login quando nella cartella temporanea non si può eseguire un programma (un file system montatonoexec). Quando non si può eseguire in nessuna delle due, il comando termina con il codice di uscita 3 e le indica entrambe. Prima di eseguire qualcosa dalla cartella, la macchina verifica che la cartella e il binario appartengano all’utente di login e non siano link simbolici, e che il binario abbia la versione e la piattaforma attese. - I file. I file indicati nei flag del comando vengono trasferiti insieme al binario (vedi File indicati nei flag).
- Il comando. Viene eseguito come utente di login, oppure tramite
sudo(vedi Root sull’altra macchina). - La pulizia. Quando il comando termina, la macchina rimuove la cartella con il binario e le copie: anche dopo un errore, dopo una connessione persa e dopo i segnali HUP, INT, QUIT, TERM, PIPE, USR1 e USR2.
--host non lascia alcun ironflock sulla macchina, nemmeno dopo agent install. Prosegui con --host da qui, oppure installa ironflock sulla macchina con la riga di installazione, che senza argomenti si limita a installarlo. self-update via --host aggiorna quel /usr/local/bin/ironflock della macchina, non il binario dell’esecuzione (ironflock self-update).
Una cartella ironflock.* resta sulla macchina in due casi:
- Dopo un’interruzione di corrente o un
kill -9sulla macchina mentre il comando è in esecuzione. La cartella contiene il binario e le copie. - Quando la connessione si perde dopo la copia e prima dell’avvio del comando, oppure l’esecuzione viene interrotta qui mentre si connette il passo che avvia il comando. La cartella contiene il binario, e anche le copie se hai eseguito il comando a un terminale.
La copia di un file .flock contiene il segreto del dispositivo, la copia di un file con la passphrase contiene la passphrase WiFi, la copia di un file con la password contiene la password del proxy. Solo l’utente di login e root possono leggerle. Rimuovi a mano una cartella di questo tipo.
File indicati nei flag
| Flag | Comandi |
|---|---|
-c, --config (il file .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 |
Ogni file viene letto qui, e un percorso relativo è relativo alla cartella di lavoro di questa macchina. Un file con passphrase o password può essere una pipe (/dev/stdin), che viene letta una volta. Il contenuto arriva alla macchina sullo standard input della connessione SSH. Né un file né la sua dimensione compaiono su una riga di comando, né qui né sulla macchina, dove ogni utente può leggere le righe di comando. La macchina confronta ogni dimensione con il massimo accettato dal comando, e poi verifica che sia arrivato tutto.
Sulla macchina, la copia è <folder>/1/device.flock: in una propria cartella (modo 0700) all’interno della cartella dell’esecuzione, con il nome che ha qui e modo 0600. Il comando lì riceve quel percorso, ad esempio --config=/tmp/ironflock.k3Xf9QpL2m/1/device.flock, quindi un errore sul contenuto del file indica la copia.
Questi casi terminano il comando su questa macchina:
- Codice di uscita 1 — un file che non è un file regolare (un file con passphrase o password può anche essere una pipe), oppure uno più grande di quanto accetta il comando: 5 MiB per un file
.flock, 4096 byte per un file con passphrase o password. - Codice di uscita 2 — un nome di file con un carattere di controllo.
- Codice di uscita 2 —
--image-filee--outputdios flash.--hostnon copia alcuna immagine sulla macchina e non riporta indietro alcun file. Esegui quel comando qui senza--host, oppure sulla macchina stessa. Senza--image-file, la macchina scarica l’immagine da sola.
Root sull’altra macchina
- Un comando che richiede root viene eseguito tramite
sudoquando l’utente di login non è root.sudosenza password e senza terminale funziona ovunque. version,os imageseos drivesvengono eseguiti come utente di login.statusedoctorleggono di più con root. Vengono eseguiti come root quando l’utente di login è root o può usaresudosenza password e senza terminale. Altrimenti vengono eseguiti come utente di login, senza chiedere, e il loro suggerimento indica il comando con--host root@machine.agent logslegge un file di root e viene eseguito tramitesudo.- Quando
sudochiede una password, o la sua configurazione vuole un terminale (requiretty), serve un terminale sulla macchina. Per questo serve un terminale qui su stdin, stdout e stderr. Senza, il comando termina con il codice di uscita 3 prima che venga copiato qualcosa. In quel caso accedi come root, consenti all’utente di login di usaresudosenza password e senza terminale, oppure esegui il comando a un terminale senza reindirizzamenti. - Anche un
sudoche rifiuta quando il comando sta per essere eseguito termina con il codice di uscita 3.
Il comando successivo che il comando remoto ti indica di eseguire è un comando per questo lato, senza sudo, perché --host ottiene root da solo: ironflock --host pi@device-17 agent start.
Terminale, domande e output
- Con un terminale qui, il comando ne riceve uno anche sulla macchina, così può porre le sue domande. Il suo stdout e il suo stderr tornano allora insieme, sul tuo terminale.
- Senza un terminale qui (una pipe,
--jsonverso un programma, la CI), stdout e stderr restano separati, e il comando non chiede nulla:--yesconferma. Ciò che stampano i file dell’utente di login sulla macchina, ad esempio un.bashrcche usa echo, viene eliminato da stdout, così che stdout contenga solo il risultato del comando. --yes,--jsone i flag del comando vengono passati alla macchina. La base di download viene passata come--download-base: il flag, oppureIRONFLOCK_DL_BASEdi questa macchina. Una base di download con credenziali di login (https://user:[email protected]/dl) termina con il codice di uscita 2 prima che venga raggiunta qualsiasi macchina, perché sulla macchina si troverebbe su una riga di comando che lì ogni utente può leggere.--help,help, un gruppo senza comando ecompletionricevono risposta qui: ciò che stampano è uguale su ogni macchina.- Ciò che la macchina invia su stdout prima che il comando venga eseguito (le sue risposte e il testo dei file dell’utente di login) viene letto fino a 64 KiB. Una quantità maggiore termina l’esecuzione con il codice di uscita 1 prima che il comando venga eseguito lì.
Ctrl-C e connessioni perse
Ctrl-C qui raggiunge il comando remoto come lo raggiungerebbe un Ctrl-C al suo terminale, e una connessione persa lo raggiunge come un hangup, con e senza un terminale qui. Dopo Ctrl-C, --host attende fino a 15 secondi che la macchina comunichi che il comando è terminato, con il suo codice di uscita (130 quando lo ha terminato Ctrl-C). Se la macchina non lo comunica in tempo, o la connessione termina prima, --host termina con 130 e dice che il comando potrebbe essere ancora in esecuzione sulla macchina. Un’esecuzione il cui comando non era ancora partito quando è arrivato Ctrl-C non lo avvia.
os install con --host ha regole proprie: una volta data la risposta alla sua domanda, una connessione persa non lo ferma più, e il comando attende qui che la macchina torni come IronFlockOS; vedi ironflock os install.
Codici di uscita ed errori
I codici di uscita sono quelli del comando (Codici di uscita). --host aggiunge questi:
| Codice | Significato |
|---|---|
| 255 | ssh non è riuscito: nessuna connessione, login o chiave host rifiutati, una connessione interrotta |
| 3 | la macchina non può eseguire il comando: un altro sistema o un’altra CPU, una shell di login che non è una shell POSIX, nessuna cartella in cui si possa eseguire un programma, un sudo che non lo consente all’utente di login |
| 130 | un’interruzione, qui (Ctrl-C) o del comando sulla macchina (un hangup, un’interruzione o un segnale di terminazione lì) |
Un errore di --host stesso è un errore come gli altri: una riga Error: su stderr oppure, con --json, l’oggetto errore su stdout. L’unica eccezione: quando l’output del comando era già arrivato, quell’output è il risultato, e l’errore è solo la riga Error: su stderr, anche con --json.
Più macchine
--host indicato più volte, oppure --hosts <file>, esegue il comando su ogni macchina, come --host lo esegue su una. Prima vengono le macchine di --host, poi quelle del file. Un file degli host con una sola macchina si comporta come con più macchine.
$ 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)Il file degli host
Il file indica un [user@]machine per riga. Un # inizia un commento, che arriva fino alla fine della riga, e le righe vuote vengono ignorate. Il file può anche essere una pipe, ad esempio --hosts <(...), e contiene al massimo 1 MiB.
# Linea di confezionamento 3
pi@device-17
pi@device-18
pi@device-19 # the spare unit# Mostra lo stato di ogni macchina del file, 20 alla volta
ironflock --hosts line3.txt --parallel 20 status
# Aggiorna l'agente su ogni macchina del file; agent update pone una domanda, quindi serve --yes
ironflock --hosts line3.txt agent update --yes
# Assegna ai dispositivi di un sito un unico account proxy; la password viene da un file
ironflock --hosts site-a.txt agent configure --https-proxy http://[email protected]:3128 --proxy-password-file proxy-password.txt --yesQuesti casi terminano con il codice di uscita 2 prima che venga eseguito qualcosa, e l’errore indica il file e la riga:
- una riga con più di una parola;
- una macchina che
--hostrifiuterebbe; - una macchina indicata due volte. Conta come due volte anche la stessa macchina con due utenti, perché il comando verrebbe eseguito su di essa due volte contemporaneamente. Un indirizzo e un nome della stessa macchina non vengono riconosciuti come uguali.
Esecuzioni parallele
Al massimo --parallel macchine vengono elaborate contemporaneamente: 10 senza il flag, da 1 a 100. Partono nell’ordine indicato, e la successiva parte quando una termina. --parallel senza più macchine termina con il codice di uscita 2.
SSH senza domande
Nessuna macchina riceve un terminale, e ssh non chiede nulla (BatchMode=yes). Questi casi falliscono su quella macchina con il codice di uscita 255 e il messaggio di ssh, e le altre macchine proseguono:
- un login che richiede una password;
- una chiave la cui passphrase non è nell’agente SSH;
- una chiave host che
sshnon conosce ancora.
Connettiti una volta con ssh per accettare una nuova chiave host, oppure imposta StrictHostKeyChecking accept-new per quelle macchine in ~/.ssh/config, come nell’esempio sopra. ssh rinuncia a connettersi dopo 30 secondi (ConnectTimeout=30, qualunque cosa dica ~/.ssh/config), quindi una macchina spenta viene segnalata a quel punto. Un sudo remoto che richiede una password o un terminale termina con il codice di uscita 3 su quella macchina; status e doctor vengono allora eseguiti come utente di login.
Output di più macchine
- Ogni riga che una macchina scrive arriva intera, preceduta da
<host>:: il suo stdout su stdout, il suo stderr su stderr. Le righe delle macchine si mescolano nell’ordine in cui arrivano. - Un’ultima riga senza carattere di nuova riga ne riceve uno. Una riga più lunga di 64 KiB arriva in parti da 64 KiB, ciascuna preceduta dall’host.
- I caratteri di controllo diversi dalla tabulazione arrivano con escape (
\x1b,\r), nelle righe e nel riepilogo, così che nessuna macchina sposti il cursore o sovrascriva la riga di un’altra macchina. Un ritorno a capo (carriage return) alla fine di una riga viene eliminato. - Un’esecuzione che fallisce qui aggiunge la sua riga
Error:preceduta dall’host, come la scrive--hostper una macchina. - Alla fine, stderr riceve un riepilogo: il codice di uscita e quante macchine sono terminate in quale modo, poi una riga per ogni macchina nell’ordine indicato. La riga dice
done, oppure il codice di uscita, il suo tipo e il motivo: l’errore qui (per 255 con il messaggio dissh) o la rigaError:del comando. Una macchina che non ha confermato la fine del suo comando dopo Ctrl-C risultainterrupted, may still run.
Codice di uscita con più macchine
Il comando termina con il codice di uscita peggiore tra quelli delle macchine: 0 quando ogni macchina è terminata con 0. Altrimenti, dal peggiore in giù:
- 130 — interrotto, qui o su una macchina.
- 1 — il comando non è riuscito su una macchina, che potrebbe essere rimasta modificata a metà, qualunque sia il codice con cui è terminato lì.
- 255 — una macchina non è stata raggiunta, o la connessione si è interrotta.
- 3 — una macchina non era nello stato richiesto dal comando, o non può eseguirlo.
- 4 — a una domanda è stato risposto no.
Il codice di uscita 2 indica una riga di comando errata qui, come per ogni comando.
Righe JSON
Con --json, stdout riceve una riga per ogni macchina quando il suo comando è terminato, nell’ordine in cui terminano, e nient’altro. Un programma legge le righe man mano che arrivano.
{"host":"pi@vm1","state":"done","exit_code":0,"result":{...}}| Campo | Significato |
|---|---|
host | la macchina come la indica --host o il file degli host |
state | done: il comando è terminato con 0. failed: è terminato sulla macchina con un altro codice, oppure la sua esecuzione è fallita qui. interrupted: l’esecuzione è stata interrotta, e la macchina ha comunicato che il comando è terminato. may_still_run: l’esecuzione è stata interrotta qui, e la macchina non ha comunicato entro il tempo di attesa che il comando è terminato. not_started: l’esecuzione è stata interrotta prima che arrivasse il turno della macchina; lì non è stato eseguito nulla. |
exit_code | come è terminato il comando sulla macchina, o come è terminata qui la sua esecuzione: 255 quando la macchina non è stata raggiunta o la connessione si è interrotta, 3 quando la macchina non può eseguire il comando, 130 quando l’esecuzione è stata interrotta. Un altro codice, come 137 dopo un kill, è quello della macchina così com’è, con lo stato failed. |
result | ciò che il comando ha scritto con --json, come lo descrive la pagina del comando. Per agent logs, l’array delle sue righe; vengono conservati al massimo 16 MiB. È presente anche per un comando che scrive il suo risultato e termina con 1 (doctor, agent update). |
error | perché il comando non è terminato con 0, con kind e message: l’errore dell’esecuzione qui (tipo ssh per una macchina non raggiunta, con il messaggio che termina con le parole di ssh tra parentesi), altrimenti l’oggetto errore del comando, altrimenti uno composto dal suo codice di uscita e dalla sua ultima riga su stderr |
output | ciò che il comando ha scritto su stdout e che non è JSON; oppure, quando ha scritto più di 16 MiB, una frase che lo dice |
stderr contiene le righe delle macchine, tra cui la riga Error: di un comando quando ne scrive una con --json (agent update), e il riepilogo. Gli errori delle esecuzioni qui si trovano solo nelle righe su stdout.
# Le macchine su cui status non è terminato con 0
ironflock --hosts line3.txt status --json 2>/dev/null | jq -r 'select(.state != "done") | .host'Ctrl-C su più macchine
Ctrl-C, SIGTERM o SIGHUP terminano le esecuzioni come terminano un’esecuzione su una macchina: ogni comando remoto riceve il segnale, e ogni macchina ha 15 secondi per confermare che il suo comando è terminato. Una macchina che non lo fa risulta may_still_run. Le macchine il cui turno non è ancora arrivato non eseguono nulla. Il riepilogo le elenca come not started, e il comando termina con 130.
Quali comandi funzionano su più macchine
| Comandi | Su più macchine |
|---|---|
version, status, doctor, os images, os drives, agent restart, agent start | sempre |
agent logs | sempre; con --follow non con --json, perché la riga di una macchina arriva quando il suo comando termina, e --follow non termina |
agent stop, agent update, agent configure, agent remove, os update, os rollback, self-update | con --yes: pongono una domanda, e su più macchine contemporaneamente non viene chiesto nulla a nessuno |
completion | riceve risposta qui e su nessuna macchina, come --help |
agent install, os install, os flash, os reset | mai: il loro file .flock indica un solo dispositivo, oppure cancellano un disco, un’unità o i dati di un dispositivo dopo una domanda che nomina quell’unica macchina |
Un flag che indica un file su questa macchina viene rifiutato con più macchine, perché il file andrebbe a ogni macchina: -c di doctor e di agent configure indica un solo dispositivo. L’eccezione è --proxy-password-file di agent configure, per un unico account proxy per le macchine di un sito.
Una riga di comando che non funziona su più macchine termina con il codice di uscita 2 e dice perché, prima che venga letto il file degli host e prima che venga raggiunta qualsiasi macchina.