Aller au contenu

Développer et installer des collections

Mise à jour :

logo ansible

Les collections Ansible est le format de distribution de contenu Ansible. Une collection regroupe différents types de contenu, tels que des rôles, modules, playbooks, plugins et même des scripts de tests, dans une structure modulaire et bien définie. Cela permet aux utilisateurs et aux organisations de maintenir leur infrastructure d’automatisation de manière plus organisée, tout en rendant le contenu plus facilement distribuable et réutilisable.

Avant l’introduction des collections, le contenu Ansible était principalement structuré en rôles individuels, souvent distribués via Ansible Galaxy ou des dépôts Git. Cependant, cette approche avait des limites, notamment en termes de gestion des dépendances entre rôles, de modularité et de partage de contenu au sein d’équipes ou d’organisations. Les collections ont été conçues pour pallier ces limites, en apportant une solution plus flexible et scalable pour organiser des projets d’automatisation complexes.

Les collections permettent également de standardiser la manière dont les modules, plugins et rôles sont empaquetés et distribués. En utilisant les collections, les développeurs peuvent non seulement regrouper du contenu Ansible mais aussi garantir la compatibilité avec différentes versions d’Ansible Core, faciliter la mise à jour et la distribution de modules ou de rôles et enfin permettre une meilleure gestion des dépendances.

Un exemple classique est l’organisation d’une collection dédiée à un fournisseur de services spécifiques comme Cisco ou AWS. Par exemple, la collection cisco.ios regroupe tous les modules, rôles et plugins nécessaires pour l’automatisation des appareils Cisco IOS, facilitant ainsi la gestion de tout ce contenu lié sous un même namespace.

Enfin, les collections ont une grande importance pour la communauté open-source Ansible, car elles permettent de mieux structurer les contributions de la communauté, tout en facilitant l’intégration des nouvelles fonctionnalités via Ansible Galaxy. Cela donne également aux utilisateurs la possibilité de consommer du contenu Ansible provenant de diverses sources fiables, tout en assurant une installation et une gestion simplifiées via des outils intégrés comme ansible-galaxy.

Ainsi, une bonne compréhension des collections Ansible est devenue incontournable pour les administrateurs système et les développeurs souhaitant automatiser leur infrastructure de manière modulable, distribuée et maintenable sur le long terme.

Installation des collections

L’installation des collections Ansible se fait principalement via l’outil ansible-galaxy. Cela permet de télécharger des collections depuis diverses sources, que ce soit Ansible Galaxy, un dépôt Git ou même un fichier local. Voici comment gérer ces différentes installations et assurer la mise à jour correcte des collections.

Installation depuis Ansible Galaxy

Pour installer une collection depuis Ansible Galaxy, utilisez la commande suivante :

Terminal window
ansible-galaxy collection install <namespace>.<collection_name>

Par exemple, pour installer la collection cisco.ios :

Terminal window
ansible-galaxy collection install cisco.ios

Cela installe la collection dans le répertoire local des collections par défaut : ~/.ansible/collections/ ou /usr/share/ansible/collections/.

Installation via un fichier requirements.yml

Vous pouvez également spécifier plusieurs collections à installer en les définissant dans un fichier requirements.yml. Ce fichier peut contenir les noms et les versions des collections à installer, ainsi que leurs sources.

Exemple pour installer des collections depuis Ansible Galaxy :

collections:
- name: cisco.ios
version: 1.3.0
- name: community.general
version: 3.4.0

Pour installer les collections définies dans ce fichier, exécutez :

Terminal window
ansible-galaxy collection install -r requirements.yml

Vous pouvez également installer une collection directement depuis un dépôt Git. Cela est utile pour tester des versions en développement ou utiliser des collections hébergées en privé.

Exemple de configuration dans le fichier requirements.yml :

collections:
- name: my_namespace.my_collection
source: https://github.com/my_namespace/my_collection.git
version: main

Ici, la collection est installée depuis le dépôt Git, en ciblant la branche main. Le paramètre version peut également être un commit ou un tag spécifique.

Mise à jour des collections avec --force

Si vous avez besoin de mettre à jour une collection déjà installée ou de forcer sa réinstallation, vous pouvez utiliser le paramètre --force. Cela permet de télécharger et réinstaller la dernière version disponible, écrasant toute version déjà présente.

Terminal window
ansible-galaxy collection install <namespace>.<collection_name> --force

Cela fonctionne également avec l’installation via un fichier requirements.yml :

Terminal window
ansible-galaxy collection install -r requirements.yml --force

Le paramètre --force est particulièrement utile si vous travaillez avec des collections en développement ou si vous avez effectué des modifications locales que vous souhaitez écraser.

Développement de collections Ansible

Le développement de collections Ansible permet de regrouper vos rôles, vos modules, vos plugins et vos autres contenus au sein d’une structure facilement distribuable. Cela facilite non seulement la gestion des dépendances, mais permet aussi de maintenir et partager un contenu cohérent au sein d’une équipe ou d’une organisation.

Prérequis pour le développement

Avant de commencer à développer une collection, il est important de maîtriser d’abord Python, puis de préparer correctement votre environnement de travail. Voici les principales étapes :

  1. Créer le répertoire de base : Les collections doivent être placées dans un répertoire nommé ansible_collections. La structure de répertoires doit respecter un schéma particulier, avec un namespace (espace de noms) et un nom de collection. Par exemple :
Terminal window
mkdir ansible_collections/
cd ansible_collections
  1. Pour initier une nouvelle collection, Ansible fournit la commande ansible-creator. Cette commande crée automatiquement la structure de base d’une collection. Par exemple, pour créer une collection dans le namespace my_namespace avec le nom my_collection, exécutez la commande suivante :
Terminal window
pip install ansible-creator
mkdir -p my_namespace/my_collection
ansible-creator init collection my_namespace.mycollection $PWD/my_namespace/my_collection
Note: collection my_namespace.mycollection created at /Users/srt20/Projets/perso/ansible/ansible_collections/my_namespace/my_collection

Cette commande génère automatiquement la structure de fichiers et de répertoires dont vous avez besoin pour commencer à développer votre collection. Cela inclut le fichier galaxy.yml, un fichier README.md, ainsi que les répertoires roles/, plugins/, tests/ et autres, qui sont vides à l’initialisation.

  • Répertoire.devcontainer/
    • devcontainer.json
    • Répertoiredocker/
      • devcontainer.json
    • Répertoirepodman/
      • devcontainer.json
  • Répertoire.github/
    • Répertoireworkflows/
      • release.yml
      • tests.yml
  • .gitignore
  • .isort.cfg
  • .pre-commit-config.yaml
  • .prettierignore
  • Répertoire.vscode/
    • extensions.json
  • CHANGELOG.rst
  • CODE_OF_CONDUCT.md
  • CONTRIBUTING
  • LICENSE
  • MAINTAINERS
  • README.md
  • Répertoirechangelogs/
    • config.yaml
  • devfile.yaml
  • Répertoiredocs/
    • .keep
    • Répertoiredocsite/
      • links.yml
  • Répertoireextensions/
    • Répertoireeda/
      • Répertoirerulebooks/
        • rulebook.yml
    • Répertoiremolecule/
      • Répertoireintegration_hello_world/
        • molecule.yml
      • Répertoireutils/
        • Répertoireplaybooks/
          • converge.yml
          • noop.yml
        • Répertoirevars/
          • vars.yml
  • galaxy.yml
  • Répertoiremeta/
    • runtime.yml
  • Répertoireplugins/
    • Répertoireaction/
      • init .py
    • Répertoirecache/
      • init .py
    • Répertoirefilter/
      • init .py
      • hello_world.py
    • Répertoireinventory/
      • init .py
    • Répertoiremodule_utils/
      • init .py
    • Répertoiremodules/
      • init .py
    • Répertoireplugin_utils/
      • init .py
    • Répertoiresub_plugins/
      • init .py
    • Répertoiretest/
      • init .py
  • pyproject.toml
  • requirements.txt
  • Répertoireroles/
    • Répertoirerun/
      • README.md
      • Répertoiredefaults/
        • main.yml
      • Répertoirefiles/
        • .keep
      • Répertoirehandlers/
        • main.yml
      • Répertoiremeta/
        • main.yml
      • Répertoiretasks/
        • main.yml
      • Répertoiretemplates/
        • .keep
      • Répertoiretests/
        • inventory
      • Répertoirevars/
        • main.yml
  • test-requirements.txt
  • Répertoiretests/
    • .gitignore
    • Répertoireintegration/
      • init .py
      • Répertoiretargets/
        • Répertoirehello_world/
          • Répertoiretasks/
            • main.yml
      • test_integration.py
    • Répertoireunit/
      • .keep
      • init .py
      • test_basic.py
  • tox-ansible.ini

Quelques explications sur cette arborescence

Cette arborescence représente la structure d’un projet Ansible complexe, destiné à être partagé et collaboratif, intégrant des outils de développement avancés pour le test, la documentation et la gestion de plugins. Voici une explication détaillée du contenu de chaque répertoire et fichier :

  • .devcontainer/
    • devcontainer.json : Ce fichier configure un environnement de développement dans un container Docker ou Podman. Il est utilisé pour définir l’environnement nécessaire pour travailler sur le projet Ansible, garantissant que chaque développeur a un environnement cohérent.
  • .vscode/
    • extensions.json : Liste des extensions recommandées pour l’éditeur Visual Studio Code, garantissant un environnement de développement optimal pour ce projet.
  • .github/
    • workflows/ : Contient des workflows GitHub Actions automatisés.
      • release.yml : Définit des actions pour gérer la publication de nouvelles versions de la collection.
      • tests.yml : Workflow pour exécuter des tests automatisés sur la collection, probablement avec des tests d’intégration et de validation.
  • Fichiers de configuration
    • .gitignore : Liste des fichiers et répertoires à exclure du contrôle de version Git.
    • .isort.cfg : Configuration pour l’outil isort, utilisé pour trier et organiser les imports dans les fichiers Python.
    • .pre-commit-config.yaml : Configuration pour l’outil pre-commit, qui exécute des vérifications automatiques avant chaque commit, comme le formatage de code ou l’exécution de tests.
    • .prettierignore : Définit les fichiers à ignorer pour l’outil Prettier, utilisé pour formater le code.
  • Fichiers standards de projet open source
  • CHANGELOG.rst : Journal des modifications de la collection, détaillant les évolutions à chaque version.
  • CODE_OF_CONDUCT.md : Charte de conduite à suivre pour les contributeurs.
  • CONTRIBUTING : Instructions pour contribuer au projet.
  • LICENSE : Le fichier de licence, spécifiant les droits d’utilisation.
  • MAINTAINERS : Liste des mainteneurs responsables de la collection.
  • README.md : Présentation générale de la collection et instructions d’utilisation.
  • changelogs/
    • config.yaml : Configuration des changelogs, probablement pour un outil automatisé de génération de journaux de modifications.
  • devfile.yaml
    • Utilisé pour définir l’environnement de développement pour les IDE compatibles avec les devfiles, comme Eclipse Che.
  • docs/
    • .keep : Un fichier vide qui permet de garder un répertoire vide dans Git.
    • docsite/links.yml : Contient des liens utilisés dans la documentation générée du projet, facilitant la navigation entre les sections.
  • extensions/
    • eda/ : Contient des règles EDA (Event-Driven Ansible).
      • rulebooks/ : Les playbooks qui répondent à des événements dans le cadre d’EDA.
    • molecule/ : Contient des tests pour le rôle integration_hello_world avec le framework de test Molecule.
      • playbooks/ : Contient les playbooks de test.
      • vars/ : Définit les variables pour les tests.
  • galaxy.yml : Ce fichier contient les métadonnées de la collection Ansible, comme son nom, son namespace, ses dépendances et sa version, requis pour la publication sur Ansible Galaxy.
  • meta/
    • runtime.yml : Définit la version minimale d’Ansible requise et la compatibilité avec d’autres collections.
  • plugins/ : Ce répertoire contient divers plugins Ansible développés pour la collection :
    • action/ : Contient les plugins d’action, utilisés pour modifier ou personnaliser le comportement des tâches Ansible.
    • cache/ : Plugins de mise en cache, par exemple pour les faits.
    • filter/ : Plugins de filtres jinja, comme hello_world.py.
    • inventory/ : Plugins d’inventaire dynamique.
    • module_utils/ : Des utilitaires pour les modules, généralement des bibliothèques de code partagées entre plusieurs modules.
    • modules/ : Contient les modules Ansible développés pour la collection.
    • plugin_utils/ : Utilitaires partagés entre les plugins.
    • sub_plugins/ : Sous-plugins utilisés par d’autres plugins.
    • test/ : Plugins de test.
  • pyproject.toml : Fichier de configuration pour les outils Python comme Poetry, Flake8, ou Black, gérant les dépendances et la configuration du projet Python.
  • requirements.txt : Contient la liste des dépendances Python nécessaires au bon fonctionnement du projet.
  • roles/
    • run/ : Un exemple de rôle Ansible, avec tous les composants habituels d’un rôle (tasks, handlers, vars etc.).
      • tests/ : Contient l’inventaire utilisé pour les tests du rôle.
  • test-requirements.txt : Fichier listant les dépendances spécifiques nécessaires pour exécuter les tests du projet.
  • tests/
    • integration/ : Tests d’intégration, validant que les différents composants fonctionnent ensemble.
      • hello_world/ : Un scénario de test d’intégration spécifique.
    • unit/ : Tests unitaires pour valider les plus petites unités de code, comme les modules et plugins.
  • tox-ansible.ini : Fichier de configuration pour Tox, un outil de gestion d’environnements de test, souvent utilisé pour automatiser les tests Ansible.

Cette structure reflète un projet Ansible bien organisé et standardisé, avec des outils de test, de développement en container et des conventions de contribution.

Compléter les principaux fichiers

Le fichier galaxy.yml

---
# This collection is initialized by https://github.com/ansible/ansible-creator 24.9.0
# See https://docs.ansible.com/ansible/latest/dev_guide/collections_galaxy_meta.html
namespace: "my_namespace"
name: "my_collection"
version: 1.0.0
readme: README.md
authors:
- your name <example@domain.com>
description: your collection description
license_file: LICENSE
# TO-DO: update the tags based on your content type
tags: ["linux", "tools"]
dependencies: {}
repository: http://example.com/repository
documentation: http://docs.example.com
homepage: http://example.com
issues: http://example.com/issue/tracker
# A list of file glob-like patterns used to filter any files or directories that should not be included in the build
# artifact. A pattern is matched from the relative path of the file or directory of the collection directory. This
# uses 'fnmatch' to match the files or directories. Some directories and files like 'galaxy.yml', '*.pyc', '*.retry',
# and '.git' are always filtered. Mutually exclusive with 'manifest'
build_ignore:
- .gitignore
- changelogs/.plugin-cache.yaml
# A dict controlling use of manifest directives used in building the collection artifact. The key 'directives' is a
# list of MANIFEST.in style
# L(directives,https://packaging.python.org/en/latest/guides/using-manifest-in/#manifest-in-commands). The key
# 'omit_default_directives' is a boolean that controls whether the default directives are used. Mutually exclusive
# with 'build_ignore'
# manifest: null

Ce fichier est un exemple de fichier galaxy.yml, qui contient les métadonnées essentielles d’une collection Ansible. Il est utilisé pour définir la collection et permet de la publier sur Ansible Galaxy ou d’autres plateformes. Voici une explication de chaque section du fichier :

  • namespace : Définit l’espace de noms (namespace) dans lequel la collection sera placée. C’est une manière d’organiser les collections par éditeur ou organisation. Ici, il est défini comme "my_namespace".
  • name : Le nom de la collection, ici "my_collection". Le nom complet de la collection sera donc my_namespace.my_collection.
  • version : Indique la version actuelle de la collection, ici définie comme 1.0.0. Cela suit le format de versionnement sémantique (semver), ce qui est recommandé pour assurer la gestion des mises à jour.
  • readme : Le chemin vers le fichier README.md qui contient la description détaillée de la collection, comment l’utiliser et quelles sont ses fonctionnalités.
  • authors : Liste des auteurs ou contributeurs de la collection. L’exemple ici indique un placeholder avec your name <example@domain.com>, qui doit être remplacé par les informations réelles.
  • description : Un résumé rapide de la collection. Ce champ est utilisé pour décrire brièvement le but ou le contenu de la collection. Ici, il est indiqué comme "your collection description", qui doit être remplacé par une description pertinente.
  • license_file : Ce champ fait référence au fichier contenant la licence sous laquelle la collection est distribuée, ici LICENSE. Il est important de spécifier les droits et restrictions pour les utilisateurs de la collection.
  • tags : Une liste de mots-clés associés à la collection, ici ["linux", "tools"]. Les tags aident les utilisateurs à rechercher et découvrir la collection en fonction de critères pertinents (par exemple, la plateforme ou le type d’outils inclus dans la collection).
  • dependencies : Ce champ liste les dépendances avec d’autres collections Ansible. Ici, {} indique qu’il n’y a pas de dépendances pour le moment. Si la collection devait dépendre d’autres collections (comme community.general), elles seraient spécifiées ici.
  • repository : L’URL du dépôt Git où le code source de la collection est maintenu. Ce champ permet aux utilisateurs d’accéder directement au dépôt pour cloner ou consulter le code.
  • documentation : Le lien vers la documentation officielle de la collection, si elle est hébergée ailleurs.
  • homepage : L’URL de la page d’accueil ou du site principal du projet.
  • issues : Le lien vers le gestionnaire de tickets ou de bugs, permettant aux utilisateurs de signaler des problèmes ou des améliorations.
  • build_ignore : Ce champ contient une liste de fichiers et de répertoires à ignorer lors de la création de l’artefact de la collection (le package final distribué). Par exemple, .gitignore et changelogs/.plugin-cache.yaml sont exclus pour ne pas être inclus dans le package final.
  • manifest : Une alternative à build_ignore qui utilise un fichier MANIFEST.in pour contrôler les fichiers à inclure ou exclure lors de la création de la collection. Ici, il est défini comme null, indiquant qu’il n’est pas utilisé dans cette configuration.

Le fichier meta/runtime.yml

---
requires_ansible: ">=2.15.0"

Le paramètre requires_ansible: ”>=2.15.0” spécifie la version minimale d’Ansible requise pour utiliser la collection. Dans ce cas, la collection nécessite qu’Ansible version 2.15.0 ou supérieure soit installée pour pouvoir fonctionner correctement.

Si un utilisateur tente d’utiliser cette collection avec une version d’Ansible inférieure à 2.15.0, il recevra probablement un message d’erreur indiquant une incompatibilité de version.

Le fichier requirements.txt

Le fichier requirements.txt contient les bibliothèques Python nécessaires au bon fonctionnement de la collection Ansible, à l’exception d’Ansible lui-même, qui n’est pas inclus pour éviter des conflits avec différentes versions d’Ansible installées par les utilisateurs. Ce fichier est utilisé pour installer les dépendances avec la commande pip install -r requirements.txt.

Ajout de contenu à la collection

Une collection Ansible est conçue pour être un conteneur modulaire regroupant différents éléments tels que les rôles, plugins, modules et inventaires. Ces éléments doivent être organisés de manière à respecter une structure de répertoires précise, ce qui permet de maintenir la collection propre, compatible avec Ansible et prête à être partagée sur des plateformes comme Ansible Galaxy.

Les rôles

Les rôles doivent être placés dans le répertoire roles/ de la collection. Un rôle est un ensemble de tâches, handlers, variables, fichiers et modèles, structuré de manière modulaire pour exécuter des actions spécifiques.

Chaque rôle suit cette structure avec un répertoire pour chaque type d’élément. Les rôles permettent de séparer les tâches d’automatisation pour les rendre réutilisables et modulaires. Plus d’explications sur les rôles Ansible

Les plugins

Les plugins Ansible permettent d’ajouter des fonctionnalités supplémentaires à Ansible, comme des filtres jinja, des modules utilitaires ou des plugins d’actions. Ils doivent être placés dans le répertoire plugins/ de la collection.

Les plugins sont divisés en plusieurs sous-catégories, selon leur type. Par exemple :

  • plugins/modules/ : Ce répertoire contient les modules personnalisés. Les modules sont des scripts ou programmes exécutés par Ansible pour accomplir des tâches spécifiques.

  • plugins/module_utils/ : Ce répertoire est dédié aux utilitaires de modules. Ce sont des bibliothèques de code réutilisable que d’autres modules peuvent importer pour faciliter des tâches complexes, comme la gestion des API ou des formats de données spécifiques.

  • plugins/filters/ : Ce répertoire contient les filtres jinja. Les filtres sont utilisés dans les templates pour transformer les données, par exemple pour formater une chaîne de caractères ou manipuler une liste.

  • plugins/callbacks/ : Ce répertoire héberge les plugins de callback, qui permettent de modifier la sortie des exécutions de playbooks ou de capturer et d’enregistrer des informations sur l’exécution de ces derniers.

  • plugins/inventory/ : Les plugins d’inventaire se trouvent ici. Ils permettent de définir dynamiquement l’inventaire d’hôtes à partir de sources externes comme des bases de données, des services cloud ou des fichiers.

  • plugins/actions/ : Ce répertoire contient les plugins d’actions. Ces plugins permettent d’exécuter des actions personnalisées avant ou après les tâches Ansible, comme la modification du comportement par défaut d’Ansible lorsqu’il exécute une tâche.

Cela permet à Ansible de charger et d’utiliser automatiquement les plugins de la collection dans vos playbooks et rôles. Plus d’explications sur les plugins Ansible (en cours de réécriture)

Les modules

Les modules sont un type particulier de plugin qui exécute des tâches spécifiques. Les modules personnalisés doivent être placés sous plugins/modules/ dans la collection.

Les modules peuvent être écrits en Python ou dans d’autres langages et Ansible les exécutera pour effectuer des tâches comme la gestion de configurations, l’interaction avec des API ou l’exécution de commandes sur des hôtes. Plus d’explications sur les modules Ansible

Les modules d’inventaires

Les inventaires (inventories) dans Ansible définissent les hôtes et groupes d’hôtes sur lesquels les tâches seront exécutées. Si vous souhaitez inclure un inventaire dans une collection, il doit être placé dans le répertoire inventory/ de la collection. Cela permet de gérer des inventaires statiques ou dynamiques de manière organisée.

Cela permet aux utilisateurs de la collection de définir des groupes d’hôtes ou de gérer dynamiquement leur infrastructure. Plus d’infos sur les inventaires

Ajouter des tests à notre collection

Depuis la version 2.9 d’Ansible, Ansible est livré avec un utilitaire se nommant ansible-test. Cet utilitaire permet d’ajouter des tests à vos collections qui peuvent être :

  • des tests unitaires sur vos propres développements de modules et de plugins (ils doivent intégrer des tests au format unittest ou pytest) units
  • des tests d’intégration integration
  • des tests syntaxique sanity

Les tests syntaxiques

Ces premiers tests ne nécessitent aucune action de notre part. Lançons les tests :

Terminal window
ansible-test sanity --docker
...
Bootstrapping Python 3.12 at: /usr/bin/python3.12
Running sanity test "action-plugin-docs"
Running sanity test "ansible-doc"
Running sanity test "changelog"
Running sanity test "compile" on Python 3.7
Running sanity test "compile" on Python 3.8
Running sanity test "compile" on Python 3.9
Running sanity test "compile" on Python 3.10
Running sanity test "compile" on Python 3.11
Running sanity test "compile" on Python 3.12
Running sanity test "empty-init"
Running sanity test "ignores"
Running sanity test "import" on Python 3.7
Running sanity test "import" on Python 3.8
Running sanity test "import" on Python 3.9
Running sanity test "import" on Python 3.10
Running sanity test "import" on Python 3.11
Running sanity test "import" on Python 3.12
Running sanity test "line-endings"
Running sanity test "no-assert"
Running sanity test "no-get-exception"
Running sanity test "no-illegal-filenames"
Running sanity test "no-smart-quotes"
Running sanity test "pep8"
ERROR: Found 1 pep8 issue(s) which need to be resolved:
ERROR: plugins/modules/apilogs_infos.py:224:161: E501: line too long (328 > 160 characters)
See documentation for help: https://docs.ansible.com/ansible-core/2.17/dev_guide/testing/sanity/pep8.html
Running sanity test "pslint"
Running sanity test "pylint"
Running sanity test "replace-urlopen"
Running sanity test "runtime-metadata"
Running sanity test "shebang"
Running sanity test "shellcheck"
Running sanity test "symlinks"
Running sanity test "use-argspec-type-path"
Running sanity test "use-compat-six"
Running sanity test "validate-modules"
Running sanity test "yamllint"
FATAL: The 1 sanity test(s) listed below (out of 34) failed. See error output above for details.
pep8

Reste plus qu’à corriger et à relancer.

Pour retrouver la liste des tests actifs (33) :

Terminal window
ansible-test sanity --list-tests
action-plugin-docs
ansible-doc
changelog
compile
empty-init
ignores
import
line-endings
no-assert
no-get-exception
no-illegal-filenames
no-smart-quotes
pep8
pslint
pylint
replace-urlopen
runtime-metadata
shebang
shellcheck
symlinks
use-argspec-type-path
use-compat-six
validate-modules
yamllint

Les tests unitaires

Prenons l’exemple du développement d’un plugin de filtre Ansible. Il faut écrire le plugin de filtre dans le répertoire plugins/filter_plugins/ de la collection.

└── tests
└── unit
└── plugins
└── filter
└── test_snaketocamel.py

Reprenons l’exemple du filtre du billet dédié à ce sujet.

from ansible.errors import AnsibleError
import re
try:
import six
HAS_LIB = True
except ImportError:
HAS_LIB = False
def snake_to_camel(text, suffix=''):
if not HAS_LIB:
raise AnsibleError('You need to install "six" prior to running '
'snaketocamel filter')
import re
return suffix + ''.join(x.title() or '_' for x in text.split('_'))
class FilterModule(object):
def filters(self):
return {
'snaketocamel': snake_to_camel
}

Dans le répertoire de la collection ajouter un répertoire tests/unit/plugins/filter et déposez-y ce fichier test_snaketocamel.py:

import unittest
from ansible_collections.steph.test.plugins.filter_plugins.snaketocamel import snake_to_camel
class TestMyFilter(unittest.TestCase):
def test_snaketocamel(self):
self.assertEqual(snake_to_camel("une_variable"), 'UneVariable')

Maintenant, il suffit de lancer ansible-test depuis le répertoire de la collection :

Terminal window
ansible-test unit --docker

Les tests d’intégration

Les tests d’intégration sont écrits sous la forme de rôles Ansible.

Dans le répertoire tests, il faut créer la structure suivante integration/targets/premierrole/tasks dans le répertoire tests de la collection.

└── tests
├── integration
│ └── targets
│ └── premierrole
│ └── tasks
│ └── main.yml

Ajoutons simplement l’import du rôle premierrole :

- ansible.builtin.import_role:
name: stephane.test_collection.premierrole

Lançons le test d’intégration :

Terminal window
ansible-test integration --docker
PLAY [testhost] ****************************************************************
TASK [Gathering Facts] *********************************************************
ok: [testhost]
TASK [steph.test.premierrole : Debug test.] ************************************
ok: [testhost] => {
"msg": "Mon premier role"
}
PLAY RECAP *********************************************************************
testhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

On peut donc désormais valider notre collection sans installer quoique ce soit, mis à part docker, avec ansible-test. On peut aussi lancer des tests sur un environnement cloud.

Build de notre collection Ansible

Cela se fait assez simplement. Depuis le répertoire de votre collection tapez la commande suivante :

Terminal window
ansible-galaxy collection build
Created collection for stephane.test_collection at /home/vagrant/Projets/perso/stephane/test_collection/stephane-test_collection-1.0.0.tar.gz

Comme pour l’installation, si vous devez reconstruire la collection il faudra utiliser l’option --force.

Utilisons notre collection Ansible

Créer un autre projet :

Terminal window
mkdir ~/Projets/test
ansible-galaxy collection install /home/vagrant/Projets/perso/stephane/test_collection/stephane-test_collection-1.0.0.tar.gz -p ./collections
[WARNING]: The specified collections path '/home/vagrant/Projets/perso/test/collections' is not part of the configured Ansible collections paths
'/home/vagrant/.ansible/collections:/usr/share/ansible/collections'. The installed collection won't be picked up in an Ansible run.

Comme vous pouvez le lire nous devons indiquer à Ansible ou se trouve notre collection. Pour ça il existe 2 moyens :

  • dans le fichier ansible.cfg dans la section [defaults] en ajoutant le paramètre collections_paths
  • avec la variable d’environnement ANSIBLE_COLLECTIONS_PATHS
Terminal window
ANSIBLE_COLLECTIONS_PATHS=

Créer un simple playbook utilisant votre collection

- hosts: localhost
gather_facts: true
tasks:
- ansible.builtin.import_role:
name: stephane.test_collection.premierrole

Vous remarquez qu’il vous faut indiquer le chemin du rôle dans la collection. Lançons-le :

Terminal window
ansible-playbook -c local playbook.yaml
PLAY [localhost] ***
TASK [Gathering Facts] ***
ok: [localhost]
TASK [stephane.test_collection.premierrole : debug] ***
ok: [localhost] => {
"msg": "OracleLinux"
}
PLAY RECAP ******
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Construction de la documentation

Pour générer la documentation de notre collection Ansible à l’aide de la commande antsibull-docs sphinx-init, suivez ces étapes :

  1. Initialiser la documentation : Utilisez la commande suivante pour générer les fichiers de documentation de base :

    Terminal window
    antsibull-docs sphinx-init --use-current --dest-dir dest my_namespace.my_collection
    • --use-current : Cela permet d’utiliser la version actuelle de votre collection pour la documentation.
    • --dest-dir dest : Définit le répertoire où la documentation sera générée. Dans cet exemple, les fichiers sont placés dans le répertoire dest. Je vous conseille dans le mettre dans un autre dossier que dans le répertoire, pour éviter les problèmes de dépendances python.
    • my_namespace.my_collection : Remplacez cela par le namespace et le nom de votre collection.
  2. Installer les dépendances : Accédez au répertoire dest créé et installez les dépendances nécessaires à la génération de la documentation via Sphinx :

    Terminal window
    pip install -r requirements.txt

    Je vous recommandé de le faire dans un environnement virtuel Python (venv) pour éviter d’affecter les installations globales.

  3. Construire la documentation : Une fois les dépendances installées, exécutez le script build.sh (ou toute autre commande de construction si personnalisée) pour générer la documentation en HTML :

    Terminal window
    ./build.sh
  4. Visualiser la documentation : Ouvrez ensuite le fichier build/html/index.html dans un navigateur pour visualiser la documentation générée.

Cela permet de générer automatiquement une documentation Sphinx complète pour votre collection Ansible, intégrant les rôles, plugins et autres éléments. Vous pouvez personnaliser davantage la documentation en ajoutant du contenu dans les fichiers générés.

Pour plus de détails, vous pouvez consulter la documentation officielle Ansible sur antsibull-docs.

Conclusion

La construction d’une collection Ansible permet de regrouper et d’organiser efficacement des rôles, modules, plugins et autres contenus Ansible dans une structure modulaire et distribuable. Ce guide a détaillé chaque étape essentielle : depuis la configuration initiale de l’environnement et la création de la collection avec ansible-creator, jusqu’à l’organisation des rôles et plugins dans les répertoires appropriés, ainsi que la gestion des dépendances et la documentation via des outils comme antsibull-docs.

En maîtrisant ces pratiques, vous pouvez non seulement structurer vos projets de manière plus efficace, mais aussi les partager facilement via des plateformes comme Ansible Galaxy, garantissant une réutilisabilité et une maintenabilité optimales. Que ce soit pour des projets internes ou communautaires, la bonne gestion des collections assure une automatisation fluide et évolutive, tout en facilitant la collaboration au sein des équipes.

L’adoption de ces bonnes pratiques pour développer et documenter vos collections Ansible vous permettra de bénéficier d’une plus grande flexibilité, de meilleures performances et d’une plus grande simplicité dans la gestion des versions et des dépendances.