Testing Ansible Roles Using Molecule
Quick guide to show how easy it is to test Ansible roles using Molecule
Why are we testing?
As we work on our Ansible roles we have an idea what we want the role to do and we test it throughout the development process. This is often manual and time consuming and often works fine…. initially. The problem is that one day someone else might make changes to your role and might accidentally break it without noticing it. When automated tests are in place, failing tests will alert the person making the change, to any breaking changes to the role.
What is Molecule?
Molecule is a tool designed to help with development and automated testing of Ansible roles. You can use it to test with multiple operating systems, virtualization providers, test scenarios etc. You can easily run your tests locally and in the cloud.
To get started you’ll need to have python, pip & virtualenv installed.
Setting up python venv & installing packages using pip
Go to the directory where you want to create your role and create a python virtual environment.
python3 -m venv env
The whole idea of python virtual environments is to create isolated environments for python projects where you can install packages and even test out multiple versions within the same project.
Activate the virtual environment to make sure all actions remain within this environment
source env/bin/activate
Once you activate an environment you should see the environment name in parentheses in your command line
(env) ➜ TestingAnsibleUsingMolecule git:(initial-dev) ✗
Installing Molecule and Docker using pip
pip install molecule docker
This will install both packages including any dependencies to the python environment
Creating the Ansible role
(env) ➜ TestingAnsibleUsingMolecule git:(initial-dev) ✗ molecule init role my-role
--> Initializing new role my-role...
Initialized role in TestingAnsibleUsingMolecule/my-role successfully.
This has created the directory structure for our Ansible role
Change into the role directory
(env) ➜ TestingAnsibleUsingMolecule git:(initial-dev) ✗ cd my-role
(env) ➜ my-role git:(initial-dev) ✗
Molecule magic
Run molecule test to make sure everything works as expected. This should run without any errors and the output should be similar to this:
(env) ➜ my-role git:(initial-dev) ✗ molecule test
--> Test matrix
└── default
├── dependency
├── lint
├── cleanup
├── destroy
├── syntax
├── create
├── prepare
├── converge
├── idempotence
├── side_effect
├── verify
├── cleanup
└── destroy
...
Because the role is empty and doesn’t really do anything the only thing that happens when we run molecule test is a docker container is spun up and the Example assertion test runs. If you open the molecule.yml file in molecule/default it looks like this
Here you can see that we’re using the docker driver & CentOS 7 image from pycontribs. You can change this to any image you’d like to use. We’re also using ansible as the verifier. This is different from molecule v2 where the default verifier was TestInfra
Lets add a simple task to our role which installs Nginx.
Open the main.yml file in the tasks directory and add the following task
Feel free to run molecule test to make sure the role runs without any errors. The play recap should look something like this
PLAY RECAP *********************************************************************
localhost : ok=2 changed=2 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
Now lets add a test to check if Nginx is installed
Open verify.yml in molecule/default and replace the current test with
All we’re doing here is
- Get a list of all installed packages
- Loop through the list of packages and check if they’re installed (nginx being the only thing in this case)
Now if you run molecule test the following happens
- Docker container starts up
- Updates are installed
- Nginx is installed
- Molecule tests run — in our case we only check to make sure nginx is installed on the container
If you look at the output from molecule test there’s a stage named Running Ansible Verifier. Here you can see what is being tested and if it passed or failed
--> Running Ansible Verifier
PLAY [Verify] ******************************************************************
TASK [Gathering Facts] *********************************************************
ok: [instance]
TASK [Gather package facts] ****************************************************
ok: [instance]
TASK [Verify Packages] *********************************************************
ok: [instance] => (item=nginx) => {
"ansible_loop_var": "item",
"changed": false,
"item": "nginx",
"msg": "All assertions passed"
}
PLAY RECAP *********************************************************************
instance : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Verifier completed successfully.
Looking at the above output everything ran successfully. Great! Now let’s break the test to make sure it actually works.
Change nginx to my_imaginary_nginx in molecule/default/verify.yml
When you run molecule test you should now see an error message as our my_imaginary_nginx package isn’t installed
--> Running Ansible Verifier
PLAY [Verify] ******************************************************************
TASK [Gathering Facts] *********************************************************
ok: [instance]
TASK [Gather package facts] ****************************************************
ok: [instance]
TASK [Verify Packages] *********************************************************
failed: [instance] (item=my_imaginary_nginx) => {
"ansible_loop_var": "item",
"assertion": "'my_imaginary_nginx' in ansible_facts.packages",
"changed": false,
"evaluated_to": false,
"item": "my_imaginary_nginx",
"msg": "Assertion failed"
}
PLAY RECAP *********************************************************************
instance : ok=2 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
ERROR:
An error occurred during the test sequence action: 'verify'. Cleaning up.
If any of your tests are failing, you can bring up the container by running molecule converge. This will only bring up the container. It won’t run any tests and the container will continue running. You can then run molecule verify to run the tests and easily jump onto it and troubleshoot anything that’s failing. Once you’re happy everything is as it should be you can run molecule test and then molecule destroy.
That’s all there is. Fairly straight forward. You can easily create tests using ansible and check for installed packages, services, files, directories etc.
Summary
In this tutorial we have created an Ansible role using Molecule, added a task to install nginx, added a test to make sure nginx is installed, and we’ve also proven that the test works by testing for an imaginary nginx package which wasn’t installed, and as expected, caused our test to fail.
Bonus — Systemd
If you require systemd you need to change the platform config in molecule/default/molecule.yml to
You can use the image from jrei/systemd-centos as an example or build your own.
P.S: If you are looking for a challenge, — Get in touch! We’re hiring!