Setting up Ansible with Molecule

Hi! My name is Arpit, and I'm a Software Engineer turned Product Manager. I use this platform to share my learnings in various different fields of interest.
If you're like me and are trying to learn Ansible, you know how cumbersome it is to test. To test your playbook, you setup a cloud instance, run your ansible playbook, verify everything and then delete the instance either to save money or get a clean slate for your next testing scenario.
However, there is a better way. Ansible comes with its own testing framework called Molecule. To test ansible playbooks, Molecule first creates one or more virtual environments on your system, runs the ansible playbook against them, verifies everything using another ansible playbook and finally destroys the virtual environments.
In this blog, I'm going to share how to setup an ansible development environment with Molecule. This blog is heavily inspired by the official ansible molecule documentation.
Requirements:
Python installed on your system.
Step 1: Create python virtual environment
a.) In your project directory, create a folder. We'll name it pyvenv. Then create the python virtual environment using python -m venv /path/to/your/directory
mkdir pyvenv
python3 -m venv pyvenv
b.) Activate the python venv
source pyvenv/bin/activate
Step 2: Install molecule and dependencies
a.) Install required packages in the pyvenv environment
pip3 install molecule
Installing molecule will automatically install ansible as its a dependency.
b. ) Check everything:
molecule --version
Result:
molecule 24.2.1 using python 3.12
ansible:2.17.0
default:24.2.1 from molecule
Step 3: Create ansible collection and role
In older blogs, you might see the command molecule init role example-role to create ansible roles. This command basically executed ansible-galaxy command in the background to create a proper directory structure for the role, but later ansible removed it because it was redundant.
a.) Create new collection
IMPORTANT: According the official documentation, a new collection must be placed under a collections/ansible_collections directory. If your collection is not in this directory structure, molecule won't be able to find your collection.
We'll name our collection my.cloud
mkdir collections
cd collections
mkdir ansible_collections
cd ansible_collections
ansible-galaxy collection init my.cloud
b.) Create role
cd my/cloud/roles
ansible-galaxy role init test_role
c.) Add the following test task in the test_role/tasks/main.yml file:
---
- name: Task is running from within the role
ansible.builtin.debug:
msg: "This is a task from test_role."
Step 4: Create a playbook
a.) Create playbook.yml file in the collection root i.e. the cloud folder
mkdir playbooks
cd playbooks
touch playbook.yml
b.) Edit the playbook.yml file and add the following:
---
- name: Test new role from within this playbook
hosts: localhost
gather_facts: false
tasks:
- name: Testing role
ansible.builtin.include_role:
name: test_role
tasks_from: main.yml
Step 5: Adding molecule to the collection
a.) Create new folder extensions in the collection root and initiate molecule
cd ..
mkdir extensions
cd extensions
molecule init scenario test_scenario
Inside the molecule directory a folder called test_scenario was created. That’s the name of the scenario we defined. If we don’t specify a scenario name, the directory will be called default .
.
└── molecule
└── test_scenario
├── converge.yml
├── create.yml
├── destroy.yml
└── molecule.yml
Make sure your final directory structure is similar to the one shown below, if not, you might get issues running Molecule.
.
└── collections
└── ansible_collections
└── my
└── cloud
├── docs
├── extensions
│ └── molecule
│ └── test_scenario
├── meta
├── playbooks
├── plugins
└── roles
└── test_role
├── defaults
├── files
├── handlers
├── meta
├── tasks
├── templates
├── tests
└── vars
Step 6: Configuring molecule
a.) Edit the molecule.yml to configure docker
---
driver:
name: default
platforms:
- name: instance
# you might want to add your own variables here based on what provisioning
# you are doing like:
image: ubuntu:latest
b.) Update converge.yml to test our playbook/role
converge.yml is where you tell molecule what to test. Add one of the following in the converge.yml
To test the whole playbook:
---
# To test the whole playbook
- name: Include a playbook from a collection
ansible.builtin.import_playbook: my.cloud.playbook
To test just a role:
---
# To test a role
- name: Test new role from within this playbook
hosts: localhost
gather_facts: false
tasks:
- name: Testing role
ansible.builtin.include_role:
name: my.cloud.test_role
tasks_from: main.yml
c.) Run molecule test
molecule test -s test_scenario
