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.
---
dependency:
name: galaxy
driver:
name: docker
platforms:
- name: instance
image: geerlingguy/docker-debian10-ansible:latest
pre_build_image: true
provisioner:
name: ansible
verifier:
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:
git 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:
mkdir -pv ~/.virtualenvs
python3 -m venv ~/.virtualenvs/molecule-demo
source ~/.virtualenvs/molecule-demo/bin/activate
pip install -r requirements.txt
Now we can run the molecule test
command to perform a full test scenario:
molecule test
The output should look similar to the following:
INFO Running default > create
PLAY [Create] ******************************************************************
TASK [Create molecule instance(s)] *********************************************
changed: [localhost] => (item=instance)
...
INFO Running default > prepare
PLAY [Prepare] *****************************************************************
TASK [Gathering Facts] *********************************************************
ok: [instance]
TASK [Update apt cache] ********************************************************
changed: [instance]
...
INFO Running default > converge
PLAY [Converge] ****************************************************************
TASK [Gathering Facts] *********************************************************
ok: [instance]
PLAY [Playbook | Install nginx] ************************************************
TASK [Gathering Facts] *********************************************************
ok: [instance]
TASK [Install nginx] ***********************************************************
changed: [instance]
PLAY RECAP *********************************************************************
instance : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
INFO Running default > idempotence
PLAY [Converge] ****************************************************************
TASK [Gathering Facts] *********************************************************
ok: [instance]
PLAY [Playbook | Install nginx] ************************************************
TASK [Gathering Facts] *********************************************************
ok: [instance]
TASK [Install nginx] ***********************************************************
ok: [instance]
PLAY RECAP *********************************************************************
instance : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
INFO Idempotence completed successfully.
INFO Running default > side_effect
WARNING Skipping, side effect playbook not configured.
INFO Running default > verify
INFO Running Ansible Verifier
PLAY [Verify] ******************************************************************
TASK [Gathering Facts] *********************************************************
ok: [instance]
TASK [Gather package list] *****************************************************
ok: [instance]
TASK [Verify nginx is installed] ***********************************************
ok: [instance] => {
"changed": false,
"msg": "All assertions passed"
}
PLAY RECAP *********************************************************************
instance : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
INFO Verifier completed successfully.
INFO Running default > cleanup
WARNING Skipping, cleanup playbook not configured.
INFO Running default > destroy
PLAY [Destroy] *****************************************************************
TASK [Wait for instance(s) deletion to complete] *******************************
FAILED - RETRYING: [localhost]: Wait for instance(s) deletion to complete (300 retries left).
changed: [localhost] => (item=instance)
PLAY RECAP *********************************************************************
localhost : 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! π§ͺ 👋