molecule Documentation

An ansible-native testing framework for collections, playbooks, and roles with configurable workflows for testing any system or service

RAW Doc

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:

bash
molecule ...
python3 -m molecule ...  # python module calling method

Documentation

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:

bash
git clone https://github.com/ansible/molecule && cd molecule
python3 -m venv .venv && source .venv/bin/activate
python3 -m pip install -U setuptools pip tox

And 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

text
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 and
destroy 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

yaml title="molecule.yml"
{!tests/fixtures/integration/test_command/molecule/docker/molecule.yml!}
yaml title="requirements.yml"
{!tests/fixtures/integration/test_command/molecule/docker/requirements.yml!}

Create playbook

yaml title="create.yml"
{!tests/fixtures/integration/test_command/molecule/docker/create.yml!}
yaml title="tasks/create-fail.yml"
{!tests/fixtures/integration/test_command/molecule/docker/tasks/create-fail.yml!}

Converge playbook

yaml title="converge.yml"
{!tests/fixtures/integration/test_command/molecule/docker/converge.yml!}

Destroy playbook

yaml title="destroy.yml"
{!tests/fixtures/integration/test_command/molecule/docker/destroy.yml!}

File: docs/examples/kubevirt.md

Using Kubevirt

!!! note

text
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 and
destroy 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 to false, 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.

yaml
---
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.io

You 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.yml Ansible 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

yaml title="molecule.yml"
{!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.
yaml title="requirements.yml"
{!tests/fixtures/integration/test_command/molecule/kubevirt/requirements.yml!}

Create playbook

yaml title="create.yml"
{!tests/fixtures/integration/test_command/molecule/kubevirt/create.yml!}
yaml title="tasks/create_vm.yml"
{!tests/fixtures/integration/test_command/molecule/kubevirt/tasks/create_vm.yml!}
yaml title="tasks/create_vm_dictionary.yml"
{!tests/fixtures/integration/test_command/molecule/kubevirt/tasks/create_vm_dictionary.yml!}

Converge playbook

yaml title="converge.yml"
{!tests/fixtures/integration/test_command/molecule/kubevirt/converge.yml!}

Destroy playbook

yaml title="destroy.yml"
{!tests/fixtures/integration/test_command/molecule/kubevirt/destroy.yml!}

File: docs/examples/podman.md

Using podman containers

!!! note

text
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:

yaml title="molecule.yml"
{!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.

yaml title="requirements.yml"
{!tests/fixtures/integration/test_command/molecule/podman/requirements.yml!}

Inventory Structure

Container definitions are managed through standard Ansible inventory:

yaml title="inventory/hosts.yml"
{!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.

yaml title="inventory/group_vars/molecule.yml"
{!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

yaml title="create.yml"
{!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.

yaml title="tasks/create-fail.yml"
{!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

yaml title="converge.yml"
{!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

yaml title="verify.yml"
{!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

yaml title="cleanup.yml"
{!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

yaml title="destroy.yml"
{!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:

  1. platforms[*].image: Docker image name:tag to use as base image.

  2. platforms[*].pre_build_image: Whether to customize base image or
    use as-is[^1].

    • When true, use the specified platform[].image as-is.

    • When false, exec docker build to customize base image
      using either:

      • Dockerfile specified by platforms[*].dockerfile or
      • Dockerfile rendered from Dockerfile.j2 template (in
        scenario dir)

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 %}

jinja
# 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.

docker
{% 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:

yaml
platforms:
  - name: instance
    image: quay.io/centos/centos:stream8
    # โ€ฆ
yaml
provisioner:
  name: ansible
  # โ€ฆ
  inventory:
    host_vars:
      # setting for the platform instance named 'instance'
      instance:
        ansible_user: ansible

Make sure to use your platform instance name. In this case
instance.

An example for a different platform instance name:

yaml
platforms:
  - name: centos8
    image: quay.io/centos/centos:stream8
    # โ€ฆ
yaml
provisioner:
  name: ansible
  # โ€ฆ
  inventory:
    host_vars:
      # setting for the platform instance named 'centos8'
      centos8:
        ansible_user: ansible

To 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.

yaml
- name: Create apps dir
  file:
    path: /opt/examples
    owner: ansible
    group: deployer
    mode: 0775
    state: directory
  # become: yes

Don'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.

bash
$ tree monolith-repo -L 3 --prune
monolith-repo
 โ”œโ”€โ”€ library
 โ”‚   โ””โ”€โ”€ foo.py
 โ”œโ”€โ”€ plugins
 โ”‚   โ””โ”€โ”€ filters
 โ”‚       โ””โ”€โ”€ foo.py
 โ””โ”€โ”€ roles
     โ”œโ”€โ”€ bar
     โ”‚   โ””โ”€โ”€ README.md
     โ”œโ”€โ”€ baz
     โ”‚   โ””โ”€โ”€ README.md
     โ””โ”€โ”€ foo
         โ””โ”€โ”€ README.md

The 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.

bash
cd monolith-repo/roles/baz
molecule test

Molecule is simply setting the ANSIBLE_* environment variables. To
view the environment variables set during a Molecule operation pass the
--debug flag.

bash
$ molecule --debug test

DEBUG: ANSIBLE ENVIRONMENT
---
ANSIBLE_CONFIG: /private/tmp/monolith-repo/roles/baz/molecule/default/.molecule/ansible.cfg

Molecule 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.

yaml
provisioner:
  name: ansible
  env:
    ANSIBLE_$VAR: $VALUE

File: docs/guides/parallel.md

Concurrent scenario execution with `--workers`

!!! warning

text
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

bash
# 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-1

Requirements

  • Collection mode -- --workers > 1 requires a valid galaxy.yml in the
    current directory (i.e., you must be in a collection).
  • Shared state -- scenarios should use shared_state: true in their
    molecule.yml so that the default scenario handles infrastructure
    create/destroy while workers run the test sequences.

How it works

  1. The default scenario's create runs first (serial, main process).
  2. Prerun tasks run for all scenarios (serial, main process).
  3. Scenarios are submitted to a ProcessPoolExecutor with the specified
    number of workers. Each worker reconstructs a Config from the
    scenario's molecule.yml and runs the scenario's sequence, skipping
    create and destroy (handled by the default scenario).
  4. Results are collected as workers complete.
  5. The default scenario's destroy runs 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:

bash
molecule test --all --workers 4 --continue-on-failure

Incompatible options

  • --workers > 1 cannot be combined with --destroy=never.

Legacy: `--parallel` isolation mode (deprecated)

!!! warning

text
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.

bash
# Deprecated -- use --workers instead
molecule test --parallel

Supported sequences: check, destroy, test.