Ansible - Tester vos roles avec molecule
Publié le : 30 août 2022 | Mis à jour le : 27 juin 2023Molecule est un framework permettant de tester vos développements de rôles Ansible et, ce sur de nombreuses distributions Linux en utilisant le driver de virtualisation et le framework de tests de votre choix.
- Parmi les principaux drivers, on retrouve : docker, libvirt, podman, vagrant, ec2, gce, azure, …
- Parmi les principaux frameworks de test, on trouve : Test-Infra et Ansible.
Dans ce tutoriel, j’utiliserai le driver docker
.
Installation de molecule
Attention de vérifier la compatibilité de la version de molecule avec celle d’Ansible et de python.
Le moyen le plus simple est de l’installer via pip
:
python3 -m pip install molecule molecule-plugins ansible-core ansible-lint --user
molecule --version
molecule 5.0.1 using python 3.11
ansible:2.14.4
azure:23.4.1 from molecule_plugins
containers:23.4.1 from molecule_plugins requiring collections: ansible.posix>=1.3.0 community.docker>=1.9.1 containers.podman>=1.8.1
delegated:5.0.1 from molecule
docker:23.4.1 from molecule_plugins requiring collections: community.docker>=3.0.2 ansible.posix>=1.4.0
ec2:23.4.1 from molecule_plugins
gce:23.4.1 from molecule_plugins requiring collections: google.cloud>=1.0.2 community.crypto>=1.8.0
podman:23.4.1 from molecule_plugins requiring collections: containers.podman>=1.7.0 ansible.posix>=1.3.0
vagrant:23.4.1 from molecule_plugins
Création de votre premier rôle avec molecule
Molecule permet d’initialiser la structure complète d’un rôle. Pour cela il suffit de lancer la commande suivante :
molecule init role --driver-name docker --verifier-name ansible steph.monrole
Les deux options de la commande permettent de définir le driver utilisé et
l’outil de test. Ici j’ai pris docker
et ansible
. Le dernier paramètre
est le nom du rôle.
On se retrouve avec la structure suivante :
├── defaults
│ └── main.yml
├── files
├── handlers
│ └── main.yml
├── meta
│ └── main.yml
├── molecule
│ └── default
│ ├── converge.yml
│ ├── molecule.yml
│ └── verify.yml
├── README.md
├── tasks
│ └── main.yml
├── templates
├── tests
│ ├── inventory
│ └── test.yml
└── vars
└── main.yml
Cette structure est identique à celle que la commande ansible-galaxy
, c’est
normal puisque molecule l’utilise. Par contre, on retrouve un répertoire
supplémentaire qui se nomme molecule
.
Pour ajouter molecule à un rôle existant il faut utiliser plutôt cette commande :
molecule init scenario -r <ROLE_NAME> --driver-name docker --verifier-name ansible <NOM_DU_SCENARIO>
Paramétrage de molecule
Le paramétrage se trouve dans le fichier molecule/default/molecule.yml
. Le
sous-dossier default
se trouvant dans le répertoire molecule
est le dossier
du scenario par défaut. On peut créer d’autres scenarios, pour cela il faudra
utiliser la seconde commande indiquée ci-dessus.
Détaillons le contenu du fichier de configuration molecule.yml
:
---
dependency:
name: galaxy
driver:
name: docker
platforms:
- name: instance
image: quay.io/centos/centos:stream8
pre_build_image: true
provisioner:
name: ansible
verifier:
name: ansible
lint: |
yaml-lint
Tout est documenté ici, mais voyons ensemble chacun des paramètres :
- dependency : Molecule utilise le repository ansible-galaxy par défaut pour installer les dépendances de rôle.
- driver : Molecule utilise un driver, docker par défaut, pour déléguer la tâche de création d’instances.
- platforms : Permet d’indiquer à Molecule quelles instances de linux sont à
créer. Pour le driver docker, il faut donner le nom de l’image à utiliser. Le
pre_build_image
permet de customiser une image en soit un fichier portant le<nom_de_la-plateforme>.dockerfile
soit le fichierDokerfile.j2
se trouvant dans le dossiertemplate
. - provisioner : On indique à Molecule que le provisioner est Ansible.
- verifier : Molecule utilise Ansible par défaut pour lancer des tests de vérification d’état sur les instances.
- test : Lance toutes les séquences de la création à la destruction.
Description du fonctionnement de molecule
Un peu ardu à expliquer ! La CLI de Molecule utilise des sous-commandes pour lancer des séquences (paramétrables). Voici la liste des principales sous-commandes :
- dependency : installe les dépendances ansible-galaxy nécessaires à l’exécution du rôle.
- create : création de l’instance avec le driver indiqué. Le rôle ne sera pas exécuté.
- prepare : exécution du playbook
prepare.yml
sur l’instance (installation des prérequis) - converge : exécution du playbook
playbook.yml
sur la l’instance (exécution du rôle lui-même) - verify : exécution du playbook
verify.yml
sur l’instance (tests unitaires) - destroy : destruction de l’environnement et de la VM
Les autres sont : check
, cleanup
, idempotence
, side-effect
,
syntax
.
C’est là où ça se complique. Chaque sous-commande lance en fait des séquences de
sous-commandes. Pour en connaitre la composition, il faut utiliser la commande
molecule matrix <sous-commandes>
:
molecule matrix converge
INFO Test matrix
---
default:
- dependency
- create
- prepare
- converge
On voit donc que la sous-commande converge
lance dans l’ordre indiqué
dependency
, puis create
, et ainsi de suite.
Paramétrage du scenario
Par défaut lors de l’initialisation, il y a un paramètre qui n’est pas mis dans la configuration, mais qui permet de décrire le scenario qui sera utilisé : scenario.
Molecule s’appuie sur cette configuration pour contrôler la composition et l’ordre des séquences du scénario. Plus d’infos ici
Vous pouvez modifier les séquences par défaut. Par exemple pour ne pas lancer
prepare
dans lors de la création de l’instance :
scenario:
create_sequence:
- dependency
- create
Vérifions avec la sous-commande matrix
:
molecule matrix create
INFO Test matrix
---
default:
- dependency
- create
Ecriture du role (basique)
Pour faire simple, je vais simplement lancer l’installation du package nginx. Il suffit de mettre ceci dans le fichier `tasks/main.yml :
- name: Install nginx.
ansible.builtin.package:
name: nginx
state: present
Ecriture des tests avec Ansible
Il est possible d’utiliser ansible pour tester la bonne exécution de notre rôle.
Lors de l’initialisation, molecule à créer un playbook molecule/verify.yml
mais je vais en modifier le contenu avec ceci :
---
- name: Verify
hosts: all
gather_facts: false
tasks:
- name: Nginx est présent
ansible.builtin.stat:
path: /usr/sbin/nginx
Execution du scenario de test
Nous allons utiliser le scénario par défaut pour tester notre rôle.
Pour lancer la création de l’instance et l’exécution du rôle, il faut utiliser
la commande molecule converge
. Si l’instance existe déjà elle ne sera pas
recréée.
molecule verify
INFO default scenario test matrix: verify
INFO Performing prerun with role_name_check=0...
INFO Set ANSIBLE_LIBRARY=/home/vagrant/.cache/ansible-compat/7bf8c0/modules:/home/vagrant/.ansible/plugins/modules:/usr/share/ansible/plugins/modules
INFO Set ANSIBLE_COLLECTIONS_PATH=/home/vagrant/.cache/ansible-compat/7bf8c0/collections:/home/vagrant/.ansible/collections:/usr/share/ansible/collections
INFO Set ANSIBLE_ROLES_PATH=/home/vagrant/.cache/ansible-compat/7bf8c0/roles:/home/vagrant/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles
INFO Using /home/vagrant/.cache/ansible-compat/7bf8c0/roles/steph.monrole symlink to current repository in order to enable Ansible to find the role using its expected full name.
INFO Running default > verify
INFO Running Ansible Verifier
INFO Sanity checks: 'docker'
PLAY [Verify] ******************************************************************
TASK [Nginx est présent] *******************************************************
ok: [instance]
PLAY RECAP *********************************************************************
instance : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Pour debugger il suffit d’ajouter l’argument --debug
devant la
sous-commande. Pour élever le niveau de debug vous pouvez utiliser cette
commande : ANSIBLE_DEBUG=true molecule converge -- -vvv
.
Pour vous connecter dans l’instance, il faut utiliser la commande molecule login
.
Si vous modifiez les tests vous pouvez relancer la commande molecule verify
pour ne pas relancer la création de l’instance et l’exécution du rôle.
Une fois terminée pour tout nettoyer, lancer la commande molecule destroy --all
.
Activation de systemd sur les instances Docker
Pour contourner les restrictions de lancement d’un service dans une instance docker, il faut modifier les paramètres des plateforms.
platforms:
- name: instance
image: quay.io/centos/centos:stream8
command: /sbin/init
tmpfs:
- /run
- /tmp
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:ro
Lançons le provisionnement :
molecule destroy --all
molecule create
Vérifions que cela fonctionne :
molecule login
[root@instance /]# systemctl list-units
UNIT LOAD ACTIVE SUB DESCRIPTION
-.mount loaded active mounted Root Mount
dev-mqueue.mount loaded active mounted POSIX Message Queue File System
etc-hostname.mount loaded active mounted /etc/hostname
etc-hosts.mount loaded active mounted /etc/hosts
etc-resolv.conf.mount loaded active mounted /etc/resolv.conf
Modifions notre rôle pour démarrer le service nginx :
- name: Install nginx.
ansible.builtin.package:
name: nginx
state: present
- name: Start nginx service
ansible.builtin.service:
name: nginx
state: started
enabled: true
Modifier l’image avec la séquence prepare
Pour installer des packages ou créer des configurations qui ne sont pas
présentes dans l’image, mais serait utile au debug par exemple, nous allons créer
un playbook dans le fichier molecule/prepare.yml
.
---
- name: Prepare
hosts: all
tasks:
- name: installation de top et nestat
ansible.builtin.package:
name:
- procps
- net-tools
state: present
On lance le converge et on vérifie que le service nginx est bien démarré :
molecule converge
...
molecule login
netstat -tlnp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 386/nginx: master p
tcp6 0 0 :::80 :::* LISTEN 386/nginx: master p
Mais on va ajouter le test dans notre playbook molecule/verify.yml
.
- name: Verify
hosts: all
gather_facts: false
tasks:
- name: Nginx est présent
ansible.builtin.stat:
path: /usr/sbin/nginx
- name: chargement de l'état des service
ansible.builtin.service_facts:
- name: Controle de la présence de nginx
ansible.builtin.assert:
that:
- services["nginx.service"]["state"] == "running"
- services["nginx.service"]["status"] == "enabled"
Vous remarquerez que j’utilise services_facts pour charger l’état des services, ainsi que le module assert pour contrôler le status et l’état du service nginx.
Voila plutôt content d’avoir pu expliquer le fonctionnement de molecule avec
son driver docker
et le verifier ansible
pour la partie test. En espérant
avoir été assez clair.
Plus loin
J’ai écris d’autres billets sur molecule :
- Utilisation du driver delegated pour provisioner des VM chez le provider outscale avec du terraform.
- Utilisation de molecule pour tester les collections, mais aussi les images packer.