How to Test Ansible Roles with Molecule and Docker

Ansible Molecule is a tool used for testing and validating Ansible roles and playbooks in multiple scenarios. It helps automate the testing of Ansible code and ensures that it will work as intended when applied to target servers. With Molecule, you can test roles and playbooks across different environments and platforms. supports different virtualization and containerization technologies such as Docker, Podman, Vagrant, and cloud providers such as Amazon Web Services, Microsoft Azure, and Google Cloud Platform.

Ansible Molecule is a powerful tool for automating and streamlining the testing and validation of Ansible roles and playbooks. It uses a testing framework such as pytest and provides an environment for the role or playbook to run in.

In this tutorial, you will learn how to set up and test Ansible Roles automatically via Molecule and Docker. You will install Ansible, Docker, and Molecule at the same time, then you will learn how to create an Ansible Roles boilerplate with Molecule and set up automatic testing of Ansible Roles via Docker containers.

Prerequisites

To complete this tutorial, you must have the following requirements:

  • A Linux system - This example uses the latest version of Ubuntu 22.04 server with hostname 'ansible-test'.
  • A non-root user with sudo/root administrator privileges - This example uses a user called 'alice'.
  • Understanding of Ansible and Ansible Roles.

Installing Dependencies

In the first section, you will install package dependencies that will be used in the following guide. This includes Python3, Pip, Ansible, and Docker CE (Community Edition). Before you start, run the following command to update and refresh your package index.

sudo apt update

Once the package index is updated, enter the following command to install Python3, Pip3, Virtualenv, and Ansible.

sudo apt install python3 python3-pip python3-venv ansible ca-certificates curl gnupg lsb-release

Input y when prompted and press ENTER to proceed.

install dependnecies

After Python3, Pip3, Virtualenv, and Ansible are installed, you will be installing the Docker CE (Community Edition) via the official Docker Repository.

Enter the following command to create a new directory '/etc/apt/keyrings' and download the GPG key of the Docker repository.

sudo mkdir -m 0755 -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

Next, add the Docker CE repository to your system using the below command.

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Add docker repo

Then update and refresh your ubuntu package index to apply the changes.

sudo apt update

Now install Docker CE packages via the following 'apt' command below. When prompted, input y to confirm and press ENTER to proceed.

sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

install docker

With the Docker CE installed, add your current user to the group 'docker' using the following command. This will allow your user to run Docker containers.

sudo usermod -aG docker $USER

You can now verify the Docker configuration using the command below. This will download and run the container 'hello-world' on your system.

docker run hello-world

If the user can execute Docker containers, you should see the output of the 'hello-world' container as below.

docker run hello world

With this, you have now installed package dependencies such as Python3, Pip3, Virtualenv, Ansible, and Docker. In the next section, you will install Molecule within the Python virtual environment.

Installing Molecule

In this section, you will create a new Python virtual environment that will be used for the development environment of Ansible Roles. You will also install Molecule and the Docker driver.

Run the following command to create a new Python virtual environment called 'ansible-venv'. Once the virtual environment is created, you should see the new directory 'ansible-venv' on your current working directory.

python3 -m venv ansible-venv

Next, run the below command to activate your Python virtual environment. Once activated, your prompt shell will become like this: '(ansible-venv) user@hostname:...'.

source ansible-venv/bin/activate

Now move your working directory to 'ansible-venv', then install Python packages Molecule and the Molecule Docker driver using the 'pip3' command as below.

cd ansible-venv/
pip3 install wheel molecule 'molecule-plugins[docker]'

Below you can see the installation process of Molecule and the Docker driver.

install molecule and docker driver

After the Molecule and Docker driver are installed, you will next create a new Ansible Role via Molecule.

Initializing Ansible Role with Molecule

After installing Molecule and the Docker driver, you will now create new Ansible Roles via molecule. In this example, you will create roles that will be used to install basic LEMP Stack (Linux, Nginx, MariaDB, and PHP-FPM) packages and ensure that LEMP Stack services are running and enabled.

First, run the following command to generate the Ansible Role boilerplate called 'test.lemp' with the driver 'docker'. This will create a new directory called 'lemp' on your current working directory.

molecule init role test.lemp --driver-name docker

generate ansible role boilerplate molecule

Move to the 'lemp' directory using the below command.

cd lemp

Open the file 'tasks/main.yml' using the nano editor and define some tasks for your role.

nano tasks/main.yml

Add the following lines to the file. With this, you will create tasks for installing LEMP Stack packages and verifying LEMP services.

---
- name: "Installing LEMP Stack"
  apt:
    name: "{{ pkg_list }}"
    state: present

- name: "Ensure LEMP Services is running"
  service:
    name: "{{ item }}"
    state: started
    enabled: true
  with_items: "{{ svc_list }}"

Save and close the file when finished.

install lemp tasks

Now open the file 'vars/main.yml' using the nano editor and add variables for your Ansible roles.

nano vars/main.yml

Add the following lines to the file. In this example, you will define the variable 'pkg_list' that contains package names of the LEMP stack, and the variable 'svc_list' that contains the services name of the LEMP Stack.

---
pkg_list:
  - nginx
  - mariadb-server
  - php-fpm
  - php-cli
svc_list:
  - nginx
  - mariadb
  - php8.1-fpm

Save the file and exit the editor when finished.

variable lis packages

Setting Up Instance for Testing

After creating Ansible roles, you will need to set up the instance that will be used to test Ansible roles. This example will be using the Docker image 'mipguerrero26/ubuntu-python3', which by default contains the Python3 package. You can use different Docker images, but you must ensure that Python is installed.

First, run the following command to download the Docker image 'mipguerrero26/ubuntu-python3'.

docker pull mipguerrero26/ubuntu-python3

download docker image

Once downloaded, verify the list of images using the below command. You should see the Docker image 'mipguerrero26/ubuntu-python3' is downloaded and available on your system.

docker images

list image

Now run the following command to run a temporary container and execute bash in the attached mode.

docker run -it mipguerrero26/ubuntu-python3 /bin/bash

Once logged in to the container, enter the following command to verify the Python and Ubuntu version.

python3 --version
cat /etc/lsb-release

You should receive an output like this - In this example, the image 'mipguerrero26/ubuntu-python3' is based on Ubuntu 22.04 and comes with Python.

verify python image

Type 'exit' to log out from the container shell.

Next, open the default Molecule configuration 'molecule/default/molecule.yml' using the nano editor.

nano molecule/default/molecule.yml

On the 'platform' section, change the name and the default image that will be used for testing. Also, add the setting 'privileged: true'. In this example, the instance for testing will be named 'instance-ubuntu22.04' with the image 'mipguerrero26/ubuntu-python3'.

platforms:
  - name: instance-ubuntu22.04
    image: mipguerrero26/ubuntu-python3
    privileged: true

Save the file and exit the editor.

molecule instance setting

Now run the 'molecule' command below to verify the list of instances within your Molecule test project. You should see the instance called 'instance-ubuntu22.04' with the driver 'Docker'.

molecule list

list molecule instance ready to test

Running Molecule Test Converge

With the Molecule instance created, you can now run the test by simply invoking the command 'molecule converge' as below. This 'converge' parameter allows you to test and verify Ansible roles against the instance that is available on your Molecule project. In this example, the Ansible role 'lemp' will be run against the instance 'instance-ubuntu22.04' via Docker.

molecule converge

Below is an output when the Molecule is running.

molecule running test

The Molecule task is to create a new instance via Docker for testing.

create container instance

Once the instance is created, the Ansible roles will be applied against the instance.

applying role

At this point, the Ansible role 'lemp' is applied to the instance 'instance-ubuntu22.04', which is running via Docker. Enter the following command to verify the running container on your system.

docker ps

You should see the container called 'instance-ubuntu22.04', which is matched with the Molecule instance name.

list container

Now log in to the container 'instance-ubuntu22.04' using the following command.

docker exec -it instance-ubuntu22.04 /bin/bash

Then verify the list of open ports on the container using the below command. You should see port 80 used by Nginx, port 3306 used by MariaDB, and the PHP-FPM running with the sock file '/run/php/php8.1-fpm.sock'. This confirms that the role 'lemp' is running successfully.

ss -tulpn
ss -pl | grep php

verify process on container

Lastly, run the following command to clean up your environment. This will destroy and remove the container 'instance-ubuntu22' from your system.

molecule destroy

destroy container instance

If you check the list of running containers on your system, there will be no running container, because the instance 'instance-ubuntu22' is removed.

docker ps
docker ps -a

container destroyed

Create Test Script with testInfra Python Module

In this section, you will create the test script scenario that will be used to verify the state of the Molecule instance and ensure that roles are applied. This can be done with Python script with the module testInfra.

First, run the following pip3 command to install the testInfra module.

pip3 install pytest-testinfra

install testInfra module

Once the testinfra module is installed, create a new directory 'molecule/default/tests/', and create a new test file 'molecule/default/tests/test_default.py' using the following nano editor command.

mkdir -p molecule/default/tests/
nano molecule/default/tests/test_default.py

Add the following Python script to the file. With this, you will test the Ansible Molecule instance to ensure that LEMP Stack packages are installed and running.

import os
import pytest
import testinfra.utils.ansible_runner

testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
    os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all')

@pytest.mark.parametrize('pkg', [
  'nginx',
  'mariadb-server',
  'php-fpm'
])
def test_pkg(host, pkg):
    package = host.package(pkg)

    assert package.is_installed

@pytest.mark.parametrize('svc', [
  'nginx',
  'mariadb',
  'php8.1-fpm'
])
def test_svc(host, svc):
    service = host.service(svc)

    assert service.is_running
    assert service.is_enabled

Save and close the file when finished.

create test script

Next, open the Molecule config file 'molecule/default/molecule.yml' using the nano editor to define the test.

nano molecule/default/molecule.yml

On the 'verifier' section, change the name to 'testinfra' and add the parameter 'directory: tests'. This means that the test script will be taken from the directory 'tests'.

verifier:
  name: testinfra
  directory: tests

Save the file and exit the editor.

apply test

Now execute the following command to run the test with all scenarios from start to end. The 'molecule test' command will start testing by creating the instance, applying for the Ansible role, running the test, then destroying everything to clean up.

molecule test

Below is the screenshot when the 'test' command is initialized, the Ansible Molecule will destroy the existing instance if available.

run test

destroy when available

Now the process of creating an instance for new testing.

create new instance

Then the Ansible role will be applied against the instance.

apply role

When the roles are applied, the test or verifier will begin. When successful, you should get an output such as 'collected 6 items - 6 passed in ...'.

run tests

Lastly, the Molecule will destroy the instance when the test is finished.

destroy instance when finished

Ansible Molecule Process in Development

When first developing roles, you must ensure that the role is generated via Molecule. Then, you can add tasks and others components to your Ansible role, define the instance for testing, then set up the test script to ensure that the desired state is applied to the target instance.

So, when you have finished the configuration of an Ansible role and defined the instance, run the following command to test the implementation of the Ansible role in your test instance.

molecule converge

Now after creating the test script and defining the test on the Molecule configuration, run the following command to apply the test.

molecule verify

When the test was successful, you can now destroy everything and retest using the command below.

molecule destroy
molecule test

You can check the detailed available paramaters of Ansible Molecule via the command below.

molecule --help

Conclusion

In this tutorial, you have learned the installation of Ansible Molecule that allows you to perform end-to-end testing of Ansible role and playbook via multiple scenarios. You have also learned how to create roles via Molecule and run testing of the Ansible role with Docker. Lastly, you have also learned how to create a Python test script with module testInfra that can be used to verify the state of desired machines/servers.

In the end, you now better understand how to test Ansible roles and work with Molecule and Docker. Learn more about Ansible Molecule by visiting the official documentation of Ansible Molecule.

Share this page:

0 Comment(s)