Aller au contenu
Infrastructure as Code medium

Tests tox multi-versions : valider un rôle sur ansible-core 2.16, 2.17, 2.18

65 min de lecture

Logo Ansible

Un rôle publié doit fonctionner sur plusieurs versions d'ansible-core (votre utilisateur peut être en 2.16, vous développez en 2.18). tox automatise les tests sur la matrice de versions : tox lance molecule test dans un environnement Python isolé pour chaque version d'Ansible.

Cette page utilise un tox.ini classique (sans le plugin tox-ansible), pattern stable, lisible, et utilisé sur les rôles de production.

  • Écrire un tox.ini classique pour rôle Ansible.
  • Définir une matrice de versions ansible-core (envlist = ansible-2.{16,17,18}).
  • Configurer Python par version d'Ansible.
  • Ajouter un env lint séparé pour fail-fast.
  • Lancer tox complet ou un environnement ciblé.
  • tox installé : pipx install tox.
  • Molecule + Podman opérationnels.
  • Avoir un rôle avec un scénario Molecule fonctionnel.

Le fichier se place à la racine du rôle, à côté de meta/ et de molecule/. Il déclare quatre environnements : trois pour les versions d'ansible-core visées, un pour le lint. Ce dernier n'apparaît pas dans envlist, il ne s'exécute donc que si vous l'appelez explicitement. Les blocs [testenv:ansible-2.X] héritent de [testenv] et n'y ajoutent que ce qui change : le Python de base et les dépendances épinglées.

; tox.ini : pattern classique multi-versions ansible-core
[tox]
envlist = ansible-2.{16,17,18}
skipsdist = true
[testenv]
commands = molecule test
setenv =
TOX_ENVNAME={envname}
PY_COLORS=1
ANSIBLE_FORCE_COLOR=1
ANSIBLE_ROLES_PATH=../
passenv = *
[testenv:ansible-2.16]
basepython = python3.10
deps =
ansible-core==2.16.*
ansible-lint==24.*
molecule>=25.0
molecule-plugins[podman]>=25.0
requests
pytest
[testenv:ansible-2.17]
basepython = python3.10
deps =
ansible-core==2.17.*
ansible-lint==24.*
molecule>=25.0
molecule-plugins[podman]>=25.0
requests
pytest
[testenv:ansible-2.18]
basepython = python3.12
deps =
ansible-core==2.18.*
ansible-lint==25.*
molecule>=26.0
molecule-plugins[podman]>=25.0
requests
pytest
; Lint séparé, fail-fast (s'exécute en premier, isolé)
[testenv:lint]
basepython = python3.12
deps =
ansible-lint==25.*
yamllint
commands =
yamllint roles/
ansible-lint --profile=production roles/

Les trois sections ci-dessous se lisent dans l'ordre où tox les applique : d'abord la matrice globale, puis la configuration partagée, enfin les surcharges propres à chaque version. Comprendre cet héritage évite de répéter inutilement commands et setenv dans chaque bloc.

C'est ici que se décide quels environnements tournent quand vous lancez tox sans argument.

envlist = ansible-2.{16,17,18}
skipsdist = true
  • envlist = matrice. La syntaxe 2.{16,17,18} génère 3 environnements : ansible-2.16, ansible-2.17, ansible-2.18.
  • skipsdist = true = pas de package Python à distribuer (un rôle n'a pas de setup.py).

Tout ce qui est déclaré ici s'applique aux trois environnements de la matrice, sans avoir à le recopier.

commands = molecule test
setenv =
ANSIBLE_ROLES_PATH=../
passenv = *
  • commands : ce qui s'exécute (molecule test pour le cycle complet).
  • setenv : variables d'env exposées à Ansible.
  • passenv = * : laisse passer toutes les variables d'env (utile pour tokens, etc.).

Un bloc par version, dont le nom doit correspondre exactement à celui généré par envlist. C'est le seul endroit où l'on épingle ansible-core.

basepython = python3.10
deps =
ansible-core==2.16.*
molecule>=25.0
  • basepython : version Python compatible avec ansible-core ciblée. Ansible 2.16 exige Python 3.10+, Ansible 2.18 exige 3.12+.
  • deps : pinning des versions exactes.

tox crée un environnement virtuel Python par environnement déclaré, y installe les dépendances, puis exécute commands. Ces venv sont conservés dans .tox/ entre deux exécutions, ce qui rend le premier lancement long et les suivants beaucoup plus rapides. Les trois formes ci-dessous couvrent le quotidien : matrice complète, version unique, lint isolé.

Les environnements s'exécutent séquentiellement ; comptez le temps d'un molecule test multiplié par trois.

Fenêtre de terminal
tox

Tox crée 3 environnements virtuels Python, installe les deps, lance molecule test dans chacun.

Le nom passé à -e est celui d'une section [testenv:...], pas un numéro de version d'Ansible.

Fenêtre de terminal
tox -e ansible-2.18

Cible une version spécifique, utile en dev.

L'environnement lint ne figure pas dans envlist : il ne tourne jamais lors d'un tox sans argument, il faut l'appeler.

Fenêtre de terminal
tox -e lint

Lance ansible-lint --profile=production + yamllint. À mettre en premier dans une CI (s'il échoue, pas la peine de lancer Molecule).

L'ordre compte : le lint dure quelques secondes là où la matrice complète prend plusieurs minutes, autant échouer tôt. Attention, l'environnement publish de la troisième étape n'existe pas dans le tox.ini présenté plus haut ; il faut lui ajouter une section [testenv:publish] avec la commande ansible-galaxy de votre choix, sinon tox s'arrête sur un environnement inconnu.

Fenêtre de terminal
# Étape 1 : lint (rapide)
tox -e lint
# Étape 2 : matrice complète
tox
# Étape 3 (sur tag Git) : publication Galaxy
tox -e publish

Le critère de choix n'est pas la richesse fonctionnelle mais le type d'artefact que vous publiez. Un rôle standalone n'a ni tests de sanity ni tests unitaires à orchestrer, ce qui rend le tox.ini classique suffisant. Une collection change la donne et justifie tox-ansible. La dernière ligne n'est pas une alternative : la matrice GitHub Actions pilote les jobs, tox reste ce qui tourne à l'intérieur de chacun.

OutilPérimètreRecommandation 2026
tox classiqueRôles standalone✅ Recommandé
tox-ansibleCollections AnsibleQuand vous publiez une collection
noxAlternative Python à toxUtilisable mais moins courant en Ansible
GitHub Actions matrixCI/CD natifComplémentaire (voir page CI)

Un rôle qui passe sur une seule version d'Ansible ne dit rien de son comportement sur les autres. Le lab vous fait écrire un tox.ini qui épingle une version d'ansible-core par environnement, associe à chacun le basepython compatible, et lance molecule test sur toute la matrice en une seule commande. La validation relit envlist, les dépendances de chaque environnement et la présence d'un environnement lint séparé.

Les deux premiers symptômes viennent du même point : basepython désigne un interpréteur qui doit exister sur la machine, tox ne l'installe pas. Deux autres lignes portent sur la durée d'exécution, principal frein à l'adoption d'une matrice en local, et la dernière sur les variables d'environnement absentes du runner de CI. Repérez votre message d'erreur dans la colonne de gauche, la correction se trouve à droite.

SymptômeCauseFix
Python 3.10 not foundbasepython absent du systèmeInstaller Python 3.10 ou utiliser pyenv
ansible-core 2.16 incompatible avec Python 3.13Trop récentUtiliser Python 3.10 pour Ansible 2.16/2.17
Lent à chaque runtox recrée les venvUtiliser tox -r (recreate) seulement si deps changent
Tests passent locallement mais ratent en CIVariables d'env manquantesAjouter passenv = * ou lister les vars critiques
molecule test lent en localContainer recreate à chaque envCycle dev : molecule converge puis molecule verify
  • tox.ini classique > tox-ansible pour rôles standalone.
  • envlist = ansible-2.{16,17,18} = matrice de versions.
  • basepython par version d'Ansible (2.16 → 3.10, 2.18 → 3.12).
  • Env lint séparé pour fail-fast en CI.
  • tox -e <env> pour cibler une version en dev.
  • CI GitHub Actions : porter la matrice tox dans un workflow, avec des permissions minimales.
  • CI GitLab : la même matrice en parallel:matrix, avec release automatique sur tag.
  • Versionner et publier : l'étape qui suit une matrice verte : tag semver, changelog, publication.

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