Échecs partiels de commandes SSH : empêchez les agents de répéter le travail
Les échecs partiels de commandes SSH exigent une réconciliation, pas des nouvelles tentatives aveugles. Conservez les codes de sortie, checkpoints, reçus et états distants observés pour les agents IA.

Un agent IA doit traiter une commande SSH échouée comme une transition d'état inconnue, et non comme une autorisation à exécuter de nouveau le même texte. Une commande peut créer un utilisateur, recharger un service, puis échouer en écrivant un fichier final. Une nouvelle tentative aveugle peut créer un compte en double, écraser un réglage modifié à la main ou transformer un déploiement récupérable en panne.
Le conseil habituel, « vérifiez le code de sortie », est nécessaire mais incomplet. Le statut de sortie décrit la façon dont un processus s'est terminé. La récupération exige de conserver ce que le processus a terminé, l'état que l'hôte signale maintenant et l'opération que l'agent voulait effectuer. Placez ces informations dans un reçu de commande durable, puis demandez à l'agent de réconcilier l'état avant toute nouvelle action.
Un échec SSH laisse trois inconnues différentes
Une action SSH échouée peut signifier que le shell distant a échoué, que la connexion a échoué ou que le contrôleur a cessé d'attendre. Ces cas exigent des traitements différents, mais les agents les réduisent souvent tous à « commande échouée ».
Prenons un script de déploiement distant qui effectue les opérations suivantes :
- Il écrit une nouvelle archive de l'application dans un répertoire de versions.
- Il fait pointer un lien symbolique
currentvers cette version. - Il redémarre le service.
- Il lance un contrôle de santé, puis renvoie un code différent de zéro parce que le contrôle détecte une erreur temporaire de dépendance.
La nouvelle version est active alors que la commande a signalé un échec. Réexécuter le script peut être sans danger si chaque opération tolère la répétition. Mais le script crée plus souvent un nouveau répertoire de version, tronque un journal, renouvelle un identifiant ou exécute une migration. Le seul code de sortie ne permet pas de déterminer ce qui s'est produit.
Le deuxième cas est plus délicat : une interruption du transport SSH. Le processus local peut recevoir 255 après une coupure réseau alors que le shell distant continue son travail. Un délai d'attente du contrôleur pose le même problème. Le contrôleur sait seulement qu'il n'a pas reçu de réponse finale. Il ignore si la cible a reçu la requête, si le shell a démarré ou si le processus modifie encore l'état.
Cette distinction détermine l'action suivante de l'agent :
- Une sortie distante confirmée avec un reçu appelle une récupération fondée sur le checkpoint échoué.
- Une défaillance du transport appelle une observation avant toute modification.
- Un délai d'attente du contrôleur appelle une observation et, si nécessaire, une procédure d'annulation explicite plutôt qu'une requête en double.
Ne donnez pas à ces trois cas le nom de « nouvelles tentatives ». Une nouvelle tentative est une opération assortie d'une règle connue de répétition sans danger. Un état distant inconnu exige une réconciliation.
Le statut de sortie décrit un processus, pas une transaction
Un code de sortie SSH fournit des éléments utiles, mais ce n'est pas un enregistrement de validation de base de données. Le manuel OpenSSH indique que ssh se termine avec le statut de la commande distante, ou avec 255 si une erreur s'est produite. Cette formulation trace une limite que de nombreux systèmes d'automatisation ignorent : un statut distant décrit la commande lorsque SSH le reçoit, tandis que 255 correspond au chemin d'erreur propre à SSH.
Un code de sortie nul doit lui aussi être interprété. Dans un shell POSIX, le statut d'une liste séquentielle simple vient normalement de la dernière commande. Ce script peut signaler une réussite après un échec important :
install -m 0644 app.conf /etc/myapp/app.conf
systemctl restart myapp
logger -t deploy "deployment finished"
Si install échoue mais que systemctl restart et logger renvoient zéro, le statut final du script est zéro. L'agent voit une réussite et peut affirmer à tort que la configuration a changé. Un dernier echo done produit le même mensonge.
Les pipelines ajoutent une autre voie d'échec. Dans Bash, le Bash Reference Manual précise que le statut d'un pipeline est celui de sa dernière commande, sauf si pipefail est activé. Cette commande peut renvoyer zéro si l'extraction se termine normalement après n'avoir reçu aucune donnée utile :
curl --fail --silent https://example.invalid/build.tar.gz | tar -xz -C /srv/myapp
Utilisez un interpréteur explicite et déclarez le comportement attendu :
#!/usr/bin/env bash
set -Eeuo pipefail
curl --fail --silent --show-error "$archive_url" | tar -xz -C "$release_dir"
-e demande à Bash de s'arrêter en cas de nombreux échecs non traités, -u refuse les variables non définies et pipefail conserve l'échec des éléments précédents du pipeline. L'option E permet au piège ERR de s'appliquer dans les fonctions et les substitutions de commandes. Ces réglages améliorent le signalement des échecs, mais ne rendent pas une séquence atomique.
Ce dernier point compte. set -e intervient après qu'une opération a renvoyé une erreur. Il ne peut pas supprimer un répertoire créé par une commande précédente ni restaurer un service redémarré auparavant. Cette option comporte aussi des exceptions surprenantes : les commandes testées par if, celles situées à gauche de && ou || et plusieurs contextes composés ne provoquent pas toujours une sortie. Ajoutez des vérifications explicites autour des actions dont l'échec modifie la récupération.
Définissez la limite de l'opération avant d'écrire la commande
Un agent ne peut pas récupérer une instruction vague comme « déployer le service ». La commande distante doit correspondre à une opération nommée, avec une postcondition qu'un observateur peut tester.
Pour un changement de version, l'opération peut être : « Faire pointer /srv/myapp/current vers la version 2025-04-18.3, puis confirmer que le service actif signale cette version. » Pour une modification de base de données : « Appliquer exactement une fois la migration add_invoice_index et confirmer que son enregistrement existe. » Le texte de la commande est un détail d'implémentation. L'opération et sa postcondition déterminent si la récupération est possible.
Découpez une opération au niveau des limites irréversibles ou visibles de l'extérieur. Un checkpoint utile ne correspond pas à chaque ligne du shell. Enregistrez-en un après une modification d'état qui change la décision suivante. Pour un déploiement, cela peut inclure la vérification de l'archive, le remplissage du répertoire de version, le changement du lien symbolique, le redémarrage du service et l'observation de l'état de santé.
Évitez de recommander, à tort, de rendre chaque commande distante « idempotente » avant de la réessayer indéfiniment. L'idempotence s'applique à une opération précise et à un état souhaité défini. mkdir -p /srv/app peut être répétable. useradd deploy ne l'est que si l'agent vérifie que le compte existant possède l'UID, le groupe, le répertoire personnel et le shell attendus. ALTER TABLE peut échouer lors d'une deuxième exécution ou, pire, une migration mal écrite peut appliquer deux fois une modification apparentée.
Une commande peut être sûre à répéter alors que le workflow qui l'entoure ne l'est pas. Redémarrer un service peut être répétable, mais le redémarrer au milieu d'une copie de configuration peut exposer un fichier incomplet. Placez la validation de l'état à côté de l'action. Ne demandez pas à l'agent de la déduire d'une règle générale.
Pour chaque opération, définissez quatre champs avant d'accorder l'accès :
- Un identifiant d'opération conservé pendant toute la récupération.
- Une postcondition souhaitée qu'une commande en lecture seule peut examiner.
- Les checkpoints décrivant les modifications d'état terminées.
- Une action de récupération pour chaque checkpoint incomplet.
L'identifiant d'opération n'est pas décoratif. Si le contrôleur en crée un nouveau à chaque tentative, la cible ne peut pas distinguer une continuation d'une nouvelle requête. C'est ainsi que surviennent les migrations répétées et le provisionnement en double.
Écrivez un reçu avant et après chaque modification d'état
Un reçu durable transforme un échec partiel en événement vérifiable. Écrivez-le sur l'hôte cible avant la première modification, mettez-le à jour après chaque checkpoint important et rendez les mises à jour atomiques.
Le script Bash suivant reste volontairement simple. Il déploie une version déjà préparée en changeant un lien symbolique et en redémarrant un service système. Il ne prétend pas couvrir toutes les méthodes de déploiement. Il montre la mécanique de reçu dont un agent a besoin.
#!/usr/bin/env bash
set -Eeuo pipefail
operation_id=${1:?operation ID required}
release=${2:?release path required}
service=${3:?service name required}
state_dir=/var/lib/agent-ops
receipt="$state_dir/$operation_id.receipt"
tmp="$receipt.$$"
mkdir -p "$state_dir"
chmod 0700 "$state_dir"
write_receipt() {
cat >"$tmp" <<EOF
operation_id=$operation_id
release=$release
service=$service
checkpoint=$1
updated_at=$(date -u +%Y-%m-%dT%H:%M:%SZ)
EOF
chmod 0600 "$tmp"
mv -f "$tmp" "$receipt"
}
fail() {
status=$?
write_receipt "failed:$status"
exit "$status"
}
trap fail ERR
if [[ -f "$receipt" ]]; then
. "$receipt"
case "$checkpoint" in
complete)
printf 'operation already complete: %s\n' "$operation_id"
exit 0
;;
switched|restarted)
printf 'operation requires reconciliation: %s\n' "$checkpoint" >&2
exit 75
;;
esac
fi
[[ -d "$release" ]]
write_receipt "release_verified"
ln -sfn "$release" /srv/myapp/current
write_receipt "switched"
systemctl restart "$service"
write_receipt "restarted"
active_target=$(readlink -f /srv/myapp/current)
[[ "$active_target" == "$release" ]]
systemctl is-active --quiet "$service"
write_receipt "complete"
printf 'operation complete: %s\n' "$operation_id"
Le fichier temporaire et mv sont importants. Sur un même système de fichiers, le renommage remplace le reçu en une seule opération. Un lecteur obtient donc soit l'ancien reçu complet, soit le nouveau, et jamais un fichier à moitié écrit. Rendez le répertoire d'état accessible en écriture uniquement au compte qui possède l'opération. Si un utilisateur non fiable peut modifier les reçus, la logique de récupération de l'agent prend une fiction pour une preuve.
Le piège ERR enregistre le statut de sortie lorsque Bash traite un échec. Il ne peut pas s'exécuter après une coupure de courant, un signal impossible à intercepter ou un arrêt brutal. C'est pourquoi le script enregistre sa progression après chaque modification d'état terminée au lieu de compter uniquement sur un piège final.
Ne sourcez pas de formats de reçus arbitraires comme le fait ce petit exemple, sauf si le répertoire possède des droits et un propriétaire stricts. En production, préférez du JSON traité par un analyseur connu ou un format de lignes fixe qui refuse les champs inattendus. L'exemple ne source qu'un fichier qu'il vient de créer dans un répertoire protégé, afin de garder le code shell lisible.
Le reçu doit décrire des faits observés, pas une intention optimiste. checkpoint=switched signifie que la commande du lien symbolique s'est terminée correctement. Cela ne signifie pas que le service a chargé la nouvelle version. complete vient après les vérifications explicites de la postcondition. Cette distinction empêche l'agent de prendre une commande écrite pour une opération achevée.
Demandez à l'agent une réconciliation, pas une nouvelle commande
Après un résultat différent de zéro, l'agent doit conserver l'identifiant d'opération initial et lancer d'abord des vérifications en lecture seule. Il ne doit pas recréer la commande de déploiement en changeant légèrement sa formulation. Une nouvelle formulation ne crée pas une nouvelle transition d'état.
Pour le reçu de déploiement précédent, une commande de réconciliation peut examiner à la fois l'enregistrement durable et la postcondition active :
operation_id='release-7f3b'
cat "/var/lib/agent-ops/$operation_id.receipt"
printf 'current='
readlink -f /srv/myapp/current
systemctl is-active myapp
systemctl show myapp --property=ActiveState --property=SubState --no-pager
La sortie doit avoir une forme que l'agent peut analyser sans faire passer de la prose pour une preuve :
operation_id=release-7f3b
release=/srv/myapp/releases/2025-04-18.3
service=myapp
checkpoint=restarted
updated_at=2025-04-18T14:05:12Z
current=/srv/myapp/releases/2025-04-18.3
active
ActiveState=active
SubState=running
Ici, le lien symbolique pointe vers la version demandée et le service est actif, mais le reçu s'est arrêté à restarted. Le processus distant a peut-être disparu après le redémarrage du service et avant l'écriture de complete. La procédure de récupération peut relancer les vérifications de la postcondition et, si elles réussissent, écrire un reçu de fin au moyen d'une commande de récupération strictement limitée. Elle ne doit pas recommencer le déploiement depuis le début.
Un protocole de contrôleur utile sépare la requête, le résultat et la récupération. Par exemple :
{
"operation_id": "release-7f3b",
"action": "deploy_release",
"target": "app-01",
"arguments": {
"release": "/srv/myapp/releases/2025-04-18.3",
"service": "myapp"
},
"mode": "reconcile"
}
La cible ne doit accepter mode: reconcile que pour une inspection en lecture seule ou pour un chemin de fin préécrit qui vérifie la postcondition. Ne laissez pas l'agent envoyer une chaîne shell arbitraire marquée reconcile. Cette étiquette n'a aucune valeur de sécurité si la commande peut modifier quoi que ce soit.
Le code 75 de l'exemple signale volontairement un échec temporaire. Le nombre exact compte moins qu'un contrat documenté : l'agent comprend qu'il doit observer l'état et ne pas envoyer automatiquement une nouvelle tentative. Réservez des résultats distincts du contrôleur pour completed, reconcile_required, rejected_before_start et transport_unknown. Un simple booléen success détruit les informations nécessaires à la récupération.
Les délais d'attente et les déconnexions exigent une preuve de l'état distant
Un délai d'attente est une observation locale. Le client local a cessé d'attendre, mais n'a pas forcément arrêté la commande distante. Prendre un délai pour une annulation est l'un des moyens les plus rapides de dupliquer une action distante.
Un contrôleur peut réduire l'ambiguïté en rendant les opérations exclusives. Avant une modification, le script distant crée un verrou exclusif associé à son identifiant d'opération. Une tentative ultérieure voit le verrou et choisit entre attendre, examiner le processus ou signaler qu'une décision humaine est nécessaire.
Pour un verrou simple au niveau de l'hôte, flock suffit souvent :
exec 9>/var/lib/agent-ops/deploy.lock
if ! flock -n 9; then
printf 'another deployment operation is active\n' >&2
exit 75
fi
Cela protège uniquement les processus qui respectent le même verrou. Cela ne protège pas contre un administrateur exécutant une procédure distincte et ne résout pas toutes les erreurs de conception de vos scripts. Pour une migration de base de données, utilisez le verrou consultatif ou le verrou de migration fourni par la base lorsque c'est possible. Pour une action d'API, utilisez un jeton d'idempotence pris en charge par cette API. Le verrou doit se trouver à côté de l'état qu'il protège.
Lorsque le contrôleur se reconnecte après un délai d'attente, examinez les éléments dans cet ordre :
- Lisez le reçu de l'identifiant d'opération initial.
- Vérifiez si le processus initial s'exécute encore, si l'opération possède un marqueur de processus fiable.
- Testez la postcondition de l'opération avec des commandes en lecture seule.
- Choisissez une action de récupération explicite ou faites remonter le cas si les observations se contredisent.
Ne faites pas de la présence du processus votre seul signal. Un processus peut exister tout en étant bloqué par une dépendance externe, tandis qu'un processus absent ne dit presque rien de ce qu'il a modifié avant de s'arrêter. Le reçu et la postcondition apportent des preuves plus solides.
Le multiplexage SSH demande la même prudence. Une connexion maître peut masquer l'échec d'une commande individuelle derrière un transport partagé, et un contrôleur peut confondre la fermeture d'un canal avec l'échec d'une opération. Capturez stdout, stderr, le code SSH brut, l'heure de début et l'heure de fin de la commande distante dans un même enregistrement d'action. Conservez stderr même si l'agent le résume. Les données brutes indiquent souvent si Bash a refusé une variable non définie, si une commande distante a renvoyé 75 ou si SSH lui-même a renvoyé 255.
Certaines modifications exigent une compensation, pas une nouvelle tentative
De nombreuses opérations ne peuvent pas être rendues répétables sans danger après coup. La rotation d'identifiants, le nettoyage destructeur, les appels d'API assimilables à des paiements et les migrations de schéma exigent une procédure compensatoire ou une décision de l'opérateur.
Prenons une rotation d'identifiant. La commande peut créer un nouvel identifiant, mettre à jour un service, vérifier l'accès, puis révoquer l'ancien. Si elle échoue après la création mais avant la mise à jour du service, une nouvelle tentative peut créer encore un identifiant et laisser plusieurs secrets actifs. Le reçu doit enregistrer immédiatement l'identifiant du nouvel objet. La récupération peut ensuite vérifier quel identifiant le service utilise et décider de mettre à jour, de révoquer ou de conserver le nouveau.
Ne placez pas les secrets dans le reçu, la sortie standard ou le contexte de l'agent. Stockez uniquement un identifiant non secret ou une empreinte, à condition que cet identifiant ne donne pas lui-même accès. Le processus de récupération doit savoir quel objet existe, pas connaître sa valeur privée.
Les migrations de bases de données présentent un autre piège. La table d'historique d'un framework peut indiquer qu'une migration nommée est terminée sans décrire un remplissage de données interrompu exécuté hors de la transaction du framework. Écrivez les migrations de façon à séparer les vérifications de la modification de schéma, de la progression du remplissage et du marqueur de fin. Si la base prend en charge le DDL transactionnel pour votre opération, utilisez-le, mais ne supposez pas que chaque instruction DDL ou effet externe sera annulé avec la transaction.
Pour les actions visibles de l'extérieur, préférez un jeton d'idempotence d'API aux suppositions basées sur SSH. Si l'hôte distant appelle une API qui accepte une clé d'idempotence, persistez ce jeton dans le reçu avant la requête. Lors de la récupération, interrogez l'API avec le même jeton ou renvoyez la requête avec ce jeton, selon la sémantique documentée de l'API. Générer un nouveau jeton à chaque tentative de l'agent annule l'intérêt de cette fonction.
La règle est simple : si vous ne pouvez pas expliquer comment déterminer si une action a eu lieu, ne donnez pas à un agent autonome l'autorisation de la réessayer. Demandez à une personne d'inspecter la cible ou repensez l'opération autour d'un enregistrement d'état durable.
Les scripts shell ont besoin d'un contrat que l'agent peut appliquer
Un script destiné à un agent doit exposer un contrat étroit et lisible par machine. Les agents reconstituent mal l'état à partir de journaux bavards, de sorties de terminal colorées et d'un mélange d'avertissements et de messages de réussite.
Utilisez des catégories de sortie stables, un seul objet de résultat et des identifiants d'opération explicites. Par exemple, écrivez une dernière ligne JSON uniquement lorsque la commande connaît son résultat :
{"operation_id":"release-7f3b","outcome":"reconcile_required","checkpoint":"switched","exit_code":75}
Conservez les diagnostics ordinaires sur stderr et réservez stdout à l'enregistrement de résultat si votre contrôleur peut imposer cette convention. Une commande shell qui écrit simultanément des bannières, des barres de progression et du JSON sur stdout invite les erreurs d'analyse. Si la commande diffuse une progression utile, écrivez d'abord le reçu durable et considérez l'enregistrement structuré final comme une commodité, pas comme l'unique preuve.
Ne laissez pas l'agent choisir des noms de checkpoints, des chemins de reçus, des noms de services ou des interpréteurs arbitraires. Exposez une commande vérifiée avec des arguments contraints. Un wrapper qui accepte un shell libre après -- ne fait que déplacer le problème derrière une étiquette plus propre.
Le contrat doit aussi indiquer quels échecs peuvent être réessayés sans danger. Un téléchargement de paquet peut renvoyer une erreur réseau réessayable avant toute modification de l'hôte. Un changement de lien symbolique suivi d'une perte de connexion ne peut pas être réessayé tant que la réconciliation n'a pas vérifié la cible du lien. Cette classification relève de l'auteur de l'opération, qui en connaît les effets, et non d'un modèle qui tente de deviner à partir de stderr.
Utilisez un hôte de test et interrompez le script à chaque checkpoint. Envoyez un signal de terminaison pendant l'extraction de l'archive, après le changement du lien symbolique, pendant le redémarrage et après le contrôle de santé final. Lancez ensuite le chemin de réconciliation et vérifiez qu'il prend la bonne décision. Si vous n'avez jamais interrompu volontairement une opération, vous ne savez pas si son comportement en cas de nouvelle tentative est sûr.
L'autorisation et les journaux d'audit doivent préserver l'historique de récupération
Un agent doit pouvoir effectuer une lecture de récupération, mais une lecture qui conduit à une nouvelle modification doit toujours respecter la limite d'autorisation habituelle. Ne dissimulez pas un deuxième déploiement dans une commande appelée status.
Sallyport peut conserver l'identifiant SSH hors de l'agent et enregistrer à la fois l'exécution de l'agent et chaque action, ce qui aide à établir qui a autorisé une tentative de récupération et quelle commande a été envoyée. Sa piste d'audit ne remplace pas le reçu côté cible : l'enregistrement d'audit peut prouver qu'une demande d'action a eu lieu, tandis que le reçu et la postcondition expliquent l'état obtenu sur la cible.
Conservez ces éléments séparément dans vos notes d'incident. L'identité de session indique quel processus d'agent détenait l'autorisation. L'enregistrement d'action indique quelle commande a été exécutée sur quel hôte et ce qu'elle a renvoyé. Le reçu cible indique où l'opération s'est arrêtée. Lorsqu'un déploiement échoue, réunir ces faits dans une seule transcription de chat fait perdre les preuves nécessaires.
Demandez une confirmation pour chaque appel concernant une opération irréversible, surtout lorsque la réconciliation peut conduire à la suppression d'identifiants, à une réparation de schéma ou à un nettoyage. Cette approbation supplémentaire est utile lorsque les preuves de l'agent se contredisent : par exemple, le reçu indique qu'un changement est terminé, mais le service actif signale encore l'ancienne version. C'est un point de décision, pas une nouvelle tentative ordinaire.
Une bonne conception de récupération rend l'action prudente facile. Donnez à l'agent une commande de réconciliation en lecture seule, un identifiant d'opération durable et un résultat d'escalade défini. Ainsi, une déconnexion produit un enregistrement vérifiable au lieu d'une seconde tentative qui modifie encore le système.
Commencez par corriger la commande que l'équipe réexécute déjà
Trouvez la commande SSH que votre équipe relance après un délai d'attente ou un message de déploiement en erreur. Ajoutez un identifiant d'opération, un reçu protégé et une vérification de postcondition en lecture seule avant de modifier quoi que ce soit d'autre.
Puis interrompez-la volontairement. Si le chemin de récupération ne peut pas déterminer si la première tentative a changé l'état, il n'est pas prêt pour un agent autonome. Réécrivez l'opération jusqu'à ce que la réponse provienne de l'hôte cible, et non de la confiance accordée à un code de sortie.
FAQ
Que dit réellement un code de sortie SSH à un agent IA ?
SSH renvoie généralement le code de sortie de la commande distante. Cela indique si le shell a signalé une réussite, mais ne prouve pas que toutes les opérations précédentes ont laissé l'hôte inchangé. Traitez un code différent de zéro comme un signal invitant à examiner l'état enregistré avant toute nouvelle tentative.
Quand peut-on réessayer automatiquement une commande SSH échouée ?
Réessayez automatiquement uniquement lorsque toutes les opérations précédant l'échec sont idempotentes et que leur postcondition peut être vérifiée. L'actualisation des métadonnées d'un paquet et le redémarrage d'un service nommé peuvent convenir. La création de comptes, la modification des règles du pare-feu et les migrations de données exigent généralement une réconciliation préalable.
set -e empêche-t-il les échecs partiels d'une commande SSH ?
Non. set -e arrête le shell dans de nombreux cas d'erreur, mais comporte des exceptions intentionnelles pour les conditions, les pipelines et les substitutions de commandes. Il ne peut pas non plus annuler une opération terminée avant l'échec d'une commande ultérieure.
Pourquoi les scripts distants doivent-ils utiliser pipefail ?
Utilisez set -o pipefail dans Bash lorsque l'échec d'un élément quelconque du pipeline doit faire échouer le script. Sans cette option, curl | tar peut renvoyer le statut de tar même si curl a échoué, ce qui donne à l'agent une vision dangereusement incomplète de l'exécution.
Que doit contenir le reçu d'une commande SSH ?
Enregistrez un identifiant d'exécution, l'opération prévue, chaque checkpoint terminé, le code de sortie et suffisamment d'état observé pour permettre la récupération. Conservez le reçu sur l'hôte distant ainsi que dans l'enregistrement d'action de l'agent, car une connexion SSH interrompue peut empêcher le retour de la sortie.
Comment empêcher une nouvelle tentative de l'agent d'exécuter deux fois la même modification ?
Utilisez un identifiant d'exécution stable fourni par le contrôleur, écrivez les checkpoints de façon atomique dans un répertoire appartenant à root et faites charger au script tout reçu existant avant son exécution. Un identifiant aléatoire recréé à chaque nouvelle tentative ne permet pas de distinguer une nouvelle tentative d'une nouvelle requête.
Que doit faire un agent après un délai d'attente SSH ?
Un délai d'attente signifie que le contrôleur a cessé d'attendre, pas que le processus distant s'est arrêté. Avant de réessayer, examinez le reçu durable, l'état du processus, le fichier de verrou, l'état du service ou l'enregistrement de transaction sur l'hôte cible.
Que signifie le code de sortie SSH 255 ?
OpenSSH utilise le code de sortie de la commande distante lorsqu'il en reçoit un et renvoie généralement 255 pour ses propres erreurs. Les agents doivent conserver le code brut et stderr, puis distinguer l'échec du script distant de l'échec du transport avant de choisir une procédure de récupération.
Comment un agent peut-il savoir si une modification distante a déjà eu lieu ?
Ne vous fiez pas au seul code de sortie. Vérifiez la postcondition concernée : interrogez le gestionnaire de paquets, examinez le service système, lisez la table des migrations ou comparez la configuration souhaitée avec celle qui est active. L'état observé détermine la bonne opération de récupération.
Les actions SSH d'un agent IA doivent-elles avoir des journaux de session et de commandes distincts ?
Enregistrez à la fois l'identité de la session et chaque action SSH individuelle. L'approbation de session indique quel processus d'agent a reçu l'autorisation, tandis que l'enregistrement d'appel indique quelle commande a été exécutée, sur quelle cible et avec quel résultat. Mélanger ces informations rend un incident plus difficile à reconstituer.