Skip to Content
Sviluppo App IoTIronFlock CLIMacchine remote via SSH

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é scp né 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-new

Così 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

  1. Il binario. La macchina riceve il binario in esecuzione qui quando ha la stessa piattaforma. Altrimenti ironflock scarica il binario per la piattaforma della macchina da <download base>/cli/<os>/<arch>/<version>/ironflock e 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 programma ironflock, la piattaforma della macchina e la stessa revisione dei sorgenti di questo binario. Il download viene conservato nella tua cartella della cache (~/.cache/ironflock su Linux, ~/Library/Caches/ironflock su un Mac) e verificato di nuovo a ogni utilizzo.
  2. 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 montato noexec). 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.
  3. I file. I file indicati nei flag del comando vengono trasferiti insieme al binario (vedi File indicati nei flag).
  4. Il comando. Viene eseguito come utente di login, oppure tramite sudo (vedi Root sull’altra macchina).
  5. 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 -9 sulla 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

FlagComandi
-c, --config (il file .flock)agent install, agent configure, doctor, os flash, os install, os reset
--wifi-password-fileos flash
--proxy-password-fileagent 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-file e --output di os flash. --host non 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 sudo quando l’utente di login non è root. sudo senza password e senza terminale funziona ovunque.
  • version, os images e os drives vengono eseguiti come utente di login.
  • status e doctor leggono di più con root. Vengono eseguiti come root quando l’utente di login è root o può usare sudo senza 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 logs legge un file di root e viene eseguito tramite sudo.
  • Quando sudo chiede 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 usare sudo senza password e senza terminale, oppure esegui il comando a un terminale senza reindirizzamenti.
  • Anche un sudo che 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, --json verso un programma, la CI), stdout e stderr restano separati, e il comando non chiede nulla: --yes conferma. Ciò che stampano i file dell’utente di login sulla macchina, ad esempio un .bashrc che usa echo, viene eliminato da stdout, così che stdout contenga solo il risultato del comando.
  • --yes, --json e i flag del comando vengono passati alla macchina. La base di download viene passata come --download-base: il flag, oppure IRONFLOCK_DL_BASE di 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 e completion ricevono 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:

CodiceSignificato
255ssh non è riuscito: nessuna connessione, login o chiave host rifiutati, una connessione interrotta
3la 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
130un’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 --yes

Questi 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 --host rifiuterebbe;
  • 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 ssh non 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 --host per 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 di ssh) o la riga Error: del comando. Una macchina che non ha confermato la fine del suo comando dopo Ctrl-C risulta interrupted, 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ù:

  1. 130 — interrotto, qui o su una macchina.
  2. 1 — il comando non è riuscito su una macchina, che potrebbe essere rimasta modificata a metà, qualunque sia il codice con cui è terminato lì.
  3. 255 — una macchina non è stata raggiunta, o la connessione si è interrotta.
  4. 3 — una macchina non era nello stato richiesto dal comando, o non può eseguirlo.
  5. 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":{...}}
CampoSignificato
hostla macchina come la indica --host o il file degli host
statedone: 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_codecome è 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.
resultciò 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).
errorperché 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
outputciò 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

ComandiSu più macchine
version, status, doctor, os images, os drives, agent restart, agent startsempre
agent logssempre; 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-updatecon --yes: pongono una domanda, e su più macchine contemporaneamente non viene chiesto nulla a nessuno
completionriceve risposta qui e su nessuna macchina, come --help
agent install, os install, os flash, os resetmai: 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.

Last updated on