Testing Ansible roles is a crucial step in ensuring the reliability and correctness of your infrastructure automation. Among the various tools available for this purpose, Molecule stands out as a versatile framework for testing Ansible roles. When coupled with Podman, a containerization tool similar to Docker, it provides a seamless and efficient environment for testing Ansible roles on Debian Linux. In this blog post, we will explore the process of setting up Molecule with Podman on Debian Linux.

If you want to engage in a conversation with fellow techies, then don’t forget to join my Discord: https://discord.gg/YbSYGsQY
Why Molecule and Podman?
Molecule is a powerful tool that simplifies the testing of Ansible roles by creating isolated environments for role testing. It supports a wide range of containerization and virtualization providers, and one of the most popular choices is Podman, an open-source container management tool.
Here are some key reasons why using Molecule with Podman for Ansible role testing is a winning combination:
- Isolation: Molecule creates clean, isolated environments for testing Ansible roles, preventing interference with your local system.
- Reproducibility: With Podman containers, you can replicate the exact test environment across different systems, ensuring consistent results.
- Efficiency: Podman is a lightweight alternative to Docker, which consumes fewer resources and is well-suited for testing purposes.
- Compatibility: Using Podman allows you to test your roles on systems that support the Podman container runtime, including Debian Linux.
Prerequisites
Before getting started, make sure you have the following prerequisites in place:
- A working installation of Ansible (PIP magic).
- Molecule and Podman installed on your system (PIP and APT magic).
- A basic understanding of Ansible roles and how to structure them (brain magic).
- An Ansible role with a properly configured “Galaxy Style” meta information.
Testing With Podman
In the Ansible role’s directory initiate a test scenario. In the past Molecule was able to create ansible roles too, but they changed this function and you have to use ansible-galaxy command for creating new roles. I have an already working common role, I will present the process on it.
All of the operations below happen in the Ansible role’s root directory (in my case the /home/tmolnar/ansible/roles/common)!
molecule init scenario -d podman
It will create a new directory and file structure under the molecule directory. Molecule creates test scenarios, and with the above command it created the default scenario. If you want to name your scenario anything else, give it a name after the command:
molecule init scenario [OPTIONS] [SCENARIO_NAME]
The most important files created here are:
molecule.yml– this is the configuration of our Molecule scenario.create.yml– this playbook creates the environment, in this case the Podman containers for Ansible testing.destroy.yml– this playbook removes the test containers and the temporary inventory for the tests.converge.yml– this playbook contains the actual testing, here you include your role to be tested.
The most basic molecule.yml file for this scenario must contain the dependencies of the role to be tested (the requirements.yml file), and the platforms that is a custom built Debian Bookworm image in my case.
Most of the code below can be found in the documentation of Molecule. I made minor modifications for my environment.
# molecule.yml
---
dependency:
name: galaxy
options:
requirements-file: requirements.yml
platforms:
- name: molecule-debian12-test
image: tmolnar-debian:1.3
The creation of the test containers handled by the create.yml file.
# create.yml
---
- name: Create
hosts: localhost
gather_facts: false
vars:
molecule_inventory:
all:
hosts: {}
molecule: {}
tasks:
- name: Create a container
containers.podman.podman_container:
name: "{{ item.name }}"
image: "{{ item.image }}"
state: started
command: sleep 1d
log_driver: json-file
register: result
loop: "{{ molecule_yml.platforms }}"
- name: Fail if container is not running
when: >
item.container.State.ExitCode != 0 or
not item.container.State.Running
ansible.builtin.include_tasks:
file: tasks/create-fail.yml
loop: "{{ result.results }}"
loop_control:
label: "{{ item.container.Name }}"
- name: Add container to molecule_inventory
vars:
inventory_partial_yaml: |
all:
children:
molecule:
hosts:
"{{ item.name }}":
ansible_connection: containers.podman.podman
ansible.builtin.set_fact:
molecule_inventory: >
{{ molecule_inventory | combine(inventory_partial_yaml | from_yaml) }}
loop: "{{ molecule_yml.platforms }}"
loop_control:
label: "{{ item.name }}"
- name: Dump molecule_inventory
ansible.builtin.copy:
content: |
{{ molecule_inventory | to_yaml }}
dest: "{{ molecule_ephemeral_directory }}/inventory/molecule_inventory.yml"
mode: '0600'
- name: Force inventory refresh
ansible.builtin.meta: refresh_inventory
- name: Fail if molecule group is missing
ansible.builtin.assert:
that: "'molecule' in groups"
fail_msg: |
molecule group was not found inside inventory groups: {{ groups }}
run_once: true # noqa: run-once[task]
To remove the unnecessary test containers the destroy.yml playbook is going to be called.
# destroy.yml
---
- name: Destroy molecule containers
hosts: molecule
gather_facts: false
tasks:
- name: Stop and remove container
delegate_to: localhost
containers.podman.podman_container:
name: "{{ inventory_hostname }}"
state: absent
rm: true
- name: Remove potentially stopped container
delegate_to: localhost
ansible.builtin.command:
cmd: podman container rm --ignore {{ inventory_hostname }}
changed_when: false
- name: Remove dynamic molecule inventory
hosts: localhost
gather_facts: false
tasks:
- name: Remove dynamic inventory file
ansible.builtin.file:
path: "{{ molecule_ephemeral_directory }}/inventory/molecule_inventory.yml"
state: absent
With the create and destroy files you have the general availability of containers, but no testing has happened yet.
The most basic test scenario will simply include the role to be tested (my common role here) in the converge.yml file.
# converge.yml
---
- name: Converge
hosts: molecule
gather_facts: false
vars:
common_hostname: testhost
common_interface: enp3s1
common_ip: 1.2.3.4
common_gateway: 3.4.5.6
tasks:
- name: Check the role
ansible.builtin.include_role:
name: common
tasks_from: main.yml
The above code is a very basic test case indeed, it includes the common role in the tasks section, and it has some pre-configured variables provided in the vars section.
The default scenario test matrix follows the following process: dependency, cleanup, destroy, syntax, create, prepare, converge, idempotence, side_effect, verify, cleanup, destroy.
At this point I have covered the steps with bold text from this procedure.
From this point you can run a full automated test that executes the role in a container and then Molecule removes the container and data at the end of the test with the following command:
molecule test
Whenever I want to keep the test container intact then Molecule can be started with:
molecule converge
The container will remain in a running state on the system and I can look around/debug in it. After finishing the work the
molecule destroy
command is going to remove the traces of this temporary environment.
Conclusion
This is just the tip of the iceberg, I just scratched the very basics of Molecule testing, though this infrastructure opens up a whole new world of possibilities in your DevOps journey.
Using Molecule with Podman simplifies and enhances the process of testing Ansible roles on Debian Linux. With this setup, you can quickly and confidently verify the functionality of your roles in isolated, reproducible environments. Whether you’re developing roles for Apache, Nginx, or any other service, Molecule and Podman provide a robust framework for role testing, helping you ensure the reliability of your infrastructure automation.
If you want to engage in a conversation with fellow techies, then don’t forget to join my Discord: https://discord.gg/YbSYGsQYES