Ansible Playbook Grapher

Example de graphe généré par Ansible Playbook Grapher
Table des matières

Ansible Playbook Grapher est un projet open-source écrit en Python qui génère des graphes à partir de playbooks Ansible. Son objectif est d’aider à visualiser les plays, les rôles, les tâches et les handlers d’un ou plusieurs playbooks Ansible. Le graphe généré peut servir de documentation visuelle pour vos projets.

Origine du projet

Nous sommes en fin 2017. Je suis fraîchement diplômé et débutant chez un client en tant que Consultant DevOps, je devais comprendre et améliorer des playbooks assez complexes avec un inventaire composé d’une cinquantaine de serveurs, une vingtaine de rôles et des centaines de tâches appliquées sur des serveurs sur OpenStack.

Comprendre les relations entre les plays, les rôles et les handers étaient un défi assez conséquent avec des centaines de fichiers YAML à ouvrir. C’est dans ce contexte que j’ai créé Ansible Playbook Grapher pour répondre à un besoin personnel avec pour objectif de comprendre assez rapidement la structure des playbooks.

Premières itérations

Dans les premières itérations, j’avais commencé à parcourir les fichiers YAML manuellement et construire un graphe à l’aide de Graphviz. Cependant, cette approche était relativement fastidieuse et sujette aux erreurs vu la taille des playbooks comme vous pouvez facilement l’imaginer…

Pour automatiser ce processus, j’ai écrit un script Python qui analyse les fichiers YAML des playbooks en parcourant les répertoires des projets. Là encore, je me suis heurté très rapidement à la complexité de l’organisation des projets Ansible avec des rôles imbriqués, les includes et imports, la variété des dossiers pouvant contenir les roles, etc. Bref, j’allais me retrouver à recoder une partie assez fastidieuse d’Ansible.

J’ai donc dû changer d’approche et chercher une solution plus robuste pour analyser les playbooks. Ce qui nous amène à la prochaine section.

Utilisation de la librairie Ansible: ansible-core

Plutôt que de tenter de réinventer la roue en écrivant un parseur YAML maison, j’ai décidé d’exploiter les librairies officielles d’Ansible pour analyser les playbooks.

Depuis Ansible 3.0.0 (2021), le projet a été restructuré en deux composants avec des versions indépendantes : ansible-core (le moteur principal, versions 2.10.x, 2.11.x…) et le package ansible (le tout-en-un avec 85+ Collections, versions 3.x, 4.x…). La première version du Grapher utilisait ansible (version 2.9.x) avant de switcher sur ansible-core plus tard.

Pour comprendre comment exploiter efficacement ces librairies, j’ai cloné le dépôt GitHub d’Ansible et analysé le code source pas à pas avec un debugger. L’objectif était de saisir précisément le mécanisme de chargement et d’interprétation des playbooks et des rôles.

Cette exploration du code source m’a révélé plusieurs défis techniques importants:

  • Les contraintes architecturales d’Ansible : Ansible a été conçu initialement pour une utilisation en ligne de commande. De nombreuses fonctionnalités de parsing sont étroitement couplées au parseur d’arguments CLI, ce qui complique leur réutilisation dans un contexte différent.

  • L’utilisation d’APIs internes : Le Grapher s’appuie sur des APIs internes d’Ansible qui ne sont pas officiellement documentées pour un usage externe. Bien qu’il existe probablement des interfaces plus stables, ces APIs internes étaient les seules solutions viables que j’ai identifiées à l’époque pour accéder aux structures de données nécessaires.

  • Les limites de la réplication du comportement : Le Grapher tente de reproduire fidèlement le comportement d’Ansible lors du chargement des playbooks. Toutefois, des différences subtiles peuvent apparaître dans certains cas complexes, notamment avec la gestion des includes et imports conditionnels où le contexte d’exécution réel diffère du contexte d’analyse statique.

Au fil du temps, j’ai réecrit plusieurs parties du code pour améliorer la robustesse et la maintenabilité du projet en séparant la partie purement parsing de la génération du graphe. Ainsi le projet a une structure comme suit:

flowchart LR subgraph INPUT["📥 Input"] PLAYBOOK["Ansible Playbooks
(YAML files)"] ROLES["Roles & Tasks"] CONFIG["Configuration
(inventory, vars)"] end subgraph PARSER["🔍 Parser"] PLAYBOOK_PARSER["PlaybookParser

• Reads YAML files
• Uses Ansible APIs
• Resolves variables
• Follows includes"] end subgraph MODEL["📊 Graph Model"] HIERARCHY["Node Hierarchy

PlaybookNode, PlayNode, RoleNode, TaskNode, BlockNode, HandlerNode"] end subgraph RENDERERS["🎨 Renderers"] GRAPHVIZ["Graphviz

SVG"] MERMAID["Mermaid

Flowchart"] JSON["JSON

Schema"] end subgraph OUTPUT["📤 Output"] SVG_OUT["Interactive SVG
(with JS)"] MMD_OUT["Mermaid Diagram
(for GitHub)"] JSON_OUT["JSON Data
(for analysis)"] end %% Connections INPUT ==> PARSER PARSER ==>|Parses & Builds| MODEL MODEL ==>|Transforms| RENDERERS GRAPHVIZ --> SVG_OUT MERMAID --> MMD_OUT JSON --> JSON_OUT %% Styling classDef inputStyle fill:#e3f2fd,stroke:#1976d2,stroke-width:3px classDef parserStyle fill:#fff3e0,stroke:#f57c00,stroke-width:3px classDef modelStyle fill:#f3e5f5,stroke:#7b1fa2,stroke-width:3px classDef renderStyle fill:#e8f5e9,stroke:#388e3c,stroke-width:3px classDef outputStyle fill:#fce4ec,stroke:#c2185b,stroke-width:3px class INPUT,PLAYBOOK,ROLES,CONFIG inputStyle class PARSER,PLAYBOOK_PARSER parserStyle class MODEL,HIERARCHY modelStyle class RENDERERS,GRAPHVIZ,MERMAID,JSON renderStyle class OUTPUT,SVG_OUT,MMD_OUT,JSON_OUT outputStyle

Cette structure me permet de rajouter de nouveaux renderers facilement, comme le support de Mermaid pour générer des diagrammes compatibles avec GitHub (le diagramme juste en haut est également fait avec Mermaid :-)).

Quelques fonctionnalités clés

Voici quelques fonctionnalités clés d’Ansible Playbook Grapher:

  • Plusieurs sorties sont supportées:
    • SVG: pour un usage intéractif. Le graphe permet d’ouvrir les fichiers sources associés à chaque nœud en double cliquant dessus.
    • Mermaid: pour documentation as code directement sur GithHub et Gitlab.
    • JSON: pour ceux qui veulent faire leur propre rendu avec d’autres outils.
  • Support des includes et imports ainsi que de certaines variables.
  • Support des handlers ainsi que les tâches déclenchées par les handlers.

Voir le projet sur GitHub pour une liste complète des fonctionnalités.

Et maintenant ?

Ansible Playbook Grapher est maintenant un outil assez mature. Même si je n’utilise plus Ansible au quotidien, je continue à maintenir le projet en corrigeant les bugs et en ajoutant de nouvelles fonctionnalités au fur et à mesure que les utilisateurs en font la demande.

Quelques chiffres depuis pepy.tech et GitHub:

Github stars
PyPI Downloads

Mohamed El Mouctar HAIDARA
Mohamed El Mouctar HAIDARA
Senior Platform Engineer