File: README.md
About Ansible Molecule
Molecule is an Ansible testing framework designed for developing and testing
Ansible collections, playbooks, and roles.
Molecule leverages standard Ansible features including inventory, playbooks,
and collections to provide flexible testing workflows. Test scenarios can
target any system or service reachable from Ansible, from containers and
virtual machines to cloud infrastructure, hyperscaler services, APIs,
databases, and network devices. Molecule can also validate inventory
configurations and dynamic inventory sources.
Molecule encourages an approach that results in consistently developed
Ansible content that is well-written, easily understood and maintained.
Molecule supports only the latest two major versions of Ansible (N/N-1).
Once installed, the command line can be called using any of the methods
below:
molecule ...
python3 -m molecule ... # python module calling methodDocumentation
Read the documentation and more at https://docs.ansible.com/projects/molecule//.
Get Involved
See the Talk to us section of the documentation to ask questions, find help, and join the conversation.
For complete details, see the
Ansible communication guide.
If you want to get moving fast and make a quick patch:
git clone https://github.com/ansible/molecule && cd molecule
python3 -m venv .venv && source .venv/bin/activate
python3 -m pip install -U setuptools pip toxAnd you're ready to make your changes!
Authors
Molecule project was created by Retr0h and
it is now community-maintained as part of the
Ansible by Red Hat project.
License
The
MIT
License.
The logo is licensed under the Creative Commons NoDerivatives 4.0
License.
If you have some other use in mind, contact us.
File: collections/README.md
Collections
These collections are here for ansible-lint so the ansible-lint pre-commit action can install them prior to linting the repository.
File: docs/examples/docker.md
Using docker containers
!!! note
This example demonstrates the use of a pre-ansible-native configuration.
For ansible-native examples see the [Using podman containers](podman.md)
or [Ansible native inventory](ansible_native_inventory.md) examples.Below you can see a scenario that is using docker containers as test hosts.
When you run molecule test --scenario-name docker the create, converge anddestroy steps will be run one after another.
This example is using Ansible playbooks and it does not need any molecule
plugins to run. You can fully control which test requirements you need to be
installed.
Config playbook
{!tests/fixtures/integration/test_command/molecule/docker/molecule.yml!}{!tests/fixtures/integration/test_command/molecule/docker/requirements.yml!}Create playbook
{!tests/fixtures/integration/test_command/molecule/docker/create.yml!}{!tests/fixtures/integration/test_command/molecule/docker/tasks/create-fail.yml!}Converge playbook
{!tests/fixtures/integration/test_command/molecule/docker/converge.yml!}Destroy playbook
{!tests/fixtures/integration/test_command/molecule/docker/destroy.yml!}File: docs/examples/kubevirt.md
Using Kubevirt
!!! note
This example demonstrates the use of a pre-ansible-native configuration.
For ansible-native examples see the [Using podman containers](podman.md)
or [Ansible native inventory](ansible_native_inventory.md) examples.Below you can see a scenario that is using Kubevirt VMs as test hosts. For Ansible to connect with the SSH in the KubeVirt VMs, it will be made accessible through the Service NodePort.
When you run molecule test --scenario-name kubevirt the create, converge anddestroy steps will be run one after another.
This example is using Ansible playbooks and it does not need any molecule
plugins to run. You can fully control which test requirements you need to be
installed.
Prerequisites
The create.yml and destroy.yml Ansible playbooks require the Ansible collection kubernetes.core. For seamless communication with the Kubernetes API server, the collection uses the following environment variables:
K8S_AUTH_API_KEY: This is the token from the service account used to authenticate with the Kubernetes cluster.K8S_AUTH_HOST: This points to the URL of the Kubernetes cluster's API.K8S_AUTH_VERIFY_SSL: If set tofalse, this disables the verification of SSL/TLS certificates, which might pose a security risk. It's mainly used for testing environments, particularly when dealing with self-signed certificates.
Additionally, for the playbooks to work, the Kubernetes service account needs specific roles and role bindings to operate in a particular namespace. This ensures the playbook has sufficient privileges to execute commands on the Kubernetes resources. These roles include getting, listing, watching, creating, deleting, and editing virtual machines and services.
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: <Molecule Kubernetes Serviceaccount>
namespace: <Kubernetes VM Namespace>
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: <Kubernetes VM Namespace>
name: <Molecule Kubernetes Role>
rules:
- apiGroups: ["kubevirt.io"]
resources: ["virtualmachines"]
verbs: ["get", "list", "watch", "create", "delete", "patch", "edit"]
- apiGroups: [""]
resources: ["services"]
verbs: ["get", "list", "watch", "create", "delete", "patch", "edit"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: <Molecule Kubernetes Rolebinding>
namespace: <Kubernetes VM Namespace>
subjects:
- kind: ServiceAccount
name: <Molecule Kubernetes Serviceaccount>
namespace: <Kubernetes VM Namespace>
roleRef:
kind: Role
name: <Molecule Kubernetes Role>
apiGroup: rbac.authorization.k8s.ioYou will need to substitute the following placeholders:
<Molecule Kubernetes Serviceaccount>: This refers to the name of the Kubernetes Serviceaccount that the molecule test utilizes to create the KubeVirt VM.<Kubernetes VM Namespace>: This denotes the name of the Kubernetes namespace where the VMs will be instantiated.<Molecule Kubernetes Role>: This is the name of the Kubernetes role which encapsulates the necessary permissions for the molecule test to function.<Molecule Kubernetes Rolebinding>: This represents the name of the Kubernetes rolebinding that associates the role<Molecule Kubernetes Role>with the serviceaccount<Molecule Kubernetes Serviceaccount>.
Considerations
- This example is using ephemeral VMs, which enhance the speed of VM creation and cleanup. However, it is important to note that any data in the system will not be retained if the VM is rebooted.
- You don't need to worry about setting up SSH keys. The
create.ymlAnsible playbook takes care of configuring a temporary SSH key. - The hostname for SSH connection to the VM is fetched dynamically, which is the K8S node where the VM is running.
Config playbook
{!tests/fixtures/integration/test_command/molecule/kubevirt/molecule.yml!}Please, replace the following parameter:
<Kubernetes VM Namespace>: This should be replaced with the namespace in Kubernetes where you intend to create the KubeVirt VMs.
{!tests/fixtures/integration/test_command/molecule/kubevirt/requirements.yml!}Create playbook
{!tests/fixtures/integration/test_command/molecule/kubevirt/create.yml!}{!tests/fixtures/integration/test_command/molecule/kubevirt/tasks/create_vm.yml!}{!tests/fixtures/integration/test_command/molecule/kubevirt/tasks/create_vm_dictionary.yml!}Converge playbook
{!tests/fixtures/integration/test_command/molecule/kubevirt/converge.yml!}Destroy playbook
{!tests/fixtures/integration/test_command/molecule/kubevirt/destroy.yml!}File: docs/examples/podman.md
Using podman containers
!!! note
This example demonstrates the use of an ansible-native configuration.This example demonstrates testing with Podman containers using standard Ansible inventory and playbooks for complete control over the testing environment.
Overview
This scenario uses:
- Inventory management: Standard Ansible inventory files for container definitions
- Container lifecycle: Managed through Ansible playbooks with full customization
- Flexible configuration: Container settings defined in inventory for easy modification
When you run molecule test --scenario-name podman, Molecule executes the complete test sequence including create, converge, verify, cleanup, and destroy steps using your custom playbooks.
Configuration
The configuration uses standard Ansible patterns:
{!tests/fixtures/integration/test_command/molecule/podman/molecule.yml!}Key points: The ansible section configures inventory location and executor arguments. The default driver indicates pure Ansible automation without Molecule-specific drivers.
{!tests/fixtures/integration/test_command/molecule/podman/requirements.yml!}Inventory Structure
Container definitions are managed through standard Ansible inventory:
{!tests/fixtures/integration/test_command/molecule/podman/inventory/hosts.yml!}Key points: Containers are defined as inventory hosts with connection and configuration details. The molecule group contains test targets.
{!tests/fixtures/integration/test_command/molecule/podman/inventory/group_vars/molecule.yml!}Key points: Group variables provide shared configuration for container settings.
Lifecycle Playbooks
Create Playbook
{!tests/fixtures/integration/test_command/molecule/podman/create.yml!}Key points: Creates containers based on inventory definitions using hostvars for configuration. Includes error handling and connection verification.
{!tests/fixtures/integration/test_command/molecule/podman/tasks/create-fail.yml!}Key points: Error handling task that displays container logs when creation fails.
Converge Playbook
{!tests/fixtures/integration/test_command/molecule/podman/converge.yml!}Key points: Validates inventory structure, gathers facts from containers, reads OS information, and writes data to a temporary file for verification. Uses proper Ansible modules instead of raw commands thanks to the Python-enabled container image.
Verify Playbook
{!tests/fixtures/integration/test_command/molecule/podman/verify.yml!}Key points: Reads the temporary file created during converge, verifies the container OS is Fedora-based, and validates the dev tools environment variable. Demonstrates comprehensive container testing and validation.
Cleanup Playbook
{!tests/fixtures/integration/test_command/molecule/podman/cleanup.yml!}Key points: Intelligently removes temporary files created during testing, but only when containers exist and are running. Includes robust error handling for edge cases.
Destroy Playbook
{!tests/fixtures/integration/test_command/molecule/podman/destroy.yml!}Key points: Cleanly removes containers using inventory host definitions with error handling.
Benefits
- Standard practices: Uses familiar Ansible inventory and playbook patterns
- Full control: Complete customization of container lifecycle and configuration
- Modern tooling: Leverages Python-enabled container images for full Ansible module support
- Comprehensive testing: Includes converge, verify, and cleanup phases for thorough validation
- Reusable: Inventory can be shared across multiple scenarios
- Maintainable: Clear separation of concerns between configuration and automation
- Flexible: Easy to extend with additional container settings, networking, or testing logic
- Robust: Intelligent error handling and conditional execution for reliable testing
This approach provides the foundation for more complex testing scenarios while maintaining simplicity and demonstrating modern ansible-native practices with comprehensive lifecycle management.
File: docs/guides/custom-image.md
Customizing the Docker Image Used by a Scenario/Platform
The docker driver supports using pre-built images and docker build
-ing local customizations for each scenario's platform. The Docker
image used by a scenario is governed by the following configuration
items:
platforms[*].image: Docker image name:tag to use as base image.platforms[*].pre_build_image: Whether to customize base image or
use as-is[^1].When
true, use the specifiedplatform[].imageas-is.When
false, execdocker buildto customize base image
using either:- Dockerfile specified by
platforms[*].dockerfileor - Dockerfile rendered from
Dockerfile.j2template (in
scenario dir)
- Dockerfile specified by
To customize the Docker image, create a Dockerfile.j2 template file in your scenario directory. Molecule renders this template to build the image for the scenario.
Here is a commonly used example Dockerfile.j2 that substitutes the base image defined in molecule.yml and installs basic dependencies:
{% raw %}
# The `item` variable contains the platform configuration from molecule.yml
FROM {{ item.image }}
# Install basic dependencies (example for Debian/Ubuntu based images)
RUN apt-get update && apt-get install -y python3 sudo bash \
&& rm -rf /var/lib/apt/lists/*{% endraw %}
Note: platforms[*].pre_build_image defaults to true in each
scenario's generated molecule.yml file. You must set it to false in your platform configuration to instruct Molecule to build the custom image.
[^1]:
Implementation in molecule docker
driver
File: docs/guides/docker-rootless.md
Docker With Non-Privileged User
The Molecule Docker driver executes Ansible playbooks as the
root user. If your workflow requires adding support for running as a
non-privileged user, then adapt molecule.yml and Dockerfile.j2 as
follows.
Note: The Dockerfile templating and image building processes are only
done for scenarios with pre_build_image = False, which is not the
default setting in generated molecule.yml files.
To modify the Docker image to support running as a normal user:
Append the following code block to the end of Dockerfile.j2. It
creates an ansible user with passwordless sudo privileges. Note the
variable SUDO_GROUP depends on the target distribution as Debian uses sudo
instead of wheel group.
{% raw %}
# Create `ansible` user with sudo permissions and membership in `DEPLOY_GROUP`
# This template gets rendered using `loop: "{{ molecule_yml.platforms }}"`, so
# each `item` is an element of platforms list from the molecule.yml file for this scenario.
ENV ANSIBLE_USER=ansible DEPLOY_GROUP=deployer
ENV SUDO_GROUP={{'sudo' if 'debian' in item.image else 'wheel' }}
RUN set -xe \
&& groupadd -r ${ANSIBLE_USER} \
&& groupadd -r ${DEPLOY_GROUP} \
&& useradd -m -g ${ANSIBLE_USER} ${ANSIBLE_USER} \
&& usermod -aG ${SUDO_GROUP} ${ANSIBLE_USER} \
&& usermod -aG ${DEPLOY_GROUP} ${ANSIBLE_USER} \
&& sed -i "/^%${SUDO_GROUP}/s/ALL\$/NOPASSWD:ALL/g" /etc/sudoers
{% endraw %}Modify provisioner.inventory in molecule.yml as follows:
platforms:
- name: instance
image: quay.io/centos/centos:stream8
# โฆprovisioner:
name: ansible
# โฆ
inventory:
host_vars:
# setting for the platform instance named 'instance'
instance:
ansible_user: ansibleMake sure to use your platform instance name. In this caseinstance.
An example for a different platform instance name:
platforms:
- name: centos8
image: quay.io/centos/centos:stream8
# โฆprovisioner:
name: ansible
# โฆ
inventory:
host_vars:
# setting for the platform instance named 'centos8'
centos8:
ansible_user: ansibleTo test it, add the following task to tasks/main.yml. It fails,
because the non-privileged user is not allowed to create a folder in/opt/. This needs to be performed using sudo.
To perform the task using sudo, uncomment become: yes. Now the task
will succeed.
- name: Create apps dir
file:
path: /opt/examples
owner: ansible
group: deployer
mode: 0775
state: directory
# become: yesDon't forget to run molecule destroy if image has already been
created.
File: docs/guides/inside-a-container.md
Running inside a container
Molecule is built into a Docker image by the Ansible Dev Tools project.
Any questions or bugs related to use of Molecule from within a container
should be addressed by the Ansible Dev Tools
project.
File: docs/guides/monolith.md
Monolith Repo
Molecule is generally used to test playbooks or roles in isolation.
However, it can also test them from a monolith repo.
$ tree monolith-repo -L 3 --prune
monolith-repo
โโโ library
โ โโโ foo.py
โโโ plugins
โ โโโ filters
โ โโโ foo.py
โโโ roles
โโโ bar
โ โโโ README.md
โโโ baz
โ โโโ README.md
โโโ foo
โโโ README.mdThe role initialized with Molecule (baz in this case) would simply
reference the dependent roles via its converge.yml or meta
dependencies.
Molecule can test complex scenarios leveraging this technique.
cd monolith-repo/roles/baz
molecule testMolecule is simply setting the ANSIBLE_* environment variables. To
view the environment variables set during a Molecule operation pass the--debug flag.
$ molecule --debug test
DEBUG: ANSIBLE ENVIRONMENT
---
ANSIBLE_CONFIG: /private/tmp/monolith-repo/roles/baz/molecule/default/.molecule/ansible.cfgMolecule can be customized any number of ways. Updating the
provisioner's env section in molecule.yml to suit the needs of the
developer and layout of the project.
provisioner:
name: ansible
env:
ANSIBLE_$VAR: $VALUEFile: docs/guides/parallel.md
Concurrent scenario execution with `--workers`
!!! warning
This functionality should be considered experimental.When testing Ansible collections with many scenarios, Molecule can run
scenarios concurrently using the --workers flag. This uses a process
pool to execute multiple scenarios in parallel while the default
scenario's create and destroy lifecycle runs serially in the main
process.
Usage
# Run with 4 concurrent workers
molecule test --all --workers 4
# Use all available CPU cores
molecule test --all --workers cpus
# Use all cores minus one (leaves headroom for the system)
molecule test --all --workers cpus-1Requirements
- Collection mode --
--workers> 1 requires a validgalaxy.ymlin the
current directory (i.e., you must be in a collection). - Shared state -- scenarios should use
shared_state: truein theirmolecule.ymlso that the default scenario handles infrastructure
create/destroy while workers run the test sequences.
How it works
- The default scenario's
createruns first (serial, main process). - Prerun tasks run for all scenarios (serial, main process).
- Scenarios are submitted to a
ProcessPoolExecutorwith the specified
number of workers. Each worker reconstructs aConfigfrom the
scenario'smolecule.ymland runs the scenario's sequence, skippingcreateanddestroy(handled by the default scenario). - Results are collected as workers complete.
- The default scenario's
destroyruns last (serial, main process).
Failure handling
By default, Molecule uses fail-fast behavior: when a scenario fails,
no new scenarios are started (workers already running finish their
current scenario), then destroy runs.
Use --continue-on-failure to run all remaining scenarios even after a
failure:
molecule test --all --workers 4 --continue-on-failureIncompatible options
--workers> 1 cannot be combined with--destroy=never.
Legacy: `--parallel` isolation mode (deprecated)
!!! warning
The `--parallel` flag is deprecated and will be removed in a future
release. Use `--workers` instead for native concurrent execution.The --parallel flag provides process isolation (UUID-based
ephemeral directories, platform name suffixing, file locking) so that
external tools like GNU Parallel
or Pytest can orchestrate multiple
Molecule processes without conflicts. Molecule itself does not spawn
concurrent work in this mode.
# Deprecated -- use --workers instead
molecule test --parallelSupported sequences: check, destroy, test.