
verify.yml Ansible suffit pour 80 % des cas, mais quand vos assertions deviennent complexes (logique conditionnelle, agrégation, comparaison cross-host), testinfra offre une API Python beaucoup plus expressive. Cette page explique quand basculer vers testinfra, comment le configurer comme verifier Molecule, et comment écrire des tests Python idiomatiques.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Quand préférer testinfra à verify.yml.
- Configurer
verifier: testinfradansmolecule.yml. - L'API testinfra :
host.package,host.service,host.socket,host.file,host.run. - Écrire des tests pytest lancés par Molecule.
- Combiner verify.yml et testinfra dans le même rôle.
Quand utiliser testinfra ?
Section intitulée « Quand utiliser testinfra ? »| Besoin | Outil recommandé |
|---|---|
| « Le service nginx est-il running ? » | verify.yml (1 assertion) |
| « Le port 80 est-il ouvert ? » | verify.yml |
| « La conf nginx contient-elle 5 directives spécifiques avec des conditions ? » | testinfra (Python plus lisible) |
| « Vérifier la cohérence cross-host (master/replica) » | testinfra |
| « Assertion conditionnelle complexe (si X alors Y sinon Z) » | testinfra |
| « Test d'idempotence custom » | testinfra |
Règle : si votre verify.yml dépasse 50 lignes ou nécessite des block: imbriqués → bascule vers testinfra.
Configurer testinfra comme verifier
Section intitulée « Configurer testinfra comme verifier »verifier: name: testinfra options: v: trueUne seule ligne suffit pour basculer du vérifier ansible (verify.yml) à testinfra (Python). options.v: true active le mode verbose pour voir les tests détaillés.
Structure des tests
Section intitulée « Structure des tests »Molecule cherche les tests dans molecule/<scenario>/tests/test_*.py.
molecule/└── default/ ├── molecule.yml ├── converge.yml └── tests/ ← convention testinfra ├── test_webserver.py └── test_security.pyL'API testinfra
Section intitulée « L'API testinfra »def test_nginx_is_installed(host): """Vérifie que nginx est installé.""" assert host.package("nginx").is_installed
def test_nginx_is_running_and_enabled(host): """Service nginx démarré et activé au boot.""" nginx = host.service("nginx") assert nginx.is_running assert nginx.is_enabled
def test_nginx_listens_on_8080(host): """nginx écoute sur 8080.""" assert host.socket("tcp://0.0.0.0:8080").is_listening
def test_nginx_config_valid(host): """nginx -t renvoie OK.""" cmd = host.run("nginx -t") assert cmd.rc == 0
def test_index_html_content(host): """Page d'accueil contient le custom message.""" f = host.file("/usr/share/nginx/html/index.html") assert f.exists assert f.user == "root" assert "testinfra-tested" in f.content_stringFixture host automatique, Molecule l'injecte. Pas besoin de configurer pytest.
API testinfra, les modules essentiels
Section intitulée « API testinfra, les modules essentiels »Ces neuf modules couvrent l'essentiel de ce qu'un rôle produit sur une machine. Les cinq premiers, package, service, socket, file et run, suffisent à la quasi-totalité des assertions ; les quatre suivants servent des cas précis, un compte Linux, un processus, une règle de pare-feu ou une unité systemd. Chacun rend un objet dont on lit les attributs, ce qui évite d'analyser une sortie de commande.
| Module | Exemple | Cas d'usage |
|---|---|---|
host.package(name) | .is_installed, .version | Vérifier paquet |
host.service(name) | .is_running, .is_enabled | Vérifier service systemd |
host.socket(uri) | .is_listening | Vérifier port en écoute |
host.file(path) | .exists, .mode, .user, .content_string | Vérifier fichier |
host.run(cmd) | .rc, .stdout, .stderr | Exécuter commande arbitraire |
host.user(name) | .exists, .uid, .gid, .shell | Vérifier utilisateur Linux |
host.process | .filter(comm='nginx') | Vérifier process en cours |
host.iptables | rules | Inspecter iptables |
host.systemd | unit-level checks | systemd avancé |
Comparaison verify.yml vs testinfra
Section intitulée « Comparaison verify.yml vs testinfra »La comparaison qui suit oppose le même contrôle écrit des deux façons, une fois sur un cas trivial, une fois sur un cas à branchements. Le résultat n'est pas celui qu'on attend : testinfra est plus court dans les deux cas. Ce qui fait pencher vers verify.yml n'est donc pas la concision, c'est de rester dans le langage du rôle, sans demander Python à une équipe qui écrit du YAML toute la journée.
Cas simple, testinfra gagne en concision
Section intitulée « Cas simple, testinfra gagne en concision »- name: Vérifier nginx running ansible.builtin.systemd: name: nginx state: started check_mode: true register: r failed_when: r is changed# testinfra (équivalent)def test_nginx_running(host): assert host.service("nginx").is_runningDeux lignes contre sept, pour un contrôle identique. Le vérifier ansible reste pourtant le défaut recommandé : il garde les assertions dans le même langage que le rôle, et une équipe qui écrit du YAML n'a alors aucun Python à maintenir.
Cas complexe, testinfra gagne (expressivité)
Section intitulée « Cas complexe, testinfra gagne (expressivité) »def test_nginx_config_consistency(host): """Test complexe : 5 directives à vérifier avec logique.""" config = host.file("/etc/nginx/nginx.conf").content_string
# Worker processes auto si CPU > 4 cœurs cpus = int(host.run("nproc").stdout.strip()) if cpus > 4: assert "worker_processes auto" in config else: assert "worker_processes 4" in config
# gzip activé en HTTPS, désactivé en HTTP if "ssl on" in config: assert "gzip on" in config else: # En HTTP-only, gzip désactivé pour les attaques BREACH assert "gzip on" not in config or "gzip_disable" in config
# SSL TLS 1.2 minimum if "listen 443" in config: assert "ssl_protocols TLSv1.2 TLSv1.3" in config assert "TLSv1 " not in config assert "TLSv1.1" not in configFaire ce genre de test en verify.yml serait inhumain, Python brille ici.
Utiliser testinfra hors Molecule
Section intitulée « Utiliser testinfra hors Molecule »testinfra n'est pas couplé à Molecule. Sur un projet playbook-based (sans rôle, ou sur des machines déjà provisionnées), on peut le lancer directement avec pytest. Deux backends utiles selon le contexte.
Backend local://, tester le control node lui-même
Section intitulée « Backend local://, tester le control node lui-même »Pour vérifier que la machine d'exécution (poste dev, CI runner, bastion) respecte une baseline :
def test_python3_is_installed(host): assert host.package("python3").is_installed
def test_passwd_permissions(host): f = host.file("/etc/passwd") assert f.user == "root" assert f.mode == 0o644pytest -v --hosts=local:// tests/testinfra exécute les commandes localement, utile pour valider un poste, un container CI, un environnement de build.
Backend ansible://, tester via inventaire Ansible
Section intitulée « Backend ansible://, tester via inventaire Ansible »Pour tester des machines distantes déjà déclarées dans un inventaire Ansible (production, staging, lab Vagrant) :
[webservers]web1.lab ansible_user=ansibleweb2.lab ansible_user=ansibledef test_nginx_listens_on_80(host): assert host.socket("tcp://0.0.0.0:80").is_listening
def test_inventory_facts_available(host): facts = host.ansible("setup")["ansible_facts"] assert facts["ansible_distribution"] in ("Ubuntu", "Rocky", "AlmaLinux")pytest -v --hosts="ansible://webservers" \ --ansible-inventory=inventory.ini \ --force-ansible tests/host.ansible("setup") récupère les facts comme un play Ansible, pratique pour brancher la logique de test selon la distribution sans recoder la détection.
Détection de drift par test
Section intitulée « Détection de drift par test »Un cas avancé : vérifier que la version installée correspond à la source de vérité (variables d'inventaire). Si un admin patche manuellement, le test échoue et signale la dérive.
def test_nginx_version_matches_inventory(host): facts = host.ansible.get_variables() expected = facts.get("nginx_version") assert expected, "nginx_version manquant dans l'inventaire"
installed = host.package("nginx").version assert installed.startswith(expected), ( f"Drift détecté : installé={installed} attendu={expected}" )À brancher dans une CI nocturne, toute dérive entre le code Ansible et les machines réelles est détectée et notifiée. Voir aussi Baselines et drift.
Mettre en pratique
Section intitulée « Mettre en pratique »Basculer le vérifier de Molecule change la nature des assertions : on quitte le YAML pour du Python qui interroge la machine. Le lab vous fait déclarer verifier: testinfra dans molecule.yml, écrire des tests appuyés sur la fixture host, puis multiplier les cas avec parametrize au lieu de dupliquer des fonctions. La validation contrôle la configuration Molecule et exige un jeu de tests réellement exploitable, pas un fichier vide.
Pièges courants
Section intitulée « Pièges courants »Ces cinq symptômes relèvent tous d'un décalage entre ce que testinfra interroge et ce que vous croyez interroger : une fixture absente, un become hérité, un contenu binaire, un chemin qui change de distribution, une écoute en IPv6. Aucun n'est une erreur de Python, et c'est pourquoi la trace pytest ne suffit jamais à les comprendre.
| Symptôme | Cause | Fix |
|---|---|---|
host fixture not found | Pas dans tests/ Molecule ou pytest standalone | Lancer via molecule verify, pas pytest direct |
host.run retourne rc != 0 | Permissions sudo manquantes | Tests testinfra héritent de become Molecule |
host.file().content_string plante | Fichier binaire | Utiliser .content (bytes) au lieu de .content_string |
| Tests passent sur RHEL, échouent sur Debian | Path différent | Charger host.system_info.distribution puis brancher |
host.socket('tcp://0.0.0.0:80') faux négatif | nginx écoute sur IPv6 uniquement | Tester aussi tcp://:::80 |
Contrôle de connaissances
Section intitulée « Contrôle de connaissances »Vérifiez que l'essentiel de ce guide est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Profil de compétences
Quoi faire maintenant
Ressources pour progresser
Des indices pour retenter votre chance ?
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications
À retenir
Section intitulée « À retenir »verify.yml= défaut 2026. testinfra complément pour assertions complexes.verifier: testinfra+options.v: truedansmolecule.yml.- API :
host.package,host.service,host.socket,host.file,host.run. - Fixture
hostinjectée automatiquement par Molecule. - Combinable :
verify.ymlpour le simple + testinfra pour le complexe dans le même scenario.
Pour aller plus loin
Section intitulée « Pour aller plus loin »- ansible-lint production : compléter les tests par le contrôle statique, avant toute exécution.
- CI GitHub Actions : lancer testinfra à chaque push, sur plusieurs distributions.
- Auditer un rôle existant : juger la qualité des tests d'un rôle tiers avant de l'adopter.