Aller au contenu

Développement de modules Ansible

Mise à jour :

logo ansible

Au cœur du fonctionnement d’Ansible se trouvent les modules, qui sont les unités fondamentales d’exécution. Ces modules sont des scripts autonomes qui effectuent des actions spécifiques sur les systèmes cibles, comme gérer des packages, des utilisateurs ou des services. La bibliothèque de modules incluse avec Ansible couvre une large gamme de fonctionnalités, mais il arrive que dans certains cas spécifiques, un module personnalisé soit nécessaire.

Développer un module personnalisé permet d’adapter Ansible à des besoins très spécifiques, par exemple pour interagir avec une API propriétaire ou pour gérer des services internes. Ces modules offrent une grande flexibilité et bien qu’Ansible en inclue déjà plusieurs centaines par défaut, créer son propre module donne un contrôle total sur la manière dont certaines actions sont exécutées dans l’infrastructure.

Prérequis pour commencer à développer un module Ansible

Avant de plonger dans le développement de modules Ansible, il est essentiel de maîtriser Python, puis de s’assurer que votre environnement est correctement configuré. Cette section décrit les prérequis et les outils nécessaires pour débuter, de l’installation des composants requis à la configuration d’un environnement de développement adapté.

Installation de Python

Les modules Ansible sont généralement développés en Python, qui est un langage simple et largement utilisé dans la communauté Ansible. Par conséquent, il est indispensable d’avoir Python 3.x installé sur votre machine.

Vous pouvez vérifier si Python est installé en exécutant cette commande dans votre terminal :

Terminal window
python3 --version

Si Python n’est pas installé, vous pouvez aller jetter un œil sur ma documentation Python

Installation d’Ansible

Pour commencer le développement, vous aurez évidemment besoin d’Ansible. Si Ansible n’est pas encore installé, vous pouvez l’installer facilement via pip. Voici la commande pour installer Ansible avec pip :

Terminal window
pip install ansible --user

Pour vérifier que l’installation s’est bien déroulée, exécutez la commande suivante :

Terminal window
ansible --version

Vous pouvez utiliser aussi un environnement virtuel.

Configuration de l’environnement de développement (IDE)

Bien que vous puissiez utiliser n’importe quel éditeur de texte pour développer un module Ansible, il est recommandé d’utiliser un IDE (environnement de développement intégré) qui facilite la gestion du code, offre des fonctionnalités comme l’autocomplétion et la coloration syntaxique et intègre des outils de débogage. Voici quelques IDE populaires que vous pouvez utiliser pour développer des modules Ansible :

  • Visual Studio Code (VS Code) : Un IDE open source très populaire, compatible avec de nombreux langages. Vous pouvez y ajouter des extensions Ansible et Python pour améliorer votre expérience de développement. Plus d’infos
  • PyCharm : Un IDE puissant pour Python, idéal pour le développement de modules Ansible. PyCharm offre de nombreuses fonctionnalités telles que l’autocomplétion et l’intégration Git.
  • Sublime Text : Un éditeur de texte léger avec des fonctionnalités de base, mais efficaces, adapté à ceux qui préfèrent la simplicité.

Quelle que soit votre préférence, assurez-vous d’avoir un environnement avec lequel vous pouvez facilement organiser votre code, gérer des projets Python et effectuer des tests.

Tests et Débogage

Le développement d’un module Ansible nécessite également la capacité de tester et déboguer vos modules. Cela peut se faire en utilisant l’outil ansible-test. Cet outil vous permet d’exécuter des tests sur votre module pour vous assurer qu’il fonctionne correctement dans différents scénarios. Je reviendrai plus en détail sur cet aspect dans une section ultérieure du guide, mais il est bon d’avoir déjà un environnement de test prêt.

Mise en place d’un projet de module Ansible (avec ansible.cfg)

Une fois que votre environnement est prêt, la première étape consiste à organiser correctement votre projet pour le développement de votre module Ansible. Au lieu de placer vos modules dans le répertoire library/, ce qui peut poser un problème sur macOS, vous pouvez spécifier un chemin personnalisé en utilisant un fichier de configuration ansible.cfg.

Voici les étapes à suivre pour configurer votre environnement de manière efficace en utilisant un répertoire personnalisé pour vos modules.

Créez un répertoire pour vos modules

Dans le répertoire de votre projet Ansible (où se trouve votre playbook), créez un répertoire spécifique pour vos modules, par exemple custom_modules. Cela vous permet de séparer clairement vos modules du reste du projet :

Terminal window
mkdir custom_modules

Placer votre module dans le répertoire

Déplacez ou créez votre module personnalisé dans ce répertoire. Par exemple, si vous développez un module appelé my_custom_module.py, il devrait être placé dans le dossier custom_modules comme ceci :

Terminal window
custom_modules/my_custom_module.py

Configurer ansible.cfg

Dans le même répertoire que votre playbook, créez un fichier ansible.cfg (ou modifiez-le si vous en avez déjà un). Ce fichier permettra à Ansible de savoir où chercher les modules personnalisés.

Voici le contenu à ajouter dans ansible.cfg pour spécifier le chemin vers votre répertoire custom_modules :

[defaults]
library = ./custom_modules

Cela dit à Ansible d’ajouter le répertoire custom_modules/ à la liste des répertoires dans lesquels il recherche les modules.

Structure de votre projet

Votre projet Ansible doit maintenant ressembler à cette structure :

.
├── ansible.cfg
├── playbook.yaml
└── custom_modules/
└── my_custom_module.py
  • ansible.cfg : Contient la configuration pour indiquer à Ansible où chercher les modules personnalisés.
  • playbook.yaml : Votre playbook principal qui utilise le module personnalisé.
  • custom_modules/ : Le dossier où sont stockés vos modules personnalisés.

Les différents blocs composants notre module Ansible

Voici un exemple simple d’un module Ansible personnalisé qui illustre les blocs essentiels d’un module. Ce module s’appelle my_custom_module et il retourne un message de salutation en fonction du nom fourni. Chaque partie sera ensuite expliquée si besoin.

Le Shebang et le codage UTF-8

Ce bloc indique à l’interpréteur Python comment exécuter le script et utilise l’encodage UTF-8 pour garantir que les caractères spéciaux sont traités correctement.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

Le bloc de compatibilité python3

Ces directives assurent la compatibilité avec les anciennes versions de Python (notamment Python 2). Cela garantit que les imports fonctionnent correctement, et que le comportement des divisions et des fonctions soit celui de Python 3, même si le module est exécuté dans un environnement Python 2.

from __future__ import absolute_import, division, print_function
__metaclass__ = type

Ce bloc décrit le copyright et la licence sous laquelle le module est distribué.

# (c) 2024, Your Name <your.email@example.com>
# GNU General Public License v3.0+

Le bloc DOCUMENTATION

Le bloc de documentation fournit une description du module, les options disponibles, les types de données et les valeurs par défaut, ainsi que des informations sur l’auteur.

DOCUMENTATION = r'''
---
module: my_custom_module
short_description: Un module qui retourne un message de salutation.
description:
- Ce module permet de retourner un message personnalisé en fonction du nom fourni.
options:
name:
description:
- Le nom de la personne à saluer.
required: true
type: str
author:
- Your Name (@yourgithub)
'''

Le bloc EXAMPLES

Ce bloc donne des exemples d’utilisation du module dans un playbook Ansible.

EXAMPLES = r'''
# Exécuter le module avec le nom "Alice"
- name: Utiliser my_custom_module
my_custom_module:
name: Alice
'''

Le bloc RETURN

Le bloc RETURN décrit les valeurs renvoyées par le module après son exécution.

RETURN = r'''
greet:
description: Message de salutation retourné par le module.
type: str
returned: always
sample: 'Hello, Alice'
'''

Les Imports Python

Ce bloc importe les bibliothèques Python nécessaires pour faire fonctionner le module. Ici, on utilise AnsibleModule de la bibliothèque ansible.module_utils.basic pour gérer les paramètres et la sortie.

from ansible.module_utils.basic import AnsibleModule

La Fonction principale du module

La fonction principale gère la logique du module. Ici, elle prend en entrée le paramètre name et retourne un message de salutation.

def run_module():
module_args = dict(
name=dict(type='str', required=True)
)
module = AnsibleModule(
argument_spec=module_args,
supports_check_mode=True
)
name = module.params['name']
result = dict(
changed=False,
greet=f"Hello, {name}"
)
module.exit_json(**result)
def main():
run_module()
if __name__ == '__main__':
main()
  • Le module accepte un seul argument name, qui est requis.
  • La fonction run_module() définit les arguments, exécute la logique du module et retourne un message personnalisé sous la forme “Hello, {name}”.
  • Le module ne change pas l’état du système, donc changed est défini sur False.
  • Enfin, le module utilise module.exit_json() pour renvoyer les résultats à Ansible.

Exécution du playbook

Lorsque vous exécutez votre playbook, Ansible va maintenant automatiquement chercher les modules dans le répertoire custom_modules, grâce à la configuration dans ansible.cfg. Assurez-vous simplement que votre playbook fait référence à votre module correctement :

- name: Test my cuctom modules
hosts: localhost
gather_facts: false
tasks:
- name: Test du module personnalisé
my_custom_module:
name: "Bob"
register: retour
- name: Debug
ansible.builtin.debug:
var: retour

Pour lancer le playbook, exécutez cette commande :

Terminal window
ansible-playbook test-playbook.yaml -c local -i localhost,

Vous devriez obtenir ce résultat :

Terminal window
PLAY [Test my cuctom modules] ********
TASK [Test du module personnalisé] *******
ok: [localhost]
TASK [Debug] *****
ok: [localhost] => {
"retour": {
"changed": false,
"failed": false,
"greet": "Hello, Bob"
}
}
PLAY RECAP *******************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Explications sur le bloc DOCUMENTATION

Le bloc DOCUMENTATION dans un module Ansible est essentiel, car il permet de documenter le fonctionnement du module de manière claire et précise. Il suit une structure en YAML et fournit des informations détaillées sur les options, la description, les exemples d’utilisation et l’auteur du module. Ce bloc permet aux utilisateurs de comprendre comment utiliser le module sans avoir besoin de lire le code source.

Structure du bloc DOCUMENTATION

Voici un exemple typique de bloc DOCUMENTATION :

DOCUMENTATION = '''
---
module: my_custom_module
short_description: Un module qui retourne un message de salutation.
description:
- Ce module permet de retourner un message personnalisé en fonction du nom fourni.
- Il peut être utilisé pour des tests simples ou pour des scripts de démonstration.
options:
name:
description:
- Le nom de la personne à saluer.
required: true
type: str
author:
- Your Name (@yourgithub)
'''

Voyons plus en détail les différents éléments qui composent ce bloc.

Le champ module

Le champ module indique le nom du module. Ce nom doit correspondre au fichier du module sans l’extension .py. Par exemple, si le module s’appelle my_custom_module.py, le nom du module dans la documentation doit être my_custom_module.

Le champ short_description

Le champ short_description donne une brève description du module (généralement une seule ligne). Cette description est utilisée dans la documentation générée par Ansible et doit résumer l’objectif principal du module.

Exemple :

short_description: Un module qui retourne un message de salutation.

Le champ description

Le champ description fournit une description détaillée du module. Ce champ peut contenir plusieurs lignes expliquant ce que fait le module, à quoi il sert et dans quels contextes il peut être utilisé. C’est ici que tu donnes une vue d’ensemble du fonctionnement du module.

Exemple :

description:
- Ce module permet de retourner un message personnalisé en fonction du nom fourni.
- Il peut être utilisé pour des tests simples ou pour des scripts de démonstration.

Le champ options

Le champ options est probablement le plus important, car il décrit les paramètres (ou arguments) que le module accepte. Chaque option a plusieurs sous-champs :

  • description : Donne une explication sur le rôle de l’option.
  • required : Indique si l’option est obligatoire ou facultative (true ou false).
  • type : Définit le type de l’option parmi: str, int, bool, dict, list et float.

Exemple d’option :

options:
name:
description:
- Le nom de la personne à saluer.
required: true
type: str

Dans cet exemple, l’option name est un paramètre obligatoire (required: true), qui doit être de type str (chaîne de caractères).

Comprendre les types dans le bloc options

Lors de la définition des options dans le bloc DOCUMENTATION d’un module Ansible, il est important de préciser le type de chaque paramètre que le module attend. Ces types permettent à Ansible de valider les entrées de l’utilisateur avant d’exécuter le module. Voici les principaux types que vous pouvez utiliser, avec des explications et des exemples d’utilisation dans un module Ansible.

str (chaîne de caractères)

Le type str représente une chaîne de caractères. Ce type est utilisé lorsque le module attend du texte en entrée. Cela peut être un nom, un chemin de fichier, ou n’importe quelle donnée textuelle.

Exemple :

name:
description:
- Le nom de la personne à saluer.
required: true
type: str

Ici, l’option name doit être une chaîne de caractères. Un exemple de valeur valide serait "Alice".

int (entier)

Le type int représente un nombre entier. Ce type est utilisé pour les paramètres qui doivent être des nombres sans virgule, comme des ports, des quantités ou des identifiants.

Exemple :

timeout:
description:
- Le délai d'attente (en secondes) avant que l’opération ne se termine.
required: false
type: int
default: 30

Ici, l’option timeout doit être un entier, par exemple 30, qui représente un temps en secondes.

bool (booléen)

Le type bool (booléen) représente une valeur vraie ou fausse. Ce type est utilisé lorsque l’option est une simple bascule entre deux états, par exemple activer ou désactiver une fonctionnalité.

Exemple :

enabled:
description:
- Active ou désactive la fonctionnalité.
required: false
type: bool
default: true

Dans cet exemple, l’option enabled est un booléen. Elle peut être true ou false, avec true comme valeur par défaut.

list (liste)

Le type list représente une collection d’éléments. Ce type est utilisé lorsque le module accepte plusieurs valeurs pour une même option. Chaque élément de la liste peut être de n’importe quel type, selon ce que vous spécifiez dans le module.

Exemple :

items:
description:
- Liste des éléments à traiter.
required: true
type: list
elements: str

Dans cet exemple, items doit être une liste de chaînes de caractères. Une valeur valide serait par exemple ["item1", "item2", "item3"].

dict (dictionnaire)

Le type dict représente une collection clé-valeur. Ce type est utilisé lorsque vous avez besoin de structurer plusieurs informations ensemble sous la forme de paires clé-valeur. Chaque clé doit correspondre à un sous-paramètre.

Exemple :

config:
description:
- Un dictionnaire contenant la configuration.
required: true
type: dict
suboptions:
path:
description: Chemin du fichier de configuration.
required: true
type: str
retries:
description: Nombre de tentatives de connexion.
required: false
type: int
default: 3

Dans cet exemple, config est un dictionnaire qui contient deux sous-options : path (une chaîne de caractères) et retries (un entier).

float (nombre à virgule flottante)

Le type float représente un nombre à virgule. Ce type est utilisé lorsque le paramètre attend un nombre décimal, comme une mesure, une précision, ou un ratio.

Exemple :

threshold:
description:
- Le seuil critique à ne pas dépasser.
required: false
type: float
default: 0.75

Dans cet exemple, threshold est un nombre à virgule flottante. Une valeur possible pourrait être 0.75, représentant par exemple un seuil de 75%.

Exemples complet

Voici un exemple plus complet d’un bloc DOCUMENTATION utilisant différents types pour les options :

DOCUMENTATION = '''
---
module: my_complex_module
short_description: Un module complexe avec différents types d'options.
description:
- Ce module illustre l'utilisation de différents types de paramètres dans Ansible.
options:
name:
description:
- Le nom de l'utilisateur à saluer.
required: true
type: str
retries:
description:
- Le nombre de tentatives avant l'échec.
required: false
type: int
default: 3
enabled:
description:
- Active ou désactive la fonctionnalité.
required: false
type: bool
default: true
items:
description:
- Liste des éléments à traiter.
required: false
type: list
elements: str
config:
description:
- Dictionnaire contenant la configuration.
required: false
type: dict
suboptions:
path:
description:
- Chemin vers le fichier de configuration.
required: true
type: str
timeout:
description:
- Délai avant expiration de la connexion.
required: false
type: int
default: 30
threshold:
description:
- Le seuil critique pour l'opération.
required: false
type: float
default: 0.75
author:
- Your Name (@yourgithub)
'''

Cet exemple montre comment utiliser différents types pour définir les options d’un module Ansible, avec des options de type chaîne de caractères (str), entier (int), booléen (bool), liste (list), dictionnaire (dict) et nombre à virgule flottante (float).

Le champ author

Le champ author indique le ou les auteurs du module. Il est recommandé d’inclure le nom et l’adresse e-mail ou le pseudo GitHub de la personne ou des personnes qui ont créé le module.

Exemple :

author:
- Your Name (@yourgithub)

Cela permet de donner crédit à l’auteur et de savoir à qui s’adresser en cas de questions ou de contributions.

Formatage des descriptions

Dans les blocs DOCUMENTATION, EXAMPLE et RETURNS des modules Ansible, il n’est pas possible d’utiliser du Markdown, du reStructuredText (reST), ni des balises HTML échappées pour formater le texte. Cela signifie que vous ne pouvez pas utiliser de mise en forme comme les balises HTML (<b>, <i>) ou les syntaxes courantes de Markdown (**gras**, *italique*).

À la place, Ansible propose des macros spécifiques qui permettent de formater le texte dans la documentation des modules. Ces macros vous permettent de rendre certains éléments plus lisibles et attrayants, tout en respectant les contraintes de format de la documentation Ansible.

Voici les principales macros disponibles :

  1. B() - Texte en gras.
  2. I() - Texte en italique.
  3. U() - Ajouter un lien direct.
  4. R() - Ajouter un lien cliquable avec texte.
  5. M() - Référence à un module Ansible.
  6. P() - Référence à un plugin Ansible.
  7. O() - Option d’un module.
  8. V() - Valeur d’une option.
  9. RV() - Valeur retournée par un module.
  10. E() - Variable d’environnement.
  11. C() - Texte en monospace (code).

Ces macros sont les méthodes standards pour formater la documentation des modules Ansible, assurant ainsi une documentation plus claire, lisible et bien structurée.

Exemple :

DOCUMENTATION = r"""
---
module: my_custom_module
short_description: Un module pour générer un message personnalisé.
description:
- Ce module permet de retourner un message de salutation en fonction de B(name), qui doit être fourni par l'utilisateur.
- Vous pouvez définir l'état du service avec O(state=present) ou O(state=absent).
- Pour plus d'informations, consultez R(la documentation officielle, https://docs.ansible.com/).
- Si l'option B(name) n'est pas définie, la variable d'environnement E(MY_ENV_VAR) sera utilisée à la place.
- Utilisez la commande C(ansible-playbook) pour exécuter un playbook avec ce module.
options:
name:
description:
- Le nom de la personne à saluer.
required: true
type: str
state:
description:
- Définit l'état du service.
required: false
type: str
choices: [present, absent]
author:
- Your Name (@yourgithub)
"""

Explication sur le bloc EXAMPLES

Le bloc EXAMPLES dans un module Ansible fournit des exemples d’utilisation du module à l’intérieur d’un playbook. Ce bloc est important, car il permet aux utilisateurs de comprendre rapidement comment intégrer et utiliser le module dans leurs propres tâches Ansible. Il doit être simple, clair et fournir plusieurs scénarios d’utilisation typiques du module.

Voici un exemple complet basé sur le module complexe que nous avons vu précédemment. Il montre différents cas d’utilisation du module avec des options de types divers.

Exemple de bloc EXAMPLES

EXAMPLES = '''
# Exemple 1 : Utiliser le module avec un nom et les options par défaut
- name: Utiliser my_complex_module avec les options par défaut
my_complex_module:
name: "Alice"
# Exemple 2 : Spécifier un nombre de tentatives (retries) et désactiver la fonctionnalité
- name: Utiliser my_complex_module avec des options personnalisées
my_complex_module:
name: "Bob"
retries: 5
enabled: false
# Exemple 3 : Fournir une liste d'éléments
- name: Utiliser my_complex_module avec une liste d'items
my_complex_module:
name: "Charlie"
items:
- "item1"
- "item2"
- "item3"
# Exemple 4 : Utiliser un dictionnaire de configuration et ajuster le seuil (threshold)
- name: Utiliser my_complex_module avec une configuration personnalisée
my_complex_module:
name: "Diana"
config:
path: "/etc/my_config.conf"
timeout: 60
threshold: 0.85
'''

Meilleures pratiques pour le bloc EXAMPLES

  • Simples et clairs : Les exemples doivent être faciles à lire et montrer comment utiliser les options de base du module.
  • Variés : Inclure des cas d’utilisation basiques ainsi que des scénarios plus complexes avec des combinaisons d’options.
  • Réels : Les exemples doivent correspondre à des cas d’utilisation réels et aider les utilisateurs à voir la valeur ajoutée du module.
  • YAML valide : Assurez-vous que les exemples sont bien formatés en YAML et peuvent être copiés-collés directement dans un playbook.

Le bloc RETURN

Le bloc RETURN dans un module Ansible décrit les données que le module retourne à la fin de son exécution. Il spécifie les informations que le module renvoie à Ansible et à l’utilisateur, notamment le format et le type des données. Cette section est essentielle pour comprendre quelles valeurs sont disponibles après l’exécution du module.

Structure du bloc RETURN

Voici un exemple de bloc RETURN basé sur le module complexe que nous avons vu précédemment, qui renvoie différents types de données en fonction des options fournies.

Exemple de bloc RETURN

RETURN = '''
greet:
description: Message de salutation retourné par le module.
type: str
returned: always
sample: 'Hello, Alice'
attempts:
description: Le nombre de tentatives effectuées avant l'achèvement de l'opération.
type: int
returned: when retries is defined
sample: 5
items_processed:
description:
- Liste des éléments traités par le module.
type: list
elements: str
returned: when items is defined
sample: ['item1', 'item2', 'item3']
config_used:
description:
- Dictionnaire contenant la configuration utilisée lors de l'exécution.
type: dict
returned: when config is defined
sample:
path: "/etc/my_config.conf"
timeout: 60
threshold_reached:
description:
- Indique si le seuil critique a été atteint pendant l'opération.
type: bool
returned: when threshold is defined
sample: true
'''

Explication des champs dans le bloc RETURN

  1. greet :

    • Description : C’est le message de salutation retourné par le module en fonction de l’option name fournie.
    • Type : Il s’agit d’une chaîne de caractères (str).
    • Returned : Ce champ est toujours retourné, indépendamment des autres options.
    • Sample : Exemple de valeur retournée ('Hello, Alice').
  2. attempts :

    • Description : Le nombre de tentatives effectuées avant la fin de l’opération.
    • Type : Entier (int).
    • Returned : Ce champ est retourné uniquement si l’option retries est définie.
    • Sample : Exemple de valeur (5).
  3. items_processed :

    • Description : Liste des éléments traités par le module si une liste d’éléments a été fournie dans l’option items.
    • Type : Liste (list) d’éléments de type str.
    • Returned : Ce champ est retourné uniquement lorsque l’option items est définie.
    • Sample : Exemple de valeur (['item1', 'item2', 'item3']).
  4. config_used :

    • Description : Dictionnaire contenant la configuration utilisée pendant l’exécution du module, lorsque l’option config est fournie.
    • Type : Dictionnaire (dict) avec plusieurs sous-options (path, timeout etc.).
    • Returned : Ce champ est retourné uniquement lorsque l’option config est définie.
    • Sample : Exemple de valeur ({'path': '/etc/my_config.conf', 'timeout': 60}).
  5. threshold_reached :

    • Description : Indique si le seuil critique spécifié par l’option threshold a été atteint pendant l’opération.
    • Type : Booléen (bool), soit true soit false.
    • Returned : Ce champ est retourné uniquement lorsque l’option threshold est définie.
    • Sample : Exemple de valeur (true).

Détails sur les champs du bloc RETURN

  • Description : Chaque champ dans le bloc RETURN doit inclure une description expliquant précisément ce que le module retourne.
  • Type : Le type de la donnée retournée, qui peut être str (chaîne de caractères), int (entier), list (liste), dict (dictionnaire), ou bool (booléen).
  • Returned : Spécifie les conditions dans lesquelles la donnée est retournée. Par exemple, always signifie que la valeur est toujours retournée, tandis que when option_name is defined signifie que la valeur est retournée uniquement si l’option spécifique a été fournie.
  • Sample : Fournit un exemple de la donnée retournée afin que l’utilisateur puisse comprendre à quoi s’attendre.

Bonnes pratiques pour le bloc RETURN

  • Clarté : Chaque retour doit être bien documenté pour que l’utilisateur sache exactement ce qu’il obtient après l’exécution du module.
  • Complet : Tous les retours possibles doivent être couverts, même ceux conditionnels (par exemple, lorsqu’une option spécifique est définie).
  • Exemples : Les exemples (sample) aident les utilisateurs à comprendre le format des retours et à mieux intégrer les données dans leurs playbooks.

Explications sur la Fonction principale du module

La fonction principale d’un module Ansible est le cœur de la logique du module. C’est ici que le module gère les paramètres fournis, exécute les actions nécessaires et retourne les résultats à Ansible. Cette fonction est indispensable, car elle contrôle le comportement du module en fonction des options définies dans le playbook. Nous allons examiner la structure typique de cette fonction en relation avec le premier exemple de module simple.

Exemple de la fonction principale

Voici l’exemple de notre module simple my_custom_module :

from ansible.module_utils.basic import AnsibleModule
def run_module():
# Définition des paramètres acceptés par le module
module_args = dict(
name=dict(type='str', required=True)
)
# Initialisation de l'AnsibleModule avec les paramètres
module = AnsibleModule(
argument_spec=module_args,
supports_check_mode=True
)
# Récupération de la valeur du paramètre 'name'
name = module.params['name']
# Création du message de salutation
result = dict(
changed=False,
greet=f"Hello, {name}"
)
# Renvoi du résultat
module.exit_json(**result)
def main():
run_module()
if __name__ == '__main__':
main()

Structure et éléments de la fonction principale

Le rôle de la fonction run_module()

La fonction run_module() est la fonction principale de ce module. Elle contient la logique du module, gère les entrées fournies par l’utilisateur et renvoie les résultats à Ansible. Voici un décryptage détaillé des différents composants de cette fonction.

Définition des paramètres : module_args

La première étape de la fonction consiste à définir les paramètres acceptés par le module. Ces paramètres sont décrits dans un dictionnaire appelé module_args. Dans cet exemple, le module attend un seul paramètre, name, qui est une chaîne de caractères obligatoire :

module_args = dict(
name=dict(type='str', required=True)
)
  • name : Ce paramètre est défini comme une chaîne de caractères (str) et est obligatoire (required: true). Cela signifie que si l’utilisateur n’inclut pas le paramètre name dans son playbook, Ansible renverra une erreur.

Initialisation de l’AnsibleModule

La fonction AnsibleModule est utilisée pour initialiser le module Ansible et gérer les paramètres, la validation et les erreurs. Cette fonction prend en entrée la définition des paramètres (via argument_spec) et d’autres options comme la prise en charge du mode de contrôle (supports_check_mode).

module = AnsibleModule(
argument_spec=module_args,
supports_check_mode=True
)
  • argument_spec : C’est le dictionnaire des paramètres acceptés par le module, ici défini par module_args.
  • supports_check_mode : Indique si le module supporte le mode de vérification (check mode), où Ansible exécute une simulation de la tâche sans réellement appliquer de changements. Ici, le module supporte le mode de vérification.

Accès aux paramètres fournis par l’utilisateur

Une fois que le module est initialisé, on peut accéder aux paramètres que l’utilisateur a fournis via la variable module.params. Ici, nous récupérons la valeur du paramètre name :

name = module.params['name']

Cela permet de récupérer le nom que l’utilisateur a passé dans le playbook et de l’utiliser dans la suite du traitement du module.

Logique principale du module

La logique principale du module repose sur le traitement du paramètre name pour générer un message de salutation. Le module ne modifie pas le système, donc la valeur changed est définie à False (indiquant qu’aucun changement n’a été fait) :

result = dict(
changed=False,
greet=f"Hello, {name}"
)
  • changed: False : Comme ce module ne modifie aucun état du système, on indique qu’aucun changement n’a été effectué.
  • greet : Le message personnalisé est généré à partir de la valeur de name et le résultat est stocké dans le dictionnaire result.

Retour des résultats : module.exit_json()

Une fois la logique terminée, le module doit retourner les résultats à Ansible. Cela se fait avec la fonction module.exit_json(), qui envoie les résultats au système Ansible sous forme de JSON. Le contenu du dictionnaire result est passé à cette fonction :

module.exit_json(**result)

Ici, nous passons le dictionnaire result avec changed=False et le message de salutation sous la clé greet.

Conclusion

Dans ce guide, nous avons parcouru les étapes essentielles pour développer un module Ansible personnalisé, de la structure de base du module à l’écriture des différents blocs comme DOCUMENTATION, EXAMPLES et RETURN. En suivant ces bonnes pratiques, vous êtes maintenant capable de créer des modules robustes et bien documentés qui répondent à des besoins spécifiques.

La suite naturelle de ce développement consiste à organiser et distribuer vos modules au sein de collections Ansible. Les collections permettent de regrouper des modules, des rôles, des plugins et des playbooks dans un ensemble cohérent et réutilisable, facilitant ainsi leur partage et leur utilisation au sein de grandes infrastructures. Dans le prochain chapitre, nous aborderons en détail la manière de créer et structurer une collection Ansible et comment y intégrer vos modules personnalisés pour une distribution plus flexible et modulaire.

Le développement de collections est une étape clé pour ceux qui souhaitent créer des modules réutilisables et maintenables à grande échelle, tout en assurant une meilleure organisation et gestion des dépendances dans leurs projets Ansible.