Pour l’un de nos clients chez Clever Age, nous avons appuyer une grosse partie de notre provisioning de l’ensemble de nos environnements avec Ansible et nous utilisons un grand nombre de rôles créés par l’excellant Geerlingguy.

L’un de ces rôles est le rôle Ansible PHP.

Le rôle permet de confier à Ansible la gestion du fichier du pool php-fpm.

Malheureusement, il n’est pas possible de modifier certaines variables du fichier d’origine ou d’ajouter de nouvelles lignes simplement.

Objectifs

Nous voulons donc créer un nouveau rôle qui dépendra du rôle geerlingguy.php et viendra gérer de nouvelles variables, notamment :

  • pm pour pouvoir passer de dynamic à static
  • pm.max_requests

Le projet

Point de départ : Documentation de Molecule

Préparation

  • Installation de molecule
pip install --user molecule

Implémentation

Molecule permet de générer directement un nouveau rôle Ansible avec une préconfiguration des tests. Nous allons utiliser cette fonctionnalité pour créer notre rôle.

Générer un nouveau rôle Ansible avec Molecule

molecule init role --role-name newrole.php --verifier-name testinfra --driver-name docker

On définit ici le nom du rôle, l’outil de tests qui nous servira à vérifier le résultat du provisioning, verifier, et le pilote, driver, qui va exécuter recevoir l’éxécution des tests.

A noter : on définit ici testinfra et docker pour l’exemple, néanmoins ce sont les valeurs par défaut.

Une fois le rôle généré, vous obtenez la structure d’un rôle classique et un ensemble de dossiers et fichiers spécifique à Molecule :

.
├── defaults
│   └── main.yml
├── handlers
│   └── main.yml
├── meta
│   └── main.yml
├── molecule
│   └── default
│       ├── Dockerfile.j2
│       ├── INSTALL.rst
│       ├── molecule.yml
│       ├── playbook.yml
│       └── tests
│           └── test_default.py
├── README.md
├── tasks
│   └── main.yml
└── vars
    └── main.yml

En regardant le fichier Install.rst, on se rend compte que pour faire fonctionner molecule avec Docker il faut ajouter un sous-module à notre système :

pip install 'molecule[docker]'

Si vous suivez une approche TDD, il est maintenant temps d’aller modifier les fichiers molecule.yaml et playbook.yaml pour y ajouter les éléments à provisionner.

Définir son playbook de tests

L’objectif du playbook est de tester le rôle courant et ses éventuels dépendances.

On va donc définir un playbook, dans le fichier playbook.yaml, avec nos variables et les rôles à appliquer

---
- name: Converge
  hosts: all
  become: yes

  vars:
    php_enable_webserver: false
    php_enable_php_fpm: true
    php_install_recommends: false
    php_fpm_pm_max_requests: 1000
    php_fpm_pm_type: "static"

  pre_tasks:
    - name: Update apt cache.
      apt: update_cache=true cache_valid_time=3600
      when: ansible_os_family == 'Debian'
      changed_when: false

  roles:
    - role: geerlingguy.php
    - role: newrole.php

Dans notre cas, on va tester l’installation du rôle geerlingguy.php suivi de notre nouveau role newrole.php et passer les 2 variables que l’on souhaite vérifier par la suite :

  • php_fpm_pm_max_requests: 1000
  • php_fpm_pm_type: "static"

Écrire des tests avec testinfra

Avant de lancer les tests, on va écrire un petit test avec testinfra, un module Pyhton pour tester ses configurations.

Dans le fichier newrole.php/molecule/default/tests/test_default.py, nous allons ajouter une nouvelle fonction

import os

import testinfra.utils.ansible_runner

testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
    os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all')

def test_php_pool_file(host):
    f = host.file('/etc/php/7.0/fpm/pool.d/www.conf')

    # Check if www.conf file exists
    assert f.exists

    c = f.content

    # Check if our 2 variables exists with the right values
    assert b'pm = static' in c
    assert b'pm.max_requests = 1000' in c

Lancer les tests

La commande molecule test va lancer l’ensemble des étapes de tests (création, lint, provision, tests…).

Si l’on veut uniquement le provisioning, il est possible de lancer uniquement la commande molecule converge.

Si l’on veut tester manuellement le résultat du provisioning, molecule verify sera à lancer.

Les comandes essentielles

  • molecule test permet de lancer toutes les étapes
  • molecule converge permet de lancer le provisioning
  • molecule verify permet de lancer uniquement les tests
  • molecule login permet de se connecter dans le conteneur
  • molecule destroy pour supprimer le conteneur

Résumé

Les objectifs atteints :

  • Un nouveau rôle Ansible qui permet de surcharger les variables du fichier pool de fpm
  • Apprentissage des commandes principales de molecule
  • Découverte de testinfra
  • Un test, minimalistes, pour vérifier si les valeurs sont bien disponibles dans le fichier avec testinfra

Conclusion

Molecule permet de tester simplement dans divers contextes ses rôles Ansible. Sans garantir à 100% l’intégrité du résultat lors de l’application sur un autre environnement, il permet d’avoir un niveau de confiance bien plus élevé et de simplifier les tests de non régressions.

Prochaines étapes

  • Généraliser l’utilisation de molecule sur tous les nouveaux développements de rôle
  • Ajouter des tests sur les rôles existants
  • Creuser les options disponibles pour lancer des tests en mode matrice
  • Tester le provisioning d’un ensemble plus conséquent de rôles avec Molecule
  • Tester le framework de test goss en complément / remplacement de testinfra