A while ago I was drafting an official Ansible Role for Icinga 2. From my previous experience with writing Puppet modules and helping shape Chef cookbooks I already knew approximately how the Ansible role should look like and what functionality should be included. At some point I came across the question how testing should be done during development?
From all the options available, two stuck out:
– KitchenCI with an Ansible provisioner
I used TestKitchen in the past to test Chef cookbooks, so this was an advantage. However, after some research I decided to go with Molecule, a tool designed especially for Ansible roles and playbooks. It seems to me to be the better option to use a tool that explicitly aims to test Ansible stuff, rather then using TestKitchen which usually is used for Chef cookbooks but has an extension to support Ansible provisioning.
Molecule support multiple virtualization providers, including Vagrant, Docker, EC2, GCE, Azure, LXC, LXD, and OpenStack. Additionally, various test frameworks are supported to run syntax checks, linting, unit- and integration tests.
Getting started with Molecule
Molecule is written in Python and the only supported installation method is Pip. I won’t go through all requirements, since there’s a great installation documentation available. Besides the requirements, you basically just install molecule via Pip
pip install molecule
After molecule is successfully installed, the next step is to initialise a new Ansible role:
molecule init role -d docker -r ansible-myrole
This will not only create files and directories needed for testing, but the whole Ansible role tree, including all directories and files to get started with a new role. I choose to use Docker as a virtualisation driver. With the
init command you can also set the verifier to be used for integration tests. The default is testinfra and I stick with that. Other options are goss and inspec.
Molecule uses Ansible to provision the containers for testing. It creates automatically playbooks to prepare, create and delete those containers. One special playbook is created to actually run your role. The main configuration file,
molecule.yml includes some general options, such as what linter to use and on which platform to test. By default
cents:7 is the only platform used to test the role. Platforms can be added to run the tests on multiple operating systems and versions.
I mentioned before that I use testinfra to write the integration tests. With the
init command Molecule creates a default scenario, which we can use for the first steps. For example, checking if a package is installed and a the service is running the code would look like this:
import os import testinfra.utils.ansible_runner testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') def test_icinga2_is_installed(host): i2_package = host.package("icinga2") assert i2_package.is_installed def test_icinga2_running_and_enabled(host): i2_service = host.service("icinga2") assert i2_service.is_running assert i2_service.is_enabled
There are multiple ways to run your tests, but there’s one command that does everything automatically. It runs listing tests, provisions containers, runs your playbook, runs integration tests, shows failures and destroys the containers at the end.
With other commands you can do all of these steps one by one. Of course there’s much more possible with molecule, such as creating different scenarios and using multiple instances to do more complex testing. The Molecule documentation is well written and has some examples on what you can do more.