Loading search data...

Ansible - Tester vos roles avec molecule

Publié le : 30 août 2022 | Mis à jour le : 27 juin 2023

logo ansible

Molecule 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 fichier Dokerfile.j2 se trouvant dans le dossier template.
  • 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 :

Mots clés :

devops ansible tutorials infra as code formation ansible

Si vous avez apprécié cet article de blog, vous pouvez m'encourager à produire plus de contenu en m'offrant un café sur  Ko-Fi. Vous pouvez aussi passer votre prochaine commande sur amazon, sans que cela ne vous coûte plus cher, via  ce lien . Vous pouvez aussi partager le lien sur twitter ou Linkedin via les boutons ci-dessous. Je vous remercie pour votre soutien.

Autres Articles


Commentaires: