
En 2026, les rôles standalone Galaxy v1 sont legacy. Galaxy NG (backend Galaxy v3) ne supporte que les collections. Si vous maintenez un rôle public, il faut le migrer en collection sans casser les playbooks downstream qui l’utilisent encore avec son ancien nom court. Le mécanisme officiel : meta/runtime.yml avec plugin_routing.redirect, qui maintient la rétrocompatibilité avec un warning de dépréciation et une removal_version planifiée.
Cette page montre la migration complète d’un mini-rôle (avec un module Python custom dans library/ legacy) vers une collection conforme, avec le redirect qui permet aux deux noms (ancien court + nouveau FQCN) de fonctionner pendant la période de transition.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Identifier un rôle standalone candidat à la migration.
- Initialiser la collection cible avec
ansible-galaxy collection init. - Déplacer
tasks/,handlers/,defaults/,templates/versroles/<name>/. - Déplacer un module custom de
library/versplugins/modules/. - Configurer
plugin_routing.redirectdansmeta/runtime.yml. - Tester que l’ancien nom déclenche un warning mais fonctionne.
- Planifier la
removal_version(semver de la collection).
Prérequis
Section intitulée « Prérequis »- Avoir lu Créer une collection custom.
- Un rôle standalone existant à migrer (ou en créer un fictif pour pratiquer).
Le rôle de départ — format legacy
Section intitulée « Le rôle de départ — format legacy »Un rôle standalone Galaxy v1 a typiquement cette structure :
my-old-role/├── tasks/main.yml├── handlers/main.yml├── defaults/main.yml├── templates/└── library/ ← DÉPRÉCIÉ : modules custom à la racine du rôle └── my_module.pyAvec un tasks/main.yml qui invoque le module par son nom court :
- name: Status check my_module: # ← nom court (sans FQCN), legacy register: status🔍 Observation : ce format est rejeté par Galaxy NG. Le library/ n’est plus reconnu dès qu’un rôle vit dans une collection. Les modules custom doivent vivre dans plugins/modules/ au niveau de la collection.
Étape 1 — Initialiser la collection cible
Section intitulée « Étape 1 — Initialiser la collection cible »mkdir -p ansible_collectionsansible-galaxy collection init mycoll.webapp \ --init-path ansible_collections/🔍 Observation : génère la structure conforme avec roles/, plugins/modules/, meta/runtime.yml. Les nouveaux emplacements sont prêts à recevoir le contenu migré.
Étape 2 — Déplacer le rôle dans roles/<name>/
Section intitulée « Étape 2 — Déplacer le rôle dans roles/<name>/ »mkdir -p ansible_collections/mycoll/webapp/roles/myrole/taskscp my-old-role/tasks/main.yml \ ansible_collections/mycoll/webapp/roles/myrole/tasks/main.yml
cp -r my-old-role/handlers \ my-old-role/defaults \ my-old-role/templates \ ansible_collections/mycoll/webapp/roles/myrole/Adapter tasks/main.yml pour utiliser le nouveau FQCN :
- name: Status check mycoll.webapp.my_module: # ← nouveau FQCN register: status🔍 Observation : à l’intérieur de la collection, on peut écrire des noms courts (my_module:) car Ansible les résout dans le contexte de la collection. Mais toujours préférer le FQCN explicite pour la lisibilité et la portabilité.
Étape 3 — Déplacer le module dans plugins/modules/
Section intitulée « Étape 3 — Déplacer le module dans plugins/modules/ »mkdir -p ansible_collections/mycoll/webapp/plugins/modulescp my-old-role/library/my_module.py \ ansible_collections/mycoll/webapp/plugins/modules/my_module.pyCompléter le module avec les sections obligatoires si elles manquent (cf Créer une collection) :
DOCUMENTATION: description + options + author.EXAMPLES: usage YAML copiable avec FQCN complet.RETURN: structure des valeurs retournées.
🔍 Observation : ansible-test sanity exige ces 3 sections. Sans, l’import Galaxy échoue silencieusement.
Étape 4 — Configurer plugin_routing.redirect — le cœur de la migration
Section intitulée « Étape 4 — Configurer plugin_routing.redirect — le cœur de la migration »C’est l’étape clé : permettre à un playbook qui invoque l’ancien nom court my_module: de continuer à marcher.
ansible_collections/mycoll/webapp/meta/runtime.yml :
---requires_ansible: ">=2.18.0"
plugin_routing: modules: my_module: # ← l'ancien nom court redirect: mycoll.webapp.my_module # ← le nouveau FQCN cible deprecation: removal_version: 2.0.0 # ← retrait planifié au bump majeur warning_text: | Le module 'my_module' (rôle standalone) est déprécié. Utilisez 'mycoll.webapp.my_module' (FQCN collection).🔍 Observation cruciale : plugin_routing.modules.<old_name>.redirect déclare la cible. deprecation: ajoute un warning au runtime mais n’échoue pas. removal_version indique quand l’alias sera retiré (semver de la collection).
Étape 5 — Tester l’ancien nom + le nouveau FQCN
Section intitulée « Étape 5 — Tester l’ancien nom + le nouveau FQCN »Créer un playbook de test :
---- hosts: db1.lab collections: - mycoll.webapp # ← déclare la collection (rétrocompat) tasks: - name: Test ancien nom court (avec deprecation warning) my_module: # ← l'ancien nom, qui sera redirigé register: legacy
- name: Test nouveau FQCN explicite mycoll.webapp.my_module: register: new
- ansible.builtin.copy: dest: /tmp/migration-proof.txt content: | legacy: {{ legacy.msg }} new: {{ new.msg }} mode: "0644"Lancer :
ANSIBLE_COLLECTIONS_PATH=ansible_collections \ ansible-playbook lab.ymlSortie attendue :
[DEPRECATION WARNING]: Le module 'my_module' (rôle standalone) est déprécié...TASK [Test ancien nom court (avec deprecation warning)] ***ok: [db1.lab]TASK [Test nouveau FQCN explicite] ***ok: [db1.lab]🔍 Observation : les deux noms fonctionnent. L’ancien nom déclenche un warning mais ne casse pas. Les playbooks downstream peuvent migrer progressivement vers le FQCN au gré des releases mineures.
Étape 6 — Planifier le retrait
Section intitulée « Étape 6 — Planifier le retrait »Workflow release par release :
| Version | Action |
|---|---|
1.0.0 | Première release de la collection avec plugin_routing.redirect actif |
1.x.x | Releases mineures successives. Le warning est affiché. Les downstream migrent. |
2.0.0 | Retrait de l’alias court. removal_version atteinte → plugin_routing est retiré du meta/runtime.yml. Les playbooks qui n’ont pas migré cassent. |
🔍 Observation : la removal_version doit être annoncée bien à l’avance (≥1 an typique) et documentée dans le CHANGELOG.rst comme breaking_changes au bump majeur.
Builder + publier la collection migrée
Section intitulée « Builder + publier la collection migrée »cd ansible_collections/mycoll/webapp/ansible-galaxy collection build --output-path ../../../build/
# Publier sur Galaxyansible-galaxy collection publish \ ../../../build/mycoll-webapp-1.0.0.tar.gz \ --token "$GALAXY_TOKEN"🔍 Observation : dépublier l’ancien rôle Galaxy v1 doit se faire après une période de transition (≥6 mois recommandé). En attendant, mettre un README sur le rôle standalone avec un lien vers la collection cible.
Lab pratique
Section intitulée « Lab pratique »Le lab collections/migration-role (labs/collections/migration-role/) reproduit ce parcours avec 7 tests pytest : structure conforme, plugin_routing.redirect présent, deprecation configurée, fichier preuve sur db1.lab qui montre le résultat des deux noms.
Pièges courants
Section intitulée « Pièges courants »- Renommer le module sans
plugin_routing.redirect: casse tous les playbooks downstream silencieusement. library/legacy à la racine du rôle dans la collection : ignoré par Ansible. Toujours déplacer les modules dansplugins/modules/.- Oublier
meta/runtime.yml:ansible-test sanityéchoue avecNo requires_ansible. - Pas de
removal_version: pattern incomplet, on ne sait pas quand retirer l’alias. - Bumper en 1.x au lieu de 2.0 quand on retire l’alias : casse semver.
À retenir
Section intitulée « À retenir »- Rôles standalone = legacy. Galaxy NG (2026) ne supporte que les collections.
- Migration =
tasks/,handlers/,defaults/→roles/<name>/.library/→plugins/modules/. plugin_routing.redirectdansmeta/runtime.ymlpermet la rétrocompatibilité.deprecation:ajoute un warning au runtime +removal_versionplanifie la suppression.- L’ancien nom continue de marcher — les downstream migrent progressivement.
- Retrait au bump majeur :
2.0.0retire l’alias, breaking change documenté dansCHANGELOG.rst.