Skip to content

Molecule Framework

Overview

Solti-Monitoring uses Molecule for automated testing of Ansible roles across multiple platforms and scenarios.

What is Molecule?

Molecule is a testing framework for Ansible roles that provides:

  • Automated testing: Test roles in isolated environments
  • Multiple platforms: Test on different OS distributions
  • Scenario-based testing: Different test configurations per scenario
  • CI/CD integration: Works with GitHub Actions, GitLab CI, etc.
  • Verification tasks: Confirm functionality after deployment

Molecule Structure

roles/influxdb/
├── molecule/
│   ├── default/           # Default test scenario
│   │   ├── molecule.yml   # Scenario configuration
│   │   ├── converge.yml   # Playbook to test
│   │   ├── verify.yml     # Verification tasks
│   │   └── prepare.yml    # Setup before testing
│   ├── podman/            # Podman-specific scenario
│   └── proxmox/           # Proxmox VM scenario
├── tasks/
├── templates/
└── README.md

Molecule Configuration

molecule.yml

---
dependency:
  name: galaxy
driver:
  name: podman  # or delegated, docker
platforms:
  - name: instance
    image: debian:12
    pre_build_image: true
    systemd: true
provisioner:
  name: ansible
  inventory:
    host_vars:
      instance:
        secure_logging: false  # Show credentials in test logs
verifier:
  name: ansible

Key Settings

Driver: - podman - Local container testing (fast) - delegated - Use external infrastructure (Proxmox, EC2) - docker - Docker container testing

Platforms: - Define test environments - OS image, networking, volumes - Systemd support for service testing

Provisioner: - Ansible configuration - Inventory variables - Connection settings

Verifier: - How to verify role execution - Usually Ansible tasks in verify.yml

Testing Workflow

Full Test Cycle

# Complete test: create, converge, verify, destroy
molecule test

# Equivalent to:
molecule create      # Create test instance
molecule converge    # Run role
molecule verify      # Run verification tasks
molecule destroy     # Clean up

Development Cycle

# Create instance once
molecule create

# Iteratively test changes
molecule converge    # Apply role
molecule verify      # Check results

# Manual inspection
molecule login       # SSH to test instance

# Cleanup when done
molecule destroy

Specific Scenarios

# Test specific scenario
molecule test -s podman
molecule test -s proxmox

# List available scenarios
molecule list

Test Scenarios

Default Scenario

Purpose: Quick local testing using containers

Platform: Podman/Docker containers Speed: Fast (2-3 minutes) Use case: Development, quick validation

# molecule/default/molecule.yml
platforms:
  - name: debian12
    image: debian:12
    systemd: true

  - name: rocky9
    image: rockylinux:9
    systemd: true

Podman Scenario

Purpose: Container-based testing with Podman

Platform: Podman containers Speed: Fast Use case: Local development without root

# molecule/podman/molecule.yml
driver:
  name: podman
platforms:
  - name: instance
    image: debian:12
    systemd: true
    command: /lib/systemd/systemd
    pre_build_image: true

Proxmox Scenario

Purpose: Full VM testing on Proxmox hypervisor

Platform: Proxmox VMs Speed: Slow (10-15 minutes) Use case: Integration testing, production validation

# molecule/proxmox/molecule.yml
driver:
  name: delegated
platforms:
  - name: test-vm
    groups:
      - molecule
provisioner:
  inventory:
    group_vars:
      molecule:
        ansible_user: root
        ansible_host: 192.168.1.100

GitHub Scenario

Purpose: CI testing in GitHub Actions

Platform: Ubuntu containers in GitHub Speed: Medium (5-10 minutes) Use case: Automated testing on PR

# molecule/github/molecule.yml
driver:
  name: podman
platforms:
  - name: ubuntu24
    image: ubuntu:24.04
    systemd: true

Writing Tests

Converge Playbook

# molecule/default/converge.yml
---
- name: Converge
  hosts: all
  become: true

  vars:
    # Override defaults for testing
    influxdb_org: "test_org"
    influxdb_bucket: "test_bucket"
    secure_logging: false  # Show credentials in logs

  tasks:
    - name: Include role
      include_role:
        name: influxdb

Verify Tasks

# molecule/default/verify.yml
---
- name: Verify
  hosts: all
  become: true
  gather_facts: false

  tasks:
    - name: Check InfluxDB service
      systemd:
        name: influxdb
        state: started
      check_mode: true
      register: service_check
      failed_when: service_check.changed

    - name: Verify InfluxDB API responds
      uri:
        url: "http://localhost:8086/health"
        status_code: 200
      register: health_check
      until: health_check.status == 200
      retries: 10
      delay: 5

    - name: Verify InfluxDB bucket exists
      command: >
        podman exec influxdb
        influx bucket list --name test_bucket
      register: bucket_check
      failed_when: "'test_bucket' not in bucket_check.stdout"

Prepare Tasks

# molecule/default/prepare.yml
---
- name: Prepare
  hosts: all
  become: true

  tasks:
    - name: Update apt cache
      apt:
        update_cache: true
      when: ansible_os_family == 'Debian'

    - name: Install required packages
      package:
        name:
          - curl
          - podman
        state: present

Platform-Specific Testing

Testing Matrix

Test each role on multiple platforms:

Platform Debian 12 Rocky 9 Ubuntu 24
Podman
GitHub
Proxmox ⏭️

Platform Variables

# molecule/default/molecule.yml
provisioner:
  inventory:
    host_vars:
      debian12:
        ansible_python_interpreter: /usr/bin/python3
      rocky9:
        ansible_python_interpreter: /usr/bin/python3.9

Debugging Tests

Verbose Output

# Show all Ansible output
molecule test --debug

# Show Ansible task output
molecule converge -- -vvv

Keep Instance Running

# Don't destroy on failure
molecule test --destroy=never

# Login to inspect
molecule login

# Cleanup manually
molecule destroy

Check Logs

# View molecule logs
cat ~/.cache/molecule/*/*/molecule.log

# View Ansible logs
export ANSIBLE_LOG_PATH=./ansible.log
molecule converge
cat ansible.log

CI/CD Integration

GitHub Actions

# .github/workflows/test.yml
name: Molecule Test

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        distro:
          - debian:12
          - rockylinux:9
          - ubuntu:24.04

    steps:
      - uses: actions/checkout@v3

      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.x'

      - name: Install dependencies
        run: |
          pip install molecule molecule-plugins[podman] ansible-core

      - name: Run Molecule
        run: molecule test
        env:
          MOLECULE_DISTRO: ${{ matrix.distro }}

GitLab CI

# .gitlab-ci.yml
test:
  image: python:3.11
  before_script:
    - pip install molecule molecule-plugins[docker] ansible-core
  script:
    - molecule test
  only:
    - merge_requests
    - main

Performance Optimization

Parallel Testing

# Test multiple scenarios in parallel
molecule test -s podman &
molecule test -s default &
wait

Caching

# molecule.yml - cache package downloads
provisioner:
  env:
    ANSIBLE_FORCE_COLOR: "1"
    PY_COLORS: "1"
  options:
    fact_caching: jsonfile
    fact_caching_connection: /tmp/molecule_facts

Skip Unnecessary Steps

# Skip dependency installation if already cached
molecule test --skip-dependency

# Only run converge (no verify)
molecule converge

Best Practices

1. Keep Tests Fast

  • Use containers for quick feedback
  • Only use VMs for integration tests
  • Cache package downloads
  • Parallel testing when possible

2. Test Real Scenarios

  • Use realistic variable values
  • Test both success and failure cases
  • Include idempotency tests
  • Verify actual functionality, not just service status

3. Maintain Test Code

  • Keep tests in sync with role changes
  • Document test requirements
  • Use consistent naming
  • Clean up after tests

4. Isolate Tests

  • Each test should be independent
  • Don't depend on previous test state
  • Clean up resources in destroy
  • Use unique resource names

5. Secure Credentials

# Use environment variables for secrets
provisioner:
  inventory:
    host_vars:
      instance:
        influxdb_admin_token: "{{ lookup('env', 'INFLUXDB_TOKEN') }}"
        secure_logging: "{{ lookup('env', 'MOLECULE_SECURE_LOGGING') | default('true') | bool }}"

Common Issues

Issue: Systemd not working in container

Solution: Enable systemd in platform config

platforms:
  - name: instance
    image: debian:12
    command: /lib/systemd/systemd
    systemd: true
    tmpfs:
      - /run
      - /tmp
    volumes:
      - /sys/fs/cgroup:/sys/fs/cgroup:ro

Issue: Network connectivity problems

Solution: Use host network mode

platforms:
  - name: instance
    network_mode: host

Issue: Permission denied errors

Solution: Run with correct privileges

platforms:
  - name: instance
    privileged: true
    capabilities:
      - SYS_ADMIN

Molecule Commands Reference

# Lifecycle
molecule create          # Create test instance
molecule converge        # Apply role
molecule verify          # Run verification
molecule destroy         # Remove instance
molecule test            # Full cycle

# Development
molecule login           # SSH to instance
molecule list            # Show instances
molecule check           # Dry run
molecule idempotence     # Test idempotency

# Cleanup
molecule cleanup         # Remove side effects
molecule reset           # Reset scenario state

Next Steps

  • Test Scenarios: Learn about available test scenarios
  • Platform Matrix: Testing across multiple distributions
  • CI/CD Integration: Automating tests
  • Verification Tasks: Writing effective verification