Introduction
Les programmes de maintenance existants nécessitent une intégration soigneuse à l'automatisation déclarative. Vous distinguerez command, shell et script, transmettrez un chemin avec espace de façon sûre, classerez les résultats en lecture seule et protégerez l'exécution selon la sortie réelle d'un script. Un pipeline et des reçus délégués au contrôleur rendront observables le lieu d'exécution et la propagation des échecs. Vous provoquerez aussi un véritable échec d'entrée manquante, puis le corrigerez.
Exécuter une commande directe avec des arguments sûrs
Dans cette étape, vous examinerez une entrée gérée avec command, préserverez un chemin contenant un espace et classerez correctement l'opération en lecture seule.
Préférez les modules déclaratifs tels que copy et file pour gérer l'état. Command, shell et script sont utiles pour intégrer un exécutable ou programme de maintenance existant. command exécute un programme géré sans shell : les pipes et redirections ne sont donc pas interprétés. Sa forme argv garde chaque argument séparé, y compris un chemin contenant des espaces.
Les cibles préparées possèdent chacune /home/automation/maintenance input.txt contenant une ligne de données approuvées, et un prérequis maintenance-ready. Le contrôleur fournit un script existant sous scripts/ pour la suite. Préservez ces entrées.
Entrez dans le projet du contrôleur :
cd /home/labex/project
Créez un playbook avec argv. Le chemin contenant un espace est une seule entrée de liste YAML. register capture le résultat de l'exécutable, dont stdout et son code de retour numérique rc. Zéro signifie normalement la réussite ; un code de retour de commande non nul fait normalement échouer la tâche.
cat > maintenance.yml <<'YAML'
- name: Inspect maintenance inputs safely
hosts: all
gather_facts: false
tasks:
- name: Read the managed input with a space-safe argument list
ansible.builtin.command:
argv:
- /usr/bin/cat
- /home/automation/maintenance input.txt
register: input_result
changed_when: false
- name: Retain the inspected input in a managed record
ansible.builtin.copy:
dest: /home/automation/command-result.txt
content: "{{ input_result.stdout }}\n"
mode: "0640"
YAML
La commande cat est en lecture seule : changed_when false classe donc son résultat comme inchangé. Ce paramètre modifie le signalement, pas les actions réelles d'une commande ; il ne doit pas masquer les changements d'un programme qui modifie l'état. La tâche copy consomme stdout renvoyé et écrit un véritable enregistrement géré avec un saut de ligne final explicite.
Vérifiez et exécutez le playbook :
ansible-playbook maintenance.yml --syntax-check
ansible-playbook maintenance.yml
Les deux tâches de lecture doivent indiquer ok, tandis que la première copie d'enregistrement modifie chaque cible. Examinez les enregistrements réels :
ansible all -m ansible.builtin.command -a 'cat /home/automation/command-result.txt'
Chacun doit contenir Approved maintenance data. Dans cette version de core, command peut développer les arguments de variables d'environnement via Python bien qu'il n'invoque pas de shell. Utilisez expand_argument_vars false lorsque des arguments littéraux préfixés par un dollar sont requis ; cela n'est pas nécessaire pour ce chemin fixe.
Transférer un script du contrôleur et protéger son exécution par sa sortie réelle
Dans cette étape, vous invoquerez le script de maintenance fourni côté contrôleur sur les deux cibles et éviterez des répétitions inutiles de son exécution.
Examinez le programme fourni avant de l'exécuter :
cat scripts/host-maintenance.sh
Il vérifie l'entrée maintenance-ready de la cible avant de créer une sortie. Une préparation manquante affiche une erreur et termine avec 42. Sinon, il écrit un rapport protégé contenant le véritable nom d'hôte cible et son argument de libellé. Sa petite implémentation shell est une entrée d'intégration existante ; utilisez des modules déclaratifs pour la configuration ordinaire de fichiers.
Le module script transfère une source du contrôleur vers la cible et l'y exécute. Cela diffère de command, dont l'exécutable doit déjà exister sur le nœud géré. Le libellé entre guillemets ci-dessous reste un argument unique avec un espace. Le chemin creates est vérifié sur la cible gérée : lorsque ce rapport existe déjà, le script est ignoré.
Ajoutez la tâche script :
cat >> maintenance.yml <<'YAML'
- name: Run the supplied controller script once per target report
ansible.builtin.script:
cmd: /home/labex/project/scripts/host-maintenance.sh 'Maintenance checked'
creates: /home/automation/maintenance-run/report.txt
register: maintenance_result
failed_when: maintenance_result.rc is defined and maintenance_result.rc != 0
YAML
Le rc du résultat enregistré contrôle failed_when. La garde is defined tient compte d'un résultat ne contenant pas de code de retour d'exécution. N'utilisez pas ignore_errors ou failed_when false pour transformer un véritable échec de script en réussite apparente.
Exécutez le playbook étendu :
ansible-playbook maintenance.yml
Les deux cibles doivent créer des rapports. Lisez les véritables sorties :
ansible all -m ansible.builtin.command -a 'cat /home/automation/maintenance-run/report.txt'
Chacune doit contenir son propre nom d'hôte et label=Maintenance checked. Répétez le même playbook :
ansible-playbook maintenance.yml
Le script doit être ignoré car son rapport cible existe, et les deux récapitulatifs doivent indiquer changed=0 sans cible en échec ou inaccessible. Creates est une garde d'existence, pas un moteur de réconciliation de contenu : il ne corrige pas un rapport existant corrompu et ne le régénère pas automatiquement lorsque les entrées du script changent.
Propager les échecs et déléguer les reçus au contrôleur
Dans cette étape, vous utiliserez shell uniquement pour un véritable pipeline, stockerez des reçus distincts sur le contrôleur et exercerez un échec de script visible sans le masquer.
Un pipe relie la sortie d'une commande à l'entrée d'une autre et nécessite donc shell. Le pipefail de Bash fait qu'une commande en échec dans un pipeline produit un échec au lieu de laisser un wc final réussi le masquer. Le pipeline ci-dessous compte seulement les lignes d'entrée ; changed_when false convient car il lit sans modifier l'état cible. failed_when rejette aussi un nombre de lignes inattendu.
Créez un répertoire de reçus sur le contrôleur. Chaque copie déléguée utilisera le nom d'inventaire d'origine dans un nom de fichier distinct, empêchant les hôtes d'écraser un reçu partagé unique :
mkdir -p receipts
Ajoutez les tâches de pipeline et de reçu. delegate_to localhost exécute uniquement la tâche de reçu sur le contrôleur ; inventory_hostname identifie toujours la cible d'origine. become false garde la création de fichiers du contrôleur sous le compte ordinaire labex.
cat >> maintenance.yml <<'YAML'
- name: Count managed input lines with explicit pipeline failure propagation
ansible.builtin.shell: |
set -o pipefail
cat '/home/automation/maintenance input.txt' | wc -l
args:
executable: /bin/bash
register: line_result
changed_when: false
failed_when: line_result.rc != 0 or (line_result.stdout | trim) != '1'
- name: Store a per-target receipt on the controller
ansible.builtin.copy:
dest: "/home/labex/project/receipts/{{ inventory_hostname }}.txt"
content: |
host={{ inventory_hostname }}
input_lines={{ line_result.stdout | trim }}
mode: "0640"
delegate_to: localhost
become: false
YAML
Exécutez la procédure complète de maintenance :
ansible-playbook maintenance.yml
Examinez les deux reçus du contrôleur. Chacun doit identifier son propre hôte d'origine et input_lines=1 :
cat receipts/web1.txt receipts/web2.txt
Exercez maintenant la véritable branche d'échec du script sur web1. Supprimez son rapport protégé par la garde et son entrée de préparation avec le module file ; ce sont des changements temporaires intentionnels dans le nœud d'entraînement :
ansible web1 -m ansible.builtin.file -a 'path=/home/automation/maintenance-run/report.txt state=absent'
ansible web1 -m ansible.builtin.file -a 'path=/home/automation/maintenance-ready state=absent'
La prochaine exécution doit faire échouer la tâche script sur web1 avec rc 42 et le message d'entrée manquante. || permet de poursuivre dans le Terminal après ce code de sortie non nul attendu du playbook ; il ne change pas la classification d'échec d'Ansible :
ansible-playbook maintenance.yml || printf 'Expected missing-readiness failure\n'
Examinez le chemin du rapport ; web1 ne doit pas posséder de rapport de réussite fabriqué après l'échec du script :
ansible web1 -m ansible.builtin.stat -a 'path=/home/automation/maintenance-run/report.txt'
Restaurez l'entrée de préparation depuis une source exacte du contrôleur et relancez la procédure complète :
printf 'Ready\n' > ready.txt
ansible web1 -m ansible.builtin.copy -a 'src=/home/labex/project/ready.txt dest=/home/automation/maintenance-ready mode=0644'
ansible-playbook maintenance.yml
Web1 doit régénérer son rapport avec succès. La répétition finale ne doit avoir aucun changement, cible inaccessible ou échec :
ansible-playbook maintenance.yml
Les inspections en lecture seule continuent à s'exécuter, le script protégé par la garde ignore les rapports existants et chaque reçu délégué reste sur le contrôleur. Cela préserve les véritables signaux d'erreur tout en gardant les répétitions réussies stables.
Résumé
Vous avez utilisé argv pour l'exécution gérée directe, script pour le transfert de programmes du contrôleur vers les cibles, et shell uniquement pour un véritable pipeline avec propagation explicite des échecs. Le signalement des changements en lecture seule, une véritable garde creates et des codes de sortie non masqués ont gardé les résultats significatifs. Les reçus délégués par hôte ont démontré l'exécution sur le contrôleur, et l'exercice d'entrée manquante s'est terminé par une procédure restaurée et stable.


