How Ansible, Molecule and Vagrant are revolutionizing testing
Re-touching finished IT infrastructures or developed IT products can be associated with a certain risk: Possible errors can be the result if something is changed again afterwards. Since updates or corrections always mean a change again, it would be helpful at this point to have a tool for testing changes. After all, testing is an essential part of any development process, but any beginning can be difficult. Molecule, a tool for testing Ansible roles, can simplify this process. This guide walks through the process of testing roles with Molecule, including setting up test environments, deploying roles, and testing deployed devices.
It covers a specific case of testing roles that deploy Docker containers and how to overcome the challenges involved.
By the end of this guide, you should have a solid understanding of how to use Molecule to test Ansible roles and ensure they work as expected before deploying them to production.
Testing Ansible Roles with Docker Containers
It's important to note that when testing roles that deploy Docker containers, it can be difficult to do so in a containerized environment (Docker in Docker, for example in GitLab CI). To overcome this issue, we can test our roles in VMs instead. In order to control these VMs, we will need a certain Molecule plugin called molecule-vagrant. This plugin fully takes care of setting up isolated environments.
Step-by-Step Guide to Testing Ansible Roles with Molecule and Vagrant
Prerequisites:
Ansible
Vagrant and VirtualBox
Molecule and Molecule-Vagrant
Step 1: Initialize a new scenario with Molecule
$ molecule init scenario -d vagrant
INFO Initializing new scenario default...
INFO Initialized scenario in /home/sebastian/a/molecule/default successfully.
Step 2: Configure your role’s dependencies
To automate Ansible role testing with Vagrant and Molecule, first, we have to configure the VM image for the Vagrant "box." inside of the molecule.yml file. We are going to be using Debian.
$ git diff 729d4e3d
--- a/molecule/default/molecule.yml
+++ b/molecule/default/molecule.yml
@@ -1,11 +1,16 @@
---
dependency:
name: galaxy
driver:
name: vagrant
platforms:
- name: instance
+ box: debian/bullseye64
provisioner:
name: ansible
verifier:
name: ansible
Then we can configure the role's dependencies by creating a requirements.yml file for Molecule testing. This file should list all the dependencies, including any Ansible roles, modules, or libraries that need to be installed.
Finally, you should create a prepare.yml file that sets up the dependencies specified in the requirements.yml file. This file can include tasks such as installing necessary packages, configuring the environment, or running any necessary scripts. With these steps in place, you can be sure that your role's dependencies are properly configured and ready for testing.
$ git diff ac65d0dc
--- a/molecule/default/molecule.yml
+++ b/molecule/default/molecule.yml
@@ -1,6 +1,7 @@
---
dependency:
name: galaxy
+ requirements-file: requirements.yml
driver:
name: vagrant
--- /dev/null
+++ b/molecule/default/prepare.yml
@@ -0,0 +1,19 @@
+---
+# Add necessary requirements to the test environment
+- name: Prepare
+ hosts: all
+ # These roles need root access
+ become: true
+
+ vars:
+ pip_install_packages:
+ - name: docker
+
+ roles:
+ - geerlingguy.docker
+ - geerlingguy.pip
+
+ pre_tasks:
+ - name: Update apt cache
+ ansible.builtin.apt:
+ update_cache: true
--- /dev/null
+++ b/molecule/default/requirements.yml
@@ -0,0 +1,8 @@
+---
+# Our role needs Docker and pip to be installed
+roles:
+ - src: geerlingguy.docker
+ version: 6.0.4
+
+ - src: geerlingguy.pip
+ version: 2.2.0
Step 3: Test your role
Once you have configured your role's dependencies, you can run the command molecule create to create the VM and prepare it. This command will create an isolated environment for testing your role and install all the dependencies specified in the requirements.yml file.
After the VM is created, you can use the command molecule login to log in to the VM and check the installation of your role's dependencies. This will give you a chance to verify that everything has been set up correctly before moving on to the next step.
Next, you can use the command molecule converge to deploy your role in the isolated environment. Keep in mind that you will have to adjust the converge.yml to run the playbook as root. This step will ensure that your role is properly installed and configured on the test VM.
$ git diff 74fdd3cb
--- a/molecule/default/converge.yml
+++ b/molecule/default/converge.yml
@@ -1,6 +1,8 @@
---
- name: Converge
hosts: all
+ # Docker access needs root permissions
+ become: true
tasks:
- name: "Include molecule_http_docker_demo"
ansible.builtin.include_role:
--- a/molecule/default/molecule.yml
+++ b/molecule/default/molecule.yml
@@ -12,6 +12,9 @@ platforms:
provisioner:
name: ansible
+ options:
+ # Enable `--diff` mode
+ D: true
verifier:
name: ansible
To make sure that the installation and functionality of your role is working as expected, you can write some tests in the verify.yml file and then run those with the command molecule verify. This step will give you the confidence that your role is working correctly before deploying it to production.
$ git diff 74fdd3cb
--- a/molecule/default/verify.yml
+++ b/molecule/default/verify.yml
@@ -3,8 +3,36 @@
- name: Verify
hosts: all
+ become: true
gather_facts: false
tasks:
- - name: Example assertion
+ - name: Register Docker container status
+ community.docker.docker_container_info:
+ name: nginx
+ register: container_info
+
+ - name: Nginx Docker container assertion
ansible.builtin.assert:
- that: true
+ that:
+ - "container_info.exists"
+ - "container_info.container.State.Status == 'running'"
+ - "container_info.container.State.Running"
+ success_msg: "container OK"
+ fail_msg: "container NOT OK"
+
+ - name: Make a simple HTTP request
+ ansible.builtin.uri:
+ url: http://localhost:80
+ return_content: true
+ register: result
+
+ - name: HTTP request assertion
+ ansible.builtin.assert:
+ that:
+ - "result.status == 200"
+ success_msg: "HTTP request OK"
+ fail_msg: "HTTP request NOT OK"
+
+ - name: Print HTTP response
+ ansible.builtin.debug:
+ msg: "{{ result.content }}"
Finally, you can run the command molecule destroy to delete the VMs that we just created. This step will remove all the resources that were used during the testing process, making sure to keep everything clean.
Bonus: Linting Your Files with Molecule
Bonus: Linting Your Files with Molecule
Molecule can even lint your files, if you configure it! Add this to your molecule.yml:
$ git diff 74fdd3cb
--- a/molecule/default/molecule.yml
+++ b/molecule/default/molecule.yml
@@ -18,3 +18,8 @@ provisioner:
verifier:
name: ansible
+
+lint: |
+ set -e
+ yamllint .
+ ansible-lint
--- a/tasks/main.yml
+++ b/tasks/main.yml
@@ -6,7 +6,7 @@
source: pull
force_source: true
-- name: Start start nginx service via Docker
+- name: Start start nginx service via Docker # noqa args[module]
community.general.docker_container:
name: "{{ nginx_service_name }}"
image: "{{ nginx_image }}"
Congratulations, you have just set up Molecule in a project.
You can now run molecule test which will run all of the steps below and also check for idempotency. You can find our demo here:
Molecule Docker Demo (Github, Netresearch)
CI/CD
GitLab CI integration is also quite easy, as it simply requires running molecule test which does all of the above steps automatically. By automating the process, we save even more time and can ensure that our roles are always working as intended.
CI Configuration
$ cat .gitlab-ci.yml
---
stages:
- test
test:
stage: test
tags:
- molecule
script:
- molecule test -- --extra-vars "docker_registry_username=${CI_REGISTRY_USER}" --extra-vars "docker_registry_password=${CI_REGISTRY_PASSWORD}"
The benefits of using Molecule for testing ansible roles are many. For one, the setup is both easy and fast. Additionally, we save a lot of time by not having to set up isolated environments. We can set up controlled environments in a VM with Vagrant (controlled by the molecule-vagrant plugin) and deploy and test roles with Molecule.
With the help of Molecule and Vagrant, Ansible testing has never been easier