Testing Ansible Content with Molecule
Time for another blog post! 🚀
In this blog post, I will be discussing how to test Ansible content with Molecule ๐งช
What is Molecule?
Molecule aids in the development and testing of Ansible content: collections, playbooks and roles.
github.com/ansible-community/molecule1
Why do we need to test Ansible content?
Testing is an integral part of the software development lifecycle. It helps identify and prevent bugs from reaching production and in some cases, helps identify performance issues. When creating Ansible content we need to ensure that it works as expected and that we are not introducing any undesired behaviour. This is where Molecule comes in.
Molecule Terminology ๐
Molecule has several terms that are used throughout the documentation. Let’s go over them now.
Instances & Drivers ๐
Molecule instances are what your Ansible content is executed against. Instances are created using a driver. Molecule has several drivers for handling the creation and destruction of instances. The drivers are currently located in ansible-community/molecule-plugins repository.
For example, the default Docker driver can be used to create a container instance and the Vagrant driver can create a virtual machine instance.
Scenarios ๐
Molecule scenarios can be thought of as a test suite. Each scenario contains its own instances and configuration. For example, a scenario could be used to test an Ansible role against different distributions or test a specific configuration of a role.
There should always be a default scenario which is used to test Ansible content with its default configuration.
Molecule Directory Structure ๐
A basic Molecule directory structure is:
molecule
โโโ default
โโโ prepare.yml
โโโ converge.yml
โโโ verify.yml
โโโ molecule.yml
Within the molecule directory is the default scenario directory which contains the prepare.yml, converge.yml and verify.yml playbooks, as well as the molecule.yml configuration file.
Prepare Playbook โถ๏ธ
The prepare.yml playbook defines the preparation tasks to run before the converge.yml playbook. For example, this could be used configure the instance.
Converge Playbook โถ๏ธ
The converge.yml playbook defines the Ansible content to be tested. This can be a playbook, role or collection.
Verify Playbook โถ๏ธ
The verify.yml playbook is executed after the converge.yml playbook. This playbook contains verification tasks to check the Ansible content has been applied correctly.
Configuration File molecule.yml ๐
The molecule.yml file contains configuration for each Molecule component2:
| Component | Description |
|---|---|
| Dependency Manager | Molecule uses Ansible Galaxy as the default manager for resolving role and collection dependencies. |
| Driver | Instances & Drivers. |
| Platforms (Instances) | Defines instances to be created by the driver for the scenario. |
| Provisioner | Molecule uses Ansible as the provisioner. The provisioner manages the life cycle of instances by communicating with the driver. |
| Scenario | Molecule’s default scenario configuration can be overridden for full control over each sequence. |
| Verifier | Molecule uses Ansible as the verifier. The verifier uses the verify.yml playbook to check the state of the instance. |
The example below shows a basic configuration using the Docker driver to create a Debian container instance.
1---
2dependency:
3 name: galaxy
4driver:
5 name: docker
6platforms:
7 - name: instance
8 image: geerlingguy/docker-debian10-ansible:latest
9 pre_build_image: true
10provisioner:
11 name: ansible
12verifier:
13 name: ansible
Molecule Commands ๐
Molecule has several commands for performing different actions. The most common commands are:
| Molecule Command | Description |
|---|---|
create | Creates the instance defined in the molecule.yml file. |
destroy | Destroys the instance defined in the molecule.yml file. |
login | Spawns a shell inside the instance. Useful for troubleshooting. |
converge | Performs the converge sequence which includes creating the instance and executing the prepare.yml and converge.yml playbooks. |
test | Performs a full test scenario. This includes the converge and idempotency sequences, executing the verify.yml playbook and destroying the instance. |
Now that we have covered the basics, let’s test an Ansible playbook with Molecule! ๐งช
Demo ๐บ
I’ve created a demo repository which contains a simple playbook to install nginx on a Debian container instance. You’ll need to have Docker and Python installed to use the repository.
Begin by cloning the repository:
1git clone https://github.com/dbrennand/molecule-demo.git && cd molecule-demo
Inspect the files and notice the default molecule scenario with the playbooks and molecule.yml configuration file. The converge.yml playbook calls the main playbook.yml two directories above.
Next, install Molecule and the Docker driver. I recommend using a virtual environment:
1mkdir -pv ~/.virtualenvs
2python3 -m venv ~/.virtualenvs/molecule-demo
3source ~/.virtualenvs/molecule-demo/bin/activate
4pip install -r requirements.txt
Now we can run the molecule test command to perform a full test scenario:
1molecule test
The output should look similar to the following:
1INFO Running default > create
2
3PLAY [Create] ******************************************************************
4
5TASK [Create molecule instance(s)] *********************************************
6changed: [localhost] => (item=instance)
7
8...
9
10INFO Running default > prepare
11
12PLAY [Prepare] *****************************************************************
13
14TASK [Gathering Facts] *********************************************************
15ok: [instance]
16
17TASK [Update apt cache] ********************************************************
18changed: [instance]
19
20...
21
22INFO Running default > converge
23
24PLAY [Converge] ****************************************************************
25
26TASK [Gathering Facts] *********************************************************
27ok: [instance]
28
29PLAY [Playbook | Install nginx] ************************************************
30
31TASK [Gathering Facts] *********************************************************
32ok: [instance]
33
34TASK [Install nginx] ***********************************************************
35changed: [instance]
36
37PLAY RECAP *********************************************************************
38instance : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
39
40INFO Running default > idempotence
41
42PLAY [Converge] ****************************************************************
43
44TASK [Gathering Facts] *********************************************************
45ok: [instance]
46
47PLAY [Playbook | Install nginx] ************************************************
48
49TASK [Gathering Facts] *********************************************************
50ok: [instance]
51
52TASK [Install nginx] ***********************************************************
53ok: [instance]
54
55PLAY RECAP *********************************************************************
56instance : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
57
58INFO Idempotence completed successfully.
59INFO Running default > side_effect
60WARNING Skipping, side effect playbook not configured.
61INFO Running default > verify
62INFO Running Ansible Verifier
63
64PLAY [Verify] ******************************************************************
65
66TASK [Gathering Facts] *********************************************************
67ok: [instance]
68
69TASK [Gather package list] *****************************************************
70ok: [instance]
71
72TASK [Verify nginx is installed] ***********************************************
73ok: [instance] => {
74 "changed": false,
75 "msg": "All assertions passed"
76}
77
78PLAY RECAP *********************************************************************
79instance : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
80
81INFO Verifier completed successfully.
82INFO Running default > cleanup
83WARNING Skipping, cleanup playbook not configured.
84INFO Running default > destroy
85
86PLAY [Destroy] *****************************************************************
87
88TASK [Wait for instance(s) deletion to complete] *******************************
89FAILED - RETRYING: [localhost]: Wait for instance(s) deletion to complete (300 retries left).
90changed: [localhost] => (item=instance)
91
92PLAY RECAP *********************************************************************
93localhost : ok=3 changed=2 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
Tada! You’ve just tested an Ansible playbook with Molecule! โจ๐
We now have peace of mind that our playbook works as expected! :slight_smile:
Conclusion ๐
In this blog post, we covered the basics of using Molecule and how to test Ansible content. I recommend checking out the Molecule documentation for more information.
I hope you found this post useful and if you have any questions or feedback, feel free to reach out to me on Twitter or via email.
Until next time, happy testing! ๐งช 👋