Présentation de Monkeyble: framework de test bout en bout pour Ansible
Monkeyble est un petit framework qui permet de tester de bout en bout vos playbooks Ansible.
Il permet, au niveau des tâches des Playbooks, de:
- 🐵 Vérifier qu'un module a été appelé avec les bons arguments ;
- 🙊 Vérifier le résultat du retour d'un module ;
- 🙈 Vérifier l'état d'exécution d'une tâche (changed, skipped, failed) ;
- 🙉 Simuler (Mock) un module afin de retourner un résultat sans faire appel au vrai module.
Monkeyble est tout particulièrement conçu pour être placé dans une CI/CD afin de détecter les éventuels régressions lors des modifications sur une base de code Ansible 🚀.
Sommaire
Contexte
La stratégie de test décrite dans la documentation officielle de Ansible consiste a exécuter un playbook sur un environnement (un inventaire) de développement qui simule la production et de valider le fonctionnement de celui-ci pour l'exécuter ensuite sur l'environement de production. Cette stratégie fonctionne dans le cadre d'un playbook utilisé pour un déploiement d'un service à un instant T. Les tests sont effectués manuellement en quelque sorte. Une fois le service déployé, en cas de modification sur le code, une exécution devra à nouveau être réalisée sur l'environement de développement avant celui de production et cetera…
Cependant, si vos playbooks sont utilisés en tant que "services" en étant exposés par exemple dans un AWX/Tower ou derrière un catalogue de services comme Squest, en cas de modification sur le code il est préférable de vérifier que le service fonctionne toujours. Un test manuel n'est bien évidemment plus adapté. On préféra donner ce travail à une CI/CD.
Ansible met à disposition de façon native quelques "garde-fous" sous forme de modules à placer dans vos tâches, rôles ou playbook afin d'effectuer des étapes de validation de données tel que "fail", "assert" ou encore le "check mode". Cela n'est pas du test à proprement parler mais il permet d'apporter une forme de vérification avant l'exécution.
Des projets annexes se sont également ajoutés pour compléter l'offre. Le plus connu étant Molecule, ce dernier se base sur la librairie Python "testinfra" ou sur Ansible lui même afin de, non pas réellement de "tester" tâche par tâche, mais de "vérifier" le résultat suite à l'exécution du rôle ou playbook.
C'est l'une des choses qui peut déranger avec ce framework quand on a l'habitude de coder des tests avec des bibliothèques de tests natives (comme unittest en Python par exemple) qui permettent de tester le code lui-même.
Par ailleurs, comme précisé dans la documentation, les ressources Ansible sont des "modèles d'états souhaités". Il n'est donc pas nécessaire de tester qu'un service a bien été démarré, qu'un paquet a bien été installé, etc. C'est Ansible qui le garantit pour vous. En effet les modules utilisés dans nos tâches ont leur propres tests unitaires qui assurent que ces choses sont déclarativement vraies.
Plus encore, les modules derrière testinfra sont d'un nombre limité et ne peuvent couvrir à eux seuls toutes les possibilités d'exécutions d'un script Ansible.
Et puis finalement un Playbook c'est quoi ? C'est bien souvent une suite de manipulations de données avant d'exécuter un module particulier. Nous récupérons de la donnée depuis une API d'un coté, puis de l'autre le résultat de l'exécution d'un module. Pour transformer cette donnée à l'aide de "filtre" afin de merger des dictionnaires, de créer des listes, extraire des variables, nous concaténons le tout avec les informations fournies par l'opérateur au moment de l'exécution, etc… pour finalement faire un appel à un autre module dans une nouvelle tâche.
Comme pour un test unitaire, suivant une liste de variables connues en entrée nous voulons être certains que cette derrière tâche :
- est bien exécutée (le script peut avoir échoué en amont) ;
- a bien été appelée avec la bonne instanciation d'arguments (notre donnée transformée) ;
- a bien retourné le résultat attendu ;
- s'est bien terminée dans l'état souhaité ("changed", skipped,"failed").
Monkeyble permet ce type de tests avec une approche que l'on retrouve communément dans les langages de programmation.
Petit tour des fonctionnalités
Tester les entrées
Vous pouvez déclarer une vérification des valeurs instanciées passées en argument des modules
- task: "my_task_name"
test_input:
- assert_equal:
arg_name: module_argument
expected: "my_value"
Monkeyble supporte des méthodes de tests comme celle disponibles dans la librairie unittest de Python: assert_equal, assert_not_equal, assert_in, assert_not_in, assert_true, assert_false, assert_is_none, assert_is_not_none, assert_list_equal, assert_dict_equal.
Tester le résultat des exécutions de module
Les modules Ansible, pour la majeure partie, retournent un dictionnaire qui peut être conservé à l'aide d'un "register" afin d'etre utilisé par les tâches suivantes.
Monkeyble permet de tester les valeurs retournées avec les mêmes méthodes que pour le test des entrées.
- task: "my_task_name"
test_output:
- assert_dict_equal:
dict_key: "result.key.name"
expected:
key1: "my_value"
key2: "my_other_value"
Tester les états des tâches
Une tâche Ansible a plusieurs états possibles suite à son exécution. Monkeyble peut vérifier qu'une tâche s'est bien terminée dans un état particulier.
- task: "my_task_name"
should_be_skipped: false
should_be_changed: true
should_failed: false
Simuler un module (Monkey patching)
Le "Monkey patching", est une technique permettant de modifier dynamiquement une méthode afin de renvoyer une ou des valeurs préalablement spécifiées dans le test.
Monkeyble permet de "mocker" une tâche et retourner un résultat défini.
Dans un scénario où vous travaillez avec des API de cloud, dans un contexte de tests, vous ne souhaitez pas forcément créer réellement une instance d'un objet à chaque exécution de votre CI/CD, cependant vous souhaitez que la tâche retourne ce que le vrai module aurait retourné afin d'exécuter le playbook dans son intégralité et que les tâches suivantes puissent se servir de cette sortie.
- task: "my_task_name"
mock:
config:
monkeyble_module:
consider_changed: true
result_dict:
my_key: "mock value"
Conclusion
Monkeyble est très simple à utiliser, son fonctionnement est entièrement basé sur de la configuration Yaml et reste donc dans le même état d'esprit que le projet Ansible.
Vous pouvez créer autant de scenarios que nécessaire afin de :
- garantir que vos playbooks ou rôles fonctionnent correctement ;
- protéger des régressions suite à une mise à jour de parties partagées ;
- tester unitairement des tâches complexes qui manipulent de la donnée ;
- passer dans chacune des conditions et blocs de code ;
- valider que vos playbooks s'arrêtent bien (fail) ou ne s'exécutent pas (skip) quand il le faut ;
- que les tâches critiques s'exécutent avec le bon jeu d'arguments.
monkeyble test
Playbook | Scenario | Test passed
-----------+-----------------+-------------
play1.yml | validate_test_1 | ✅
play1.yml | validate_test_2 | ✅
play2.yml | validate_this | ✅
play2.yml | validate_that | ✅
🐵 Monkeyble test result - Tests passed: 4 of 4 tests
Happy testing à vous ! ✅
# C'est quoi la grande différence avec Molécule ?
Posté par xandercagexxx . Évalué à 1.
Je connaissais pas Monkeyble.
Je sais qu'il y a Molecule pour tester les roles Ansible, mais de ce que tu indiques là, j'ai l'impression que Monkeyble test seulement le playbook.
C'est quoi la grande différence entre les 2 soft et faut-il utiliser les 2 ?
On est pas encore passé à ce niveau de qualité en interne, mais je suis preneur de tous les retours possible sur les 2 outils.
[^] # Re: C'est quoi la grande différence avec Molécule ?
Posté par Gil Cot ✔ (site web personnel, Mastodon) . Évalué à 3.
De ce que j'ai compris, Monkeyble teste effectivement les playbooks selon un certain nombre de choix faits (comme écrire un test unitaire lorsqu'on développe)
test_input
… Mais je n'ai pas bien compris où la tâche se place et en quoi c'est mieux quewhen
dans la tâche,assert
avant.test_output
… Pareil, je ne sais pas où se place cette tâche et pourquoi c'est mieux que d'utiliserfailed_when
/changed_when
/etc dans la tâche,fail
après.should_be_skipped
/should_be_changed
/should_failed
qui semblent être des synonymes des tests avecwhen
sur les variables d'étatchanged
/failed
/skipped
(avec des filtres de même nom surresults
)mock
dont je n'ai pas compris l'exemple mais qui me fait penser aucheck_mode
Molecule peut être utilisé aussi pour tester les playbooks (quand on teste un rôle, on teste un playbook qui ne traite que de ce rôle, mais rien n'empêche de faire plus large) mais le principe est d'automatiser ce test sur les environnements de qualification …en reproduisant tous les cas que l'on supporte (tous les os dans toutes les versions et toutes les combinaisons logicielles doivent être présentes.)
“It is seldom that liberty of any kind is lost all at once.” ― David Hume
[^] # Re: C'est quoi la grande différence avec Molécule ?
Posté par sispheor . Évalué à 3.
J'aurais dû mettre le hello World de la doc.
Monkeyble ne demande pas de modification du playbook ou rôle. Il va exécuter le playbook et vérifier tâche par tâche les entrée ou sortie.
Le mock aussi présent dans la doc permet de valider par exemple les inputs sans pour autant vraiment exécuter le module.
Par exemple vous avez un module pour créer une VM vous voulez juste vérifier que la tâche aurait été appelé avec les bons arguments.
Faut faire un tour sur la doc pour mieux visualiser.
[^] # Re: C'est quoi la grande différence avec Molécule ?
Posté par Gil Cot ✔ (site web personnel, Mastodon) . Évalué à 2.
My bad, je me suis contentée de cette publication. Je vais jeter un œil à la doc.
“It is seldom that liberty of any kind is lost all at once.” ― David Hume
[^] # Re: C'est quoi la grande différence avec Molécule ?
Posté par sispheor . Évalué à 1.
C'est ma faute aussi. Je baigne dedans et du coup j'ai pas pensé à mettre cette chose essentielle qu' est le hello World.
Faudrait que je contacte la rédaction pour voir si je peux modifier la dépêche.
[^] # Re: C'est quoi la grande différence avec Molécule ?
Posté par Ysabeau 🧶 (site web personnel, Mastodon) . Évalué à 3.
La modération peut, seule le faire.
Donc, on modifie quoi et où dans le texte ?
« Tak ne veut pas quʼon pense à lui, il veut quʼon pense », Terry Pratchett, Déraillé.
[^] # Re: C'est quoi la grande différence avec Molécule ?
Posté par sispheor . Évalué à 1. Dernière modification le 02 décembre 2022 à 16:57.
Il faudrait genre ajouter la traduction FR de la section "hello world" du readme ici.
Le mettre juste après "contexte" je pense.
[^] # Re: C'est quoi la grande différence avec Molécule ?
Posté par sispheor . Évalué à 3.
En réalité molécule ne test pas vraiment. Il exécute le playbook dans un env conteneurisé et vous demande de "vérifier" par vous même après coup que le résultat final est bien celui attendu.
[^] # Re: C'est quoi la grande différence avec Molécule ?
Posté par Alex G. . Évalué à 3.
Déjà savoir qu'un playbook qui run jusqu'au bout c'est un bon signe, car le playbook peut lui même contenir les tests que l'environnement déployé fonctionne (c'est mieux en général !) par exemple avec un check sur une url publique, ou une petite requête BDD, etc.
# Intéressant mais est-ce suffisant ?
Posté par Alex G. . Évalué à 3.
Bravo pour votre projet. Monkeyble est sûrement tout à fait utile pour améliorer les playbook, mais ça ne me semble pas suffisant.
Perso ce qui m'a éloigné de Ansible c'est justement que cette phrase est fausse ! Rare sont les modules Ansible vraiment écrits comme ça.
(attention, mon expérience date un peu, si des choses ont changé c'est super)
Un des manques criant, par exemple, est le nettoyage des tâches supprimées (si j'enlève une tâche qui ajoute une ligne dans un fichier de conf, cette ligne restera là où elle a été mise), il faudrait plutôt que Ansible gère un état on/off.
Pour assurer sa maxime, Ansible devrait drastiquement limiter les modules à ceux capable de gérer ces cas là, mais ce n'est pas vrai de la plupart des modules de base même…
J'ai beaucoup souffert à déverminer des playbook qui avait fait l'objet de maintenance, qui pouvait run sur la machine de prod, mais était incapable de ré-installer une machine à partir de zéro… ou le contraire !
Bref perso je suis bien plus content de l'approche Docker pour le moment: rebâtir tout de zéro à chaque fois, sans arrêt ! (mais oui, ok, Docker ne va pas faire l'install du système sosu jacent, donc il faut un truc, mais je le limite au maximum)
Si je devais faire du déploiement automatisé je chercherais autre chose que Ansible, peut être pyinfra pour éviter le cauchemar des yaml imbriqués les uns dans les autres (et qui s'appellent tous "main.yml" ;-) ).
[^] # Re: Intéressant mais est-ce suffisant ?
Posté par Benoît Sibaud (site web personnel) . Évalué à 5. Dernière modification le 03 décembre 2022 à 10:57.
Oui tu es d'abord censé "retirer la ligne" (state absent au lieu de present) puis retirer la tâche. Il n'y a pas de magie non plus : si tu retires une machine de ton inventaire, ansible ne va pas la déconfigurer. Si tu retires de la gestion ansible un utilisateur ajouté sur une machine sans avoir fait son retrait, il va rester. Pareil pour une entrée DNS ajoutée, un stockage objet distant provisionné, un fichier créée sur disque, un paquet installé, etc. Etc. Ansible ne gère pas ce qu'on ne lui dit pas, Git ne gère pas ce qu'on ne lui dit pas, etc.
[^] # Re: Intéressant mais est-ce suffisant ?
Posté par Gil Cot ✔ (site web personnel, Mastodon) . Évalué à 2.
+1 C'est que malheureusement l'outil n'est pas compris comme cela par certaines personne qui s'attendent à une sorte de magie vodou. Mais effectivement, ça gère les états que l'on déclare (et retire la gestion d'un état ne va pas automagiquement retirer l'état heureusement, mais juste ne plus la gérer.)
“It is seldom that liberty of any kind is lost all at once.” ― David Hume
[^] # Re: Intéressant mais est-ce suffisant ?
Posté par Alex G. . Évalué à 2.
On est d'accord, et je n'ai jamais dit que ce devait être magique, mais vraiment il y a des commandes où cet état présent/absent n'est pas géré par la commande. (bon en tout cas à l'époque où je l'utilisais).
C'est peut être aussi les rôles qui manquent parfois de maturité (et n'ont pas de vrai désinstallation).
Au final je trouve en tout cas que la promesse de "déclarer un état" n'est que très peu tenue.
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.