Aller au contenu
Infrastructure as Code medium

Commandes ad-hoc Ansible : modules, patterns d'hôtes et quand basculer en playbook

11 min de lecture

Logo Ansible

Une commande ad-hoc Ansible exécute un module unique sur un pattern d'hôtes, sans écrire de playbook. C'est l'outil parfait pour les opérations one-shot : tester la connectivité, vérifier la version d'un paquet, redémarrer un service sur un sous-ensemble de la fleet, copier un fichier ponctuel. Les commandes ad-hoc constituent un objectif explicite de l'examen RHCE EX294, vous devez savoir les écrire à la volée sans hésiter. Cette page couvre la syntaxe, les modules essentiels avec sorties réelles, les patterns d'hôtes, et les critères pour basculer en playbook.

  • Comprendre la syntaxe ansible PATTERN -m MODULE -a "ARGS" et chaque composant ;
  • Lancer les modules de base : ping, setup, command, shell, dnf, service, copy, file ;
  • Cibler des hôtes avec les patterns : groupes, wildcards, intersections, exclusions ;
  • Reconnaître les trois statuts dans la sortie (SUCCESS, CHANGED, FAILED) ;
  • Décider quand une opération doit basculer en playbook (idempotence stricte, multi-tâches, traçabilité).
Fenêtre de terminal
ansible PATTERN -m MODULE [-a "ARGS"] [OPTIONS]
ComposantRôleExemple
PATTERNCible un ou plusieurs hôtesall, web1.lab, webservers, web*
-m MODULEModule à exécuterping, setup, dnf, service, copy, file
-a "ARGS"Arguments du module (clé=valeur)name=nginx state=present
OPTIONSOptions Ansible--check, --diff, -b (become), -K (ask sudo pwd)

Si vous omettez -m, Ansible utilise par défaut le module command (ansible all -a 'uptime' est équivalent à ansible all -m command -a 'uptime'). Mais soyez explicite, vous gagnerez en clarté.

Fenêtre de terminal
ansible all -m ping
web1.lab | SUCCESS => {
"changed": false,
"ping": "pong"
}
db1.lab | SUCCESS => {
"changed": false,
"ping": "pong"
}
web2.lab | SUCCESS => {
"changed": false,
"ping": "pong"
}
control-node.lab | SUCCESS => {
"changed": false,
"ping": "pong"
}

SUCCESS + changed: false : la chaîne fonctionne et rien n'a été modifié.

Le module setup affiche les centaines de variables que la phase gather_facts collecte au début de chaque play. Pratique pour vérifier la valeur d'un fact :

Fenêtre de terminal
ansible web1.lab -m setup -a 'filter=ansible_distribution*'
web1.lab | SUCCESS => {
"ansible_facts": {
"ansible_distribution": "AlmaLinux",
"ansible_distribution_file_parsed": true,
"ansible_distribution_file_path": "/etc/redhat-release",
"ansible_distribution_file_variety": "RedHat",
"ansible_distribution_major_version": "10",
"ansible_distribution_release": "Heliotrope Lion",
"ansible_distribution_version": "10.1"
},
"changed": false
}

Le filter= accepte un wildcard glob. Sans filtre, vous récupérez plusieurs centaines de lignes de facts.

Fenêtre de terminal
ansible webservers -m command -a 'uptime'
web1.lab | CHANGED | rc=0 >>
14:40:14 up 6 min, 2 users, load average: 0.06, 0.12, 0.06
web2.lab | CHANGED | rc=0 >>
14:40:15 up 6 min, 2 users, load average: 0.06, 0.10, 0.04

Statut CHANGED parce que command est non-idempotent par défaut. Le rc=0 confirme l'exit code zéro. Pas de pipe, pas de redirection (>), pas de variable d'environnement, c'est le rôle de shell.

Fenêtre de terminal
ansible webservers -m shell -a 'df -h / | tail -1'
web1.lab | CHANGED | rc=0 >>
/dev/vda4 8.8G 1.1G 7.8G 12% /
web2.lab | CHANGED | rc=0 >>
/dev/vda4 8.8G 1.1G 7.8G 12% /

shell accepte les pipes, redirections, et variables d'environnement. À utiliser uniquement quand command ne suffit pas, shell est un vecteur d'injection si la valeur vient d'une variable mal contrôlée.

Fenêtre de terminal
ansible db1.lab -m dnf -a 'name=tree state=present' --check
db1.lab | CHANGED => {
"changed": true,
"msg": "Check mode: No changes made, but would have if not in check mode",
"rc": 0,
"results": [
"Installed: tree-2.1.0-8.el10.x86_64"
]
}

L'option --check (dry-run) montre ce qui serait fait sans appliquer le changement. C'est la combinaison parfaite pour valider une commande risquée avant de la lancer pour de vrai.

Fenêtre de terminal
ansible web1.lab -m service -a 'name=firewalld state=started'
web1.lab | SUCCESS => {
"changed": false,
"name": "firewalld",
"state": "started",
...
}

changed: false parce que firewalld est déjà démarré (le playbook de préparation l'a fait). service est idempotent : il ne tente l'action que si l'état réel diverge de l'état désiré.

Fenêtre de terminal
echo "test ansible 2026" > /tmp/ansible-test.txt
ansible web1.lab -m copy -a 'src=/tmp/ansible-test.txt dest=/tmp/ansible-test.txt mode=0644'

Premier run :

web1.lab | CHANGED => {
"changed": true,
"checksum": "6e8652783ec319763ffa93599d00443fba131901",
"dest": "/tmp/ansible-test.txt",
"mode": "0644",
...
}

Second run immédiat :

web1.lab | SUCCESS => {
"changed": false,
"checksum": "6e8652783ec319763ffa93599d00443fba131901",
"dest": "/tmp/ansible-test.txt",
"mode": "0644",
...
}

SUCCESS + changed: false : Ansible a comparé le checksum SHA-1 local et distant, ils sont identiques, aucun transfert n'a eu lieu. C'est l'idempotence par checksum.

file, gérer les permissions et les chemins (idempotent)

Section intitulée « file, gérer les permissions et les chemins (idempotent) »
Fenêtre de terminal
ansible web1.lab -m file -a 'path=/tmp/ansible-test.txt state=absent'
web1.lab | CHANGED => {
"changed": true,
"path": "/tmp/ansible-test.txt",
"state": "absent"
}

Au second run, le fichier est déjà absent → changed: false. Le module file couvre aussi les permissions (mode, owner, group), les liens symboliques (state=link) et la création de répertoires (state=directory).

PatternCible
allTous les hôtes de l'inventaire
web1.labUn seul hôte par son nom exact
webserversTous les hôtes du groupe webservers
webservers:dbserversUnion : tous les hôtes des deux groupes
webservers:&rhce_labIntersection : hôtes dans webservers ET dans rhce_lab
webservers:!web1.labExclusion : tous les webservers SAUF web1.lab
web*Wildcard : tout hôte commençant par web
web*:!*.localCombinaison : web* SAUF *.local

Exemple concret, appliquer un patch sur tous les webservers sauf un :

Fenêtre de terminal
ansible 'webservers:!web1.lab' -m dnf -a 'name=* state=latest' -b

L'option -b active become (sudo). Le * côté name= met tous les paquets à jour.

StatutCouleurSignification
SUCCESSvertModule idempotent, aucun changement
CHANGEDjauneModule a appliqué un changement réel
FAILEDrougeModule a échoué (rc != 0, exception, etc.)
UNREACHABLErougeHôte injoignable en SSH

SUCCESS + changed: false est le signal qu'un second passage n'aurait rien à faire, c'est la preuve d'idempotence au niveau ad-hoc.

L'ad-hoc atteint ses limites dès que l'opération devient :

  • Multi-tâches : enchaîner installation + configuration + démarrage de service. Un playbook gère la séquence et arrête tout en cas d'erreur intermédiaire.
  • Conditionnelle : « installer nginx si la distribution est RedHat ». Un when: dans un play est plus propre qu'un script qui appelle ansible plusieurs fois.
  • Traçable : un playbook YAML versionné dans Git documente l'opération, sa relance est reproductible. Une commande ad-hoc dans un terminal est volatile.
  • Idempotente avec variables : ad-hoc accepte -a "name={{ var }}" mais sans inventaire de variables, ça devient vite illisible. Variables, vars_files et group_vars sont la zone du playbook.

Règle pratique : plus de 3 commandes ad-hoc consécutives sur la même cible = il est temps d'écrire un playbook.

SymptômeCauseFix
module not found ou silenceMauvais nom de module ou collection non installéeansible-doc -l | grep <nom> ; ansible-galaxy collection install <fqcn>
Pipes (|) and redirections require a shellcommand reçoit un pipe alors qu'il ne supporte pasBascule en -m shell (et seulement si nécessaire)
changed=true à chaque run sur command/shellModules non idempotents par natureAjouter creates: ou removes: ; mieux : utiliser le module idempotent dédié (dnf, service, file)
--ask-pass demandé alors que la clé est OKAnsible n'a pas trouvé la cléVérifier ansible.cfg (private_key_file) ou poser ansible_ssh_private_key_file dans l'inventaire
  • La syntaxe ansible PATTERN -m MODULE -a "ARGS" est l'outil principal pour les opérations one-shot sur une fleet.
  • Les modules essentiels sont ping, setup, command, shell, dnf, service, copy, file, à connaître par cœur pour la RHCE.
  • Les patterns d'hôtes combinent groupes, wildcards, intersections (&) et exclusions (!).
  • SUCCESS + changed: false = idempotence ; CHANGED = action réelle ; FAILED = à investiguer.
  • Bascule en playbook dès que l'opération est multi-tâches, conditionnelle, traçable ou paramétrée.
  • L'option --check est le mode dry-run universel pour valider sans appliquer.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn