Machines distantes via SSH
--host exécute une commande ironflock sur une autre machine via SSH au lieu de celle-ci. Il vous sert à gérer des appareils depuis votre ordinateur portable, Mac compris, sans y installer ironflock. Donné plusieurs fois, ou avec un fichier d’hôtes, il exécute la commande sur plusieurs machines à la fois.
ironflock --host [user@]machine <command> [flags]
ironflock --host [user@]machine --host [user@]machine ... <command> [flags]
ironflock --hosts <file> [--parallel <n>] <command> [flags]Toutes les commandes sauf completion s’exécutent ainsi sur une autre machine. --host, --hosts et --parallel sont des options globales : elles peuvent se placer avant ou après le nom de la commande.
Une machine
--host [user@]machine exécute la même commande avec les mêmes options sur cette machine. Ce qu’elle affiche revient tel quel, stdout sur stdout et stderr sur stderr, de même que son code de sortie.
$ 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":[...]}Ce dont l’autre machine a besoin
- Linux sur amd64, arm64 ou ARM 32 bits (v5 à v7). Sur un autre système, la commande se termine avec le code de sortie 3.
- Un serveur SSH qui exécute des commandes. Ni
scpni SFTP ne sont nécessaires. - Un shell de connexion POSIX : sh, bash, dash ou zsh. Avec csh, tcsh et fish, la commande se termine avec le code de sortie 3 et un message qui le dit.
- Un compte de connexion root, ou
sudo, pour les commandes qui nécessitent root (voir Root sur l’autre machine).
La machine n’a pas besoin qu’ironflock y soit installé : chaque exécution apporte son propre binaire.
Paramètres SSH
--host utilise le ssh de cette machine : votre ~/.ssh/config, vos clés, l’agent SSH et les hôtes de rebond (jump hosts) fonctionnent comme avec ssh. Il désactive ce dont la commande n’a pas besoin : le transfert de l’agent et de X11, les redirections de ports, une RemoteCommand et une LocalCommand.
--host accepte [user@]machine et rien d’autre. Un port ou d’autres options SSH se mettent dans ~/.ssh/config :
Host device-*
User pi
Port 2222
StrictHostKeyChecking accept-newAvec ceci, ironflock --host device-17 status se connecte en tant que pi sur le port 2222, et ssh accepte la clé d’hôte d’un appareil qu’il ne connaît pas encore. Une valeur de --host qui commence par - est refusée, tout comme une valeur qui contient d’autres caractères que des lettres, des chiffres, ., _, -, et les : et % d’une adresse IPv6.
Une seule connexion SSH sert à toute l’exécution lorsque le chemin de son socket de contrôle est assez court ; le socket est créé dans le dossier temporaire, sinon dans /tmp. ssh ne demande alors le mot de passe qu’une fois. Sinon, chaque étape de l’exécution ouvre sa propre connexion, et ssh le redemande pour chacune.
Un appareil configuré par ironflock agent install ou par IronFlockOS a un utilisateur SSH pour le propriétaire du projet, qui se connecte avec la clé du fichier .flock de l’appareil. Accès SSH indique le nom d’utilisateur et comment extraire la clé du fichier.
Ce qui se passe sur la machine
- Le binaire. La machine reçoit le binaire qui s’exécute ici lorsqu’elle a la même plateforme. Sinon,
ironflocktélécharge le binaire pour la plateforme de la machine depuis<download base>/cli/<os>/<arch>/<version>/ironflocket le vérifie ici avant de l’utiliser : sa signature (.asc) avec la clé de publication d’IronFlock que contient ce binaire, et ses informations de build, qui doivent nommer le programmeironflock, la plateforme de la machine et la même révision source que ce binaire. Le téléchargement est conservé dans votre dossier de cache (~/.cache/ironflocksous Linux,~/Library/Caches/ironflocksur un Mac) et revérifié à chaque utilisation. - Le dossier. Le binaire va dans un nouveau dossier que seul le compte de connexion peut lire (
mktemp -d), sous${TMPDIR:-/tmp}sur la machine, ou sous le répertoire personnel du compte lorsqu’un programme ne peut pas s’exécuter dans le dossier temporaire (un système de fichiers monténoexec). Lorsqu’il ne peut s’exécuter dans aucun des deux, la commande se termine avec le code de sortie 3 et nomme les deux. Avant d’exécuter quoi que ce soit depuis le dossier, la machine vérifie que le dossier et le binaire appartiennent au compte de connexion et ne sont pas des liens symboliques, et que le binaire a la version et la plateforme attendues. - Les fichiers. Les fichiers désignés dans les options de la commande sont transmis (voir Fichiers désignés dans les options).
- La commande. Elle s’exécute sous le compte de connexion, ou via
sudo(voir Root sur l’autre machine). - Le nettoyage. Lorsque la commande se termine, la machine supprime le dossier avec le binaire et les copies : y compris après un échec, après une connexion perdue, et après les signaux HUP, INT, QUIT, TERM, PIPE, USR1 et USR2.
--host ne laisse aucun ironflock sur la machine, même après agent install. Continuez ensuite avec --host, ou installez ironflock sur la machine avec la ligne d’installation, qui, sans argument, se contente de l’installer. self-update via --host met à jour ce /usr/local/bin/ironflock de la machine, et non le binaire de l’exécution (ironflock self-update).
Un dossier ironflock.* reste sur la machine dans deux cas :
- Après une coupure de courant ou un
kill -9sur la machine pendant que la commande s’exécute. Le dossier contient le binaire et les copies. - Lorsque la connexion est perdue après la copie et avant le démarrage de la commande, ou que l’exécution est interrompue ici pendant que l’étape qui démarre la commande établit la connexion. Le dossier contient le binaire, et aussi les copies si vous avez exécuté la commande dans un terminal.
Une copie d’un fichier .flock contient le secret de l’appareil, une copie d’un fichier de phrase secrète la phrase secrète WiFi, une copie d’un fichier de mot de passe le mot de passe du proxy. Seuls le compte de connexion et root peuvent les lire. Supprimez un tel dossier à la main.
Fichiers désignés dans les options
| Option | Commandes |
|---|---|
-c, --config (le fichier .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 |
Chaque fichier est lu ici, et un chemin relatif est relatif au dossier de travail de cette machine. Un fichier de phrase secrète ou de mot de passe peut être un pipe (/dev/stdin), lu une seule fois. Le contenu est envoyé à la machine sur l’entrée standard de la connexion SSH. Ni un fichier ni sa taille ne figurent sur une ligne de commande, ni ici ni sur la machine, où chaque utilisateur peut lire les lignes de commande. La machine vérifie chaque taille par rapport au maximum qu’accepte la commande, puis que tout est arrivé.
Sur la machine, la copie est <folder>/1/device.flock : dans un dossier à part (mode 0700) à l’intérieur du dossier de l’exécution, avec le nom qu’elle porte ici et le mode 0600. La commande y reçoit ce chemin, par exemple --config=/tmp/ironflock.k3Xf9QpL2m/1/device.flock, si bien qu’une erreur qui porte sur le contenu du fichier nomme la copie.
Les cas suivants mettent fin à la commande sur cette machine :
- Code de sortie 1 — un fichier qui n’est pas un fichier ordinaire (un fichier de phrase secrète ou de mot de passe peut aussi être un pipe), ou un fichier plus grand que ce qu’accepte la commande : 5 Mio pour un fichier
.flock, 4096 octets pour un fichier de phrase secrète ou de mot de passe. - Code de sortie 2 — un nom de fichier qui contient un caractère de contrôle.
- Code de sortie 2 —
--image-fileet--outputdeos flash.--hostne copie aucune image sur la machine et ne rapporte aucun fichier. Exécutez cette commande ici sans--host, ou sur la machine elle-même. Sans--image-file, la machine télécharge l’image elle-même.
Root sur l’autre machine
- Une commande qui nécessite root s’exécute via
sudolorsque le compte de connexion n’est pas root.sudosans mot de passe et sans terminal fonctionne partout. version,os imagesetos drivess’exécutent sous le compte de connexion.statusetdoctorlisent davantage avec root. Ils s’exécutent en tant que root lorsque le compte de connexion est root ou peut utilisersudosans mot de passe et sans terminal. Sinon, ils s’exécutent sous le compte de connexion, sans rien demander, et leur conseil indique la commande avec--host root@machine.agent logslit un fichier qui appartient à root et s’exécute viasudo.- Lorsque
sudodemande un mot de passe, ou que sa configuration exige un terminal (requiretty), il a besoin d’un terminal sur la machine. Il faut pour cela un terminal sur stdin, stdout et stderr ici. Sans terminal, la commande se termine avec le code de sortie 3 avant que quoi que ce soit ne soit copié. Connectez-vous alors en root, autorisez le compte à utilisersudosans mot de passe et sans terminal, ou exécutez la commande dans un terminal sans redirection. - Si
sudorefuse au moment où la commande va s’exécuter, elle se termine aussi avec le code de sortie 3.
Lorsque la commande indique là-bas quoi exécuter ensuite, elle nomme une commande pour ce côté-ci, sans sudo, car --host obtient root lui-même : ironflock --host pi@device-17 agent start.
Terminal, questions et sortie
- Avec un terminal ici, la commande en reçoit un aussi sur la machine, pour pouvoir poser ses questions. Son stdout et son stderr reviennent alors ensemble, dans votre terminal.
- Sans terminal ici (un pipe,
--jsonvers un programme, la CI), stdout et stderr restent séparés, et la commande ne pose aucune question :--yesconfirme. Ce qu’affichent les fichiers du compte sur la machine, comme un.bashrcqui fait un echo, est retiré de stdout, afin que stdout ne transporte que le résultat de la commande. --yes,--jsonet les options de la commande sont transmis. La base de téléchargement est transmise sous la forme de--download-base: l’option, ou la variableIRONFLOCK_DL_BASEde cette machine. Avec une base de téléchargement qui contient des identifiants (https://user:[email protected]/dl), la commande se termine avec le code de sortie 2 avant qu’aucune machine ne soit jointe, car sur la machine elle figurerait sur une ligne de commande que chaque utilisateur peut y lire.--help,help, un groupe sans commande etcompletionobtiennent leur réponse ici : ce qu’ils affichent est identique sur chaque machine.- Ce que la machine envoie sur stdout avant l’exécution de la commande (ses réponses et le texte des fichiers du compte) est lu jusqu’à 64 Kio. Au-delà, l’exécution se termine avec le code de sortie 1 avant que la commande ne s’y exécute.
Ctrl-C et connexions perdues
Ctrl-C ici atteint la commande là-bas comme le ferait un Ctrl-C dans son propre terminal, et une connexion perdue l’atteint comme un raccrochage (hangup), avec ou sans terminal ici. Après Ctrl-C, --host attend jusqu’à 15 secondes que la machine indique que la commande s’est terminée là-bas, avec son code de sortie (130 lorsque c’est Ctrl-C qui l’a terminée). Si la machine ne le fait pas à temps, ou si la connexion se termine avant, --host se termine avec 130 et indique que la commande s’exécute peut-être encore là-bas. Une exécution dont la commande n’avait pas démarré à l’arrivée du Ctrl-C ne la démarre pas.
os install via --host a ses propres règles : une fois la réponse donnée à sa question, une connexion perdue ne l’arrête plus, et la commande attend ici que la machine revienne sous IronFlockOS ; voir ironflock os install.
Codes de sortie et erreurs
Les codes de sortie sont ceux de la commande (Codes de sortie). --host ajoute ceux-ci :
| Code | Signification |
|---|---|
| 255 | ssh a échoué : pas de connexion, compte de connexion ou clé d’hôte refusés, connexion coupée |
| 3 | la machine ne peut pas exécuter la commande : autre système ou processeur, shell de connexion qui n’est pas un shell POSIX, aucun dossier où un programme peut s’exécuter, sudo qui n’autorise pas le compte de connexion |
| 130 | une interruption, ici (Ctrl-C) ou de la commande sur la machine (raccrochage, interruption ou signal de terminaison là-bas) |
Un échec de --host lui-même est une erreur comme une autre : une ligne Error: sur stderr ou, avec --json, l’objet d’erreur sur stdout. Une seule exception : lorsque la sortie de la commande était déjà arrivée, cette sortie est le résultat, et l’erreur se limite à la ligne Error: sur stderr, même avec --json.
Plusieurs machines
--host donné plusieurs fois, ou --hosts <file>, exécute la commande sur chaque machine, comme --host l’exécute sur une seule. Les machines de --host passent en premier, puis celles du fichier. Un fichier d’hôtes qui ne contient qu’une machine s’exécute comme plusieurs machines.
$ 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)Le fichier d’hôtes
Le fichier nomme un [user@]machine par ligne. Un # commence un commentaire, qui court jusqu’à la fin de la ligne, et les lignes vides sont ignorées. Le fichier peut aussi être un pipe, comme --hosts <(...), et fait au plus 1 Mio.
# Ligne de conditionnement 3
pi@device-17
pi@device-18
pi@device-19 # the spare unit# Afficher l'état de chaque machine du fichier, 20 à la fois
ironflock --hosts line3.txt --parallel 20 status
# Mettre à jour l'agent sur chaque machine du fichier ; agent update pose une question, --yes est donc nécessaire
ironflock --hosts line3.txt agent update --yes
# Donner aux appareils d'un site un même compte proxy ; le mot de passe provient d'un fichier
ironflock --hosts site-a.txt agent configure --https-proxy http://[email protected]:3128 --proxy-password-file proxy-password.txt --yesLes cas suivants se terminent avec le code de sortie 2 avant toute exécution, et l’erreur nomme le fichier et la ligne :
- une ligne qui contient plus d’un mot ;
- une machine que
--hostrefuserait ; - une machine nommée deux fois. C’est aussi le cas de la même machine avec deux utilisateurs, car la commande s’y exécuterait deux fois en même temps. Une adresse et un nom d’une même machine ne sont pas reconnus comme identiques.
Exécutions parallèles
Au plus --parallel machines s’exécutent en même temps : 10 sans l’option, de 1 à 100. Elles démarrent dans l’ordre donné, et la suivante démarre dès qu’une autre se termine. --parallel sans plusieurs machines se termine avec le code de sortie 2.
SSH sans questions
Aucune machine ne reçoit de terminal, et ssh ne pose aucune question (BatchMode=yes). Les cas suivants échouent sur la machine concernée avec le code de sortie 255 et les propres mots de ssh, et les autres machines continuent :
- un compte de connexion qui exige un mot de passe ;
- une clé dont la phrase secrète n’est pas dans l’agent SSH ;
- une clé d’hôte que
sshne connaît pas encore.
Connectez-vous une fois avec ssh pour accepter une nouvelle clé d’hôte, ou définissez StrictHostKeyChecking accept-new pour ces machines dans ~/.ssh/config, comme dans l’exemple ci-dessus. ssh renonce à se connecter au bout de 30 secondes (ConnectTimeout=30, quoi qu’en dise ~/.ssh/config) : une machine éteinte est donc signalée à ce moment-là. Un sudo qui y exige un mot de passe ou un terminal se termine avec le code de sortie 3 sur cette machine ; status et doctor s’exécutent alors sous le compte de connexion.
Sortie de plusieurs machines
- Chaque ligne qu’écrit une machine arrive entière, précédée de
<host>:: son stdout sur stdout, son stderr sur stderr. Les lignes des machines se mêlent dans l’ordre où elles arrivent. - Une dernière ligne sans saut de ligne en reçoit un. Une ligne de plus de 64 Kio arrive en morceaux de 64 Kio, chacun précédé de l’hôte.
- Les caractères de contrôle autres que la tabulation arrivent échappés (
\x1b,\r), dans les lignes et dans le récapitulatif, afin qu’aucune machine ne déplace le curseur ni n’écrase la ligne d’une autre. Un retour chariot en fin de ligne est supprimé. - Une exécution qui échoue ici ajoute sa ligne
Error:précédée de l’hôte, comme--hostl’écrit pour une seule machine. - À la fin, stderr reçoit un récapitulatif : le code de sortie et le nombre de machines par issue, puis une ligne par machine dans l’ordre donné. La ligne indique
done, ou le code de sortie, son type et la raison : l’erreur d’ici (pour 255, avec les propres mots dessh) ou la ligneError:de la commande. Une machine qui n’a pas confirmé la fin de sa commande après Ctrl-C estinterrupted, may still run.
Code de sortie de plusieurs machines
La commande se termine avec le pire code de sortie des machines : 0 lorsque chaque machine s’est terminée avec 0. Sinon, du plus grave au moins grave :
- 130 — interruption, ici ou sur une machine.
- 1 — la commande a échoué sur une machine et l’a peut-être laissée à moitié modifiée, quel que soit le code avec lequel elle s’y est terminée.
- 255 — une machine n’a pas été jointe, ou la connexion a été coupée.
- 3 — une machine n’était pas dans l’état dont la commande a besoin, ou ne peut pas l’exécuter.
- 4 — une question a reçu la réponse non.
Le code de sortie 2 signale une ligne de commande erronée ici, comme pour chaque commande.
Lignes JSON
Avec --json, stdout reçoit une ligne par machine lorsque sa commande s’est terminée, dans l’ordre où elles se terminent, et rien d’autre. Un programme lit les lignes au fur et à mesure qu’elles arrivent.
{"host":"pi@vm1","state":"done","exit_code":0,"result":{...}}| Champ | Signification |
|---|---|
host | la machine telle que la nomme --host ou le fichier d’hôtes |
state | done : la commande s’est terminée avec 0. failed : elle s’est terminée avec un autre code là-bas, ou son exécution a échoué ici. interrupted : l’exécution a été interrompue, et la machine a indiqué que la commande s’est terminée. may_still_run : l’exécution a été interrompue ici, et la machine n’a pas indiqué dans le délai d’attente que la commande s’est terminée. not_started : l’exécution a été interrompue avant que vienne le tour de la machine ; rien ne s’y est exécuté. |
exit_code | comment la commande s’est terminée sur la machine, ou comment son exécution s’est terminée ici : 255 lorsque la machine n’a pas été jointe ou que la connexion a été coupée, 3 lorsque la machine ne peut pas exécuter la commande, 130 lorsque l’exécution a été interrompue. Un autre code, comme 137 après un kill, est celui de la machine tel quel, avec l’état failed. |
result | ce que la commande a écrit avec --json, tel que le décrit la page de la commande. Pour agent logs, le tableau de ses lignes ; au plus 16 Mio sont conservés. Une commande qui écrit son résultat et se termine avec 1 (doctor, agent update) l’a aussi. |
error | pourquoi la commande ne s’est pas terminée avec 0, avec kind et message : l’erreur de l’exécution ici (type ssh pour une machine qui n’a pas été jointe, le message se terminant par les mots de ssh entre parenthèses), sinon l’objet d’erreur de la commande, sinon un objet formé de son code de sortie et de sa dernière ligne sur stderr |
output | ce que la commande a écrit sur stdout et qui n’est pas du JSON ; ou, lorsqu’elle a écrit plus de 16 Mio, une phrase qui le dit |
stderr contient les lignes des machines, dont la propre ligne Error: d’une commande lorsqu’elle en écrit une avec --json (agent update), ainsi que le récapitulatif. Les erreurs des exécutions d’ici figurent uniquement dans les lignes sur stdout.
# Les machines sur lesquelles status ne s'est pas terminé avec 0
ironflock --hosts line3.txt status --json 2>/dev/null | jq -r 'select(.state != "done") | .host'Ctrl-C sur plusieurs machines
Ctrl-C, SIGTERM ou SIGHUP met fin aux exécutions comme à une exécution sur une seule machine : chaque commande là-bas le reçoit, et chaque machine a 15 secondes pour confirmer que sa commande s’est terminée. Une machine qui ne le fait pas est may_still_run. Les machines dont le tour n’est pas venu n’exécutent rien. Le récapitulatif les liste comme not started, et la commande se termine avec 130.
Commandes exécutables sur plusieurs machines
| Commandes | Sur plusieurs machines |
|---|---|
version, status, doctor, os images, os drives, agent restart, agent start | toujours |
agent logs | toujours ; avec --follow, pas avec --json, car la ligne d’une machine arrive quand sa commande se termine, et --follow ne se termine pas |
agent stop, agent update, agent configure, agent remove, os update, os rollback, self-update | avec --yes : elles posent une question, et sur plusieurs machines à la fois personne n’est interrogé |
completion | réponse donnée ici et sur aucune machine, comme pour --help |
agent install, os install, os flash, os reset | jamais : leur fichier .flock désigne un seul appareil, ou elles effacent un disque, un lecteur ou les données d’un appareil après une question qui nomme la machine concernée |
Une option qui désigne un fichier sur cette machine est refusée avec plusieurs machines, car le fichier irait à chaque machine : -c de doctor et de agent configure désigne un seul appareil. L’exception est --proxy-password-file de agent configure, qui permet un même compte proxy pour les machines d’un site.
Une ligne de commande qui ne s’exécute pas sur plusieurs machines se termine avec le code de sortie 2 et dit pourquoi, avant que le fichier d’hôtes ne soit lu et avant qu’aucune machine ne soit jointe.