Probar el código de infraestructura es tan crítico como probar el código de aplicaciones, sin embargo, a menudo se pasa por alto. Cuando tus playbooks de Ansible se despliegan en producción, ¿qué tan seguro estás de que funcionarán correctamente? Aquí es donde entra Molecule: un potente framework de testing diseñado específicamente para roles de Ansible. En este tutorial completo, aprenderás a implementar estrategias de testing robustas para tu automatización de Ansible, desde pruebas básicas de roles hasta validaciones complejas de múltiples escenarios. Ya sea que estés gestionando un puñado de servidores u orquestando miles de nodos, Molecule transformará cómo desarrollas y mantienes tu infraestructura como código.

Prerequisitos

Antes de sumergirte en Molecule, asegúrate de tener configurado lo siguiente:

Herramientas Requeridas:

  • Python 3.8 o superior
  • Ansible 2.10 o superior
  • Docker (para testing basado en contenedores)
  • pip (gestor de paquetes de Python)

Requisitos de Conocimiento:

  • Experiencia básica con Ansible (roles, tareas, handlers)
  • Familiaridad con sintaxis YAML
  • Comprensión de conceptos de Docker
  • Competencia en línea de comandos

Configuración del Entorno: Recomiendo crear un entorno virtual de Python dedicado para evitar conflictos de dependencias:

python3 -m venv molecule-env
source molecule-env/bin/activate  # En Windows: molecule-env\Scripts\activate

Paso 1: Instalar Molecule

La instalación de Molecule es directa con pip. Necesitarás instalar Molecule junto con el driver de Docker, que usaremos para nuestros escenarios de testing.

# Instalar Molecule con soporte para Docker
pip install "molecule[docker,lint]"

# Verificar instalación
molecule --version

Salida Esperada:

molecule 5.0.1 using python 3.11
    ansible:2.15.4
    default:5.0.1 from molecule
    docker:2.1.0 from molecule_plugins.docker

La instalación incluye varios componentes:

  • Core de Molecule: El framework de testing en sí
  • Driver de Docker: Habilita testing basado en contenedores
  • Herramientas de lint: Ansible-lint y yamllint para calidad de código

Punto de Verificación: Ejecuta molecule --version y confirma que todos los componentes estén instalados. Si falta el driver de Docker, reinstala con el extra [docker].

Paso 2: Inicializar un Nuevo Role

Vamos a crear un ejemplo práctico: un role de servidor web Nginx. Molecule se integra perfectamente con la estructura de roles de Ansible Galaxy.

# Crear un nuevo role con testing de Molecule incorporado
molecule init role nginx --driver-name docker

# Navegar al directorio del role
cd nginx

Este comando genera una estructura completa de role:

nginx/
├── defaults/
│   └── main.yml
├── files/
├── handlers/
│   └── main.yml
├── meta/
│   └── main.yml
├── molecule/
│   └── default/
│       ├── converge.yml
│       ├── molecule.yml
│       └── verify.yml
├── tasks/
│   └── main.yml
├── templates/
├── tests/
└── vars/
    └── main.yml

Directorios Clave:

  • molecule/default/: Contiene la configuración de tu escenario de testing
  • tasks/main.yml: Donde van tus tareas de Ansible
  • handlers/main.yml: Para reinicios de servicios y notificaciones

Paso 3: Entender la Estructura de Molecule

El directorio molecule/default/ contiene tres archivos críticos:

molecule.yml - El archivo de configuración principal:

---
dependency:
  name: galaxy
driver:
  name: docker
platforms:
  - name: instance
    image: geerlingguy/docker-ubuntu2204-ansible:latest
    pre_build_image: true
provisioner:
  name: ansible
verifier:
  name: ansible

Desglose de Configuración:

  • dependency: Gestiona dependencias de roles de Ansible Galaxy
  • driver: Especifica Docker para crear instancias de prueba
  • platforms: Define entornos de prueba (OS, imagen, recursos)
  • provisioner: Usa Ansible para aplicar tu role
  • verifier: Ejecuta tests de verificación después de la convergencia

converge.yml - Aplica tu role a las instancias de prueba:

---
- name: Converge
  hosts: all
  become: true
  tasks:
    - name: "Include nginx"
      include_role:
        name: "nginx"

verify.yml - Contiene aserciones para validar el comportamiento del role:

---
- name: Verify
  hosts: all
  gather_facts: false
  tasks:
    - name: Example assertion
      ansible.builtin.assert:
        that: true

Paso 4: Escribir tu Primera Prueba

Vamos a construir un role funcional de Nginx con pruebas apropiadas. Comienza definiendo las tareas del role.

tasks/main.yml:

---
# Instalar servidor web Nginx
- name: Install Nginx package
  ansible.builtin.apt:
    name: nginx
    state: present
    update_cache: yes
  notify: Start nginx

- name: Ensure Nginx is started and enabled
  ansible.builtin.service:
    name: nginx
    state: started
    enabled: yes

- name: Deploy custom index.html
  ansible.builtin.copy:
    content: |
      <html>
      <head><title>Ansible Managed</title></head>
      <body><h1>Deployed with Ansible</h1></body>
      </html>
    dest: /var/www/html/index.html
    owner: www-data
    group: www-data
    mode: '0644'

handlers/main.yml:

---
- name: Start nginx
  ansible.builtin.service:
    name: nginx
    state: started

Ahora crea pruebas de verificación significativas en molecule/default/verify.yml:

---
- name: Verify
  hosts: all
  gather_facts: true
  tasks:
    - name: Check if Nginx is installed
      ansible.builtin.package_facts:
        manager: auto

    - name: Assert Nginx package is present
      ansible.builtin.assert:
        that:
          - "'nginx' in ansible_facts.packages"
        fail_msg: "Nginx package is not installed"
        success_msg: "Nginx package is correctly installed"

    - name: Check if Nginx service is running
      ansible.builtin.service_facts:

    - name: Assert Nginx service is active
      ansible.builtin.assert:
        that:
          - "ansible_facts.services['nginx.service'].state == 'running'"
          - "ansible_facts.services['nginx.service'].status == 'enabled'"
        fail_msg: "Nginx service is not running or not enabled"
        success_msg: "Nginx service is active and enabled"

    - name: Check if Nginx is listening on port 80
      ansible.builtin.wait_for:
        port: 80
        timeout: 5

    - name: Verify custom index.html content
      ansible.builtin.uri:
        url: http://localhost
        return_content: yes
      register: webpage

    - name: Assert webpage contains expected content
      ansible.builtin.assert:
        that:
          - "'Deployed with Ansible' in webpage.content"
        fail_msg: "Custom index.html was not deployed correctly"
        success_msg: "Custom index.html is correctly deployed"

Paso 5: Ejecutar las Pruebas

Molecule proporciona un ciclo de vida de testing completo. Aquí está cómo ejecutar las pruebas:

# Ejecutar la secuencia completa de testing
molecule test

# O ejecutar pasos individuales:
molecule create    # Crear instancias de prueba
molecule converge  # Aplicar tu role
molecule verify    # Ejecutar pruebas de verificación
molecule destroy   # Limpiar instancias

La Secuencia Completa de Testing:

Cuando ejecutas molecule test, Molecule ejecuta estas fases:

  1. Dependency: Instalar dependencias de roles desde Ansible Galaxy
  2. Lint: Verificar sintaxis y mejores prácticas
  3. Cleanup: Eliminar instancias de prueba anteriores
  4. Destroy: Asegurar estado limpio
  5. Create: Crear contenedores de prueba
  6. Prepare: Pasos opcionales de pre-configuración
  7. Converge: Aplicar tu role
  8. Idempotence: Re-ejecutar para asegurar que no ocurran cambios
  9. Verify: Ejecutar pruebas de aserción
  10. Destroy: Limpiar recursos

Salida Esperada (abreviada):

--> Test matrix

└── default
    ├── dependency
    ├── cleanup
    ├── destroy
    ├── create
    ├── prepare
    ├── converge
    ├── idempotence
    ├── verify
    └── destroy

--> Scenario: 'default'
--> Action: 'converge'

    PLAY [Converge] ********************************************************

    TASK [Include nginx] ***************************************************
    included: /Users/user/nginx/tasks/main.yml

    TASK [Install Nginx package] *******************************************
    changed: [instance]

    TASK [Ensure Nginx is started and enabled] *****************************
    changed: [instance]

    PLAY RECAP *************************************************************
    instance: ok=3 changed=2 unreachable=0 failed=0

--> Scenario: 'default'
--> Action: 'verify'

    TASK [Assert Nginx service is active] **********************************
    ok: [instance] => {
        "msg": "Nginx service is active and enabled"
    }

Consejo de Flujo de Desarrollo: Durante el desarrollo, usa molecule converge repetidamente para aplicar cambios sin destruir instancias. Solo ejecuta el molecule test completo cuando estés listo para validar todo.

Paso 6: Probar con Diferentes Escenarios

La infraestructura del mundo real rara vez se ejecuta en un solo OS. Los escenarios de Molecule te permiten probar en múltiples plataformas simultáneamente.

Crea un escenario multi-plataforma modificando molecule/default/molecule.yml:

---
dependency:
  name: galaxy
driver:
  name: docker
platforms:
  - name: ubuntu-20-04
    image: geerlingguy/docker-ubuntu2004-ansible:latest
    pre_build_image: true
  - name: ubuntu-22-04
    image: geerlingguy/docker-ubuntu2204-ansible:latest
    pre_build_image: true
  - name: debian-11
    image: geerlingguy/docker-debian11-ansible:latest
    pre_build_image: true
provisioner:
  name: ansible
  playbooks:
    converge: converge.yml
    verify: verify.yml
verifier:
  name: ansible

Crear Escenarios Nombrados:

También puedes crear escenarios de prueba completamente separados para diferentes casos de uso:

# Crear un escenario tipo producción
molecule init scenario production

# Crear un escenario para probar actualizaciones
molecule init scenario upgrade

Esto crea:

molecule/
├── default/
│   ├── converge.yml
│   ├── molecule.yml
│   └── verify.yml
├── production/
│   ├── converge.yml
│   ├── molecule.yml
│   └── verify.yml
└── upgrade/
    ├── converge.yml
    ├── molecule.yml
    └── verify.yml

Ejecutar Escenarios Específicos:

# Probar solo el escenario de producción
molecule test -s production

# Converger múltiples escenarios
molecule converge --all

Paso 7: Integración CI/CD

Molecule se integra perfectamente con pipelines de integración continua. Aquí está cómo configurarlo con GitHub Actions.

.github/workflows/molecule.yml:

---
name: Molecule Tests

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        scenario:
          - default
          - production

    steps:
      - name: Check out code
        uses: actions/checkout@v3

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

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install "molecule[docker,lint]"
          pip install ansible

      - name: Run Molecule tests
        run: molecule test -s ${{ matrix.scenario }}

Configuración de GitLab CI (.gitlab-ci.yml):

---
stages:
  - test

molecule:
  stage: test
  image: geerlingguy/docker-ubuntu2204-ansible:latest
  services:
    - docker:dind
  variables:
    DOCKER_HOST: tcp://docker:2375
    DOCKER_TLS_CERTDIR: ""
  before_script:
    - pip install "molecule[docker,lint]"
  script:
    - molecule test --all
  only:
    - merge_requests
    - main

Punto de Verificación: Empuja tu role a un repositorio Git y verifica que el pipeline de CI se ejecute exitosamente. Verifica que todos los escenarios pasen y que el pipeline falle en caso de errores de prueba.

Ejemplos del Mundo Real

Ejemplo 1: Probar un Role de Servidor Web

Vamos a extender nuestro role de Nginx con configuración SSL y virtual hosts.

tasks/main.yml (extendido):

---
- name: Install Nginx and SSL dependencies
  ansible.builtin.apt:
    name:
      - nginx
      - openssl
    state: present
    update_cache: yes

- name: Create SSL directory
  ansible.builtin.file:
    path: /etc/nginx/ssl
    state: directory
    mode: '0755'

- name: Generate self-signed SSL certificate
  ansible.builtin.command:
    cmd: >
      openssl req -x509 -nodes -days 365 -newkey rsa:2048
      -keyout /etc/nginx/ssl/nginx.key
      -out /etc/nginx/ssl/nginx.crt
      -subj "/C=US/ST=State/L=City/O=Org/CN=localhost"
    creates: /etc/nginx/ssl/nginx.crt

- name: Deploy SSL virtual host configuration
  ansible.builtin.template:
    src: vhost-ssl.conf.j2
    dest: /etc/nginx/sites-available/default
    mode: '0644'
  notify: Reload nginx

- name: Ensure Nginx is started
  ansible.builtin.service:
    name: nginx
    state: started
    enabled: yes

templates/vhost-ssl.conf.j2:

server {
    listen 80;
    listen 443 ssl;

    ssl_certificate /etc/nginx/ssl/nginx.crt;
    ssl_certificate_key /etc/nginx/ssl/nginx.key;

    root /var/www/html;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}

molecule/default/verify.yml (extendido):

---
- name: Verify
  hosts: all
  gather_facts: true
  tasks:
    - name: Check SSL certificate exists
      ansible.builtin.stat:
        path: /etc/nginx/ssl/nginx.crt
      register: ssl_cert

    - name: Assert SSL certificate is present
      ansible.builtin.assert:
        that:
          - ssl_cert.stat.exists
          - ssl_cert.stat.mode == '0644'

    - name: Verify Nginx is listening on HTTPS
      ansible.builtin.wait_for:
        port: 443
        timeout: 5

    - name: Test HTTPS connection
      ansible.builtin.uri:
        url: https://localhost
        validate_certs: no
        return_content: yes
      register: https_response

    - name: Assert HTTPS is working
      ansible.builtin.assert:
        that:
          - https_response.status == 200

Ejemplo 2: Probar Configuración de Base de Datos

Aquí está cómo probar un role de PostgreSQL con Molecule.

molecule/default/molecule.yml:

---
platforms:
  - name: postgres-instance
    image: geerlingguy/docker-ubuntu2204-ansible:latest
    pre_build_image: true
    volumes:
      - /sys/fs/cgroup:/sys/fs/cgroup:ro
    privileged: true
    command: /lib/systemd/systemd

tasks/main.yml (role de PostgreSQL):

---
- name: Install PostgreSQL
  ansible.builtin.apt:
    name:
      - postgresql
      - postgresql-contrib
      - python3-psycopg2
    state: present
    update_cache: yes

- name: Ensure PostgreSQL is started
  ansible.builtin.service:
    name: postgresql
    state: started
    enabled: yes

- name: Create application database
  become_user: postgres
  community.postgresql.postgresql_db:
    name: appdb
    state: present

- name: Create database user
  become_user: postgres
  community.postgresql.postgresql_user:
    name: appuser
    password: "{{ db_password | default('changeme') }}"
    db: appdb
    priv: ALL
    state: present

molecule/default/verify.yml:

---
- name: Verify
  hosts: all
  become: true
  tasks:
    - name: Check PostgreSQL service status
      ansible.builtin.service_facts:

    - name: Assert PostgreSQL is running
      ansible.builtin.assert:
        that:
          - "ansible_facts.services['postgresql.service'].state == 'running'"

    - name: Verify database exists
      become_user: postgres
      community.postgresql.postgresql_query:
        db: appdb
        query: SELECT 1
      register: db_check

    - name: Assert database is accessible
      ansible.builtin.assert:
        that:
          - db_check is succeeded

    - name: Test database connection with user
      become_user: postgres
      community.postgresql.postgresql_query:
        db: appdb
        login_user: appuser
        query: CREATE TABLE test (id serial PRIMARY KEY, name varchar(50))
      register: table_creation

    - name: Assert user has correct privileges
      ansible.builtin.assert:
        that:
          - table_creation is succeeded

Ejemplo 3: Probar Hardening de Seguridad

Los roles de seguridad requieren pruebas exhaustivas para asegurar que no rompan funcionalidad.

molecule/default/verify.yml (hardening de seguridad):

---
- name: Verify Security Hardening
  hosts: all
  gather_facts: true
  tasks:
    - name: Check if SSH password authentication is disabled
      ansible.builtin.lineinfile:
        path: /etc/ssh/sshd_config
        regexp: '^PasswordAuthentication'
        line: 'PasswordAuthentication no'
        state: present
      check_mode: yes
      register: ssh_config

    - name: Assert SSH is properly configured
      ansible.builtin.assert:
        that:
          - not ssh_config.changed
        fail_msg: "SSH password authentication is not disabled"

    - name: Verify firewall is active
      ansible.builtin.command: ufw status
      register: ufw_status
      changed_when: false

    - name: Assert firewall is enabled
      ansible.builtin.assert:
        that:
          - "'Status: active' in ufw_status.stdout"

    - name: Check for unattended upgrades
      ansible.builtin.stat:
        path: /etc/apt/apt.conf.d/50unattended-upgrades
      register: unattended_upgrades

    - name: Assert automatic updates are configured
      ansible.builtin.assert:
        that:
          - unattended_upgrades.stat.exists

    - name: Verify root login is disabled
      ansible.builtin.command: passwd -S root
      register: root_status
      changed_when: false

    - name: Assert root account is locked
      ansible.builtin.assert:
        that:
          - "'L' in root_status.stdout"
        fail_msg: "Root account is not locked"

Mejores Prácticas

Organización de Pruebas

Mantén las pruebas enfocadas y modulares:

# Mal: Un archivo de verificación gigante
verify.yml  # 500 líneas de pruebas

# Bien: Tareas de verificación separadas
molecule/default/
├── molecule.yml
├── converge.yml
├── verify.yml
└── verify/
    ├── test_installation.yml
    ├── test_configuration.yml
    ├── test_security.yml
    └── test_networking.yml

El verify.yml principal incluye pruebas específicas:

---
- name: Verify
  hosts: all
  tasks:
    - name: Run installation tests
      include_tasks: verify/test_installation.yml

    - name: Run configuration tests
      include_tasks: verify/test_configuration.yml

    - name: Run security tests
      include_tasks: verify/test_security.yml

Gestión de Escenarios

Usa escenarios estratégicamente:

  • default: Pruebas básicas de funcionalidad
  • production: Entorno tipo producción con todas las características
  • upgrade: Probar rutas de actualización desde versiones anteriores
  • multi-node: Pruebas de sistemas distribuidos

No crees escenarios para variaciones menores. En su lugar, usa variables:

# molecule/default/converge.yml
- name: Converge
  hosts: all
  vars:
    # Sobrescribe estas en escenarios específicos
    enable_ssl: "{{ scenario_ssl | default(true) }}"
    enable_monitoring: "{{ scenario_monitoring | default(false) }}"
  roles:
    - nginx

Pruebas de Idempotencia

La idempotencia es crítica: ejecutar tu role múltiples veces no debería causar cambios después de la primera ejecución.

Molecule prueba esto automáticamente. Asegúrate de que tus tareas sean idempotentes:

# Mal: Siempre reporta cambios
- name: Configure application
  ansible.builtin.shell: echo "config=true" >> /etc/app.conf

# Bien: Configuración idempotente
- name: Configure application
  ansible.builtin.lineinfile:
    path: /etc/app.conf
    line: "config=true"
    create: yes

Monitorea la salida de la prueba de idempotencia:

PLAY RECAP *****************************************************************
instance: ok=10 changed=0 unreachable=0 failed=0

Si changed es mayor que 0 en la segunda ejecución, tienes problemas de idempotencia.

Docker vs Vagrant

Docker (Recomendado para la mayoría de casos):

  • Rápido: Los contenedores inician en segundos
  • Eficiente en recursos: Ejecuta muchas instancias simultáneamente
  • Amigable con CI: Funciona en la mayoría de entornos de CI
  • Limitaciones: No puede probar módulos del kernel, peculiaridades de systemd, o cualquier cosa que requiera VM completa

Vagrant (Para escenarios complejos):

  • VMs completas: Sistema operativo completo
  • Systemd: Soporte completo del sistema init
  • Testing de kernel: Puede probar parámetros y módulos del kernel
  • Compensaciones: Más lento (minutos para iniciar), pesado en recursos, más difícil en CI

Cuándo usar Vagrant:

# molecule/vagrant/molecule.yml
---
driver:
  name: vagrant
platforms:
  - name: ubuntu-vm
    box: ubuntu/jammy64
    memory: 2048
    cpus: 2
provisioner:
  name: ansible

Usa Vagrant cuando pruebes roles que:

  • Modifican parámetros del kernel (sysctl)
  • Requieren características específicas de systemd
  • Instalan módulos del kernel
  • Necesitan stack de red completo

Errores Comunes

Limitaciones de Contenedores

Problema: Systemd no funciona apropiadamente en contenedores estándar.

Solución: Usa imágenes pre-construidas con soporte para systemd:

platforms:
  - name: instance
    image: geerlingguy/docker-ubuntu2204-ansible:latest
    volumes:
      - /sys/fs/cgroup:/sys/fs/cgroup:ro
    privileged: true
    command: /lib/systemd/systemd

Las imágenes Docker de Jeff Geerling están construidas específicamente para testing de Ansible con systemd funcional.

Problemas de Privilegios

Problema: Las tareas fallan con errores de permisos.

Solución: Usa become apropiadamente en tu playbook de convergencia:

# molecule/default/converge.yml
---
- name: Converge
  hosts: all
  become: true  # Ejecutar tareas con sudo
  tasks:
    - name: Include role
      include_role:
        name: nginx

Evita requerir become: yes en el role mismo cuando sea posible. Deja que el usuario decida la escalada de privilegios.

Gestión de Dependencias

Problema: El role depende de otros roles, pero no están disponibles durante el testing.

Solución: Define dependencias en meta/main.yml:

# meta/main.yml
---
dependencies:
  - role: geerlingguy.security
  - role: geerlingguy.firewall

Molecule instala estas automáticamente antes de probar si tienes habilitado el gestor de dependencias de Galaxy:

# molecule/default/molecule.yml
dependency:
  name: galaxy
  options:
    role-file: requirements.yml

Crea requirements.yml para dependencias externas:

# requirements.yml
---
roles:
  - name: geerlingguy.security
    version: 2.3.0
  - name: geerlingguy.firewall
    version: 3.1.0

Inestabilidad de Pruebas

Problema: Las pruebas ocasionalmente fallan sin razón aparente.

Causas comunes:

  • Timeouts de red
  • Condiciones de carrera en el inicio de servicios
  • Tiempos de espera insuficientes

Solución: Agrega esperas y reintentos apropiados:

- name: Wait for service to be ready
  ansible.builtin.wait_for:
    port: 80
    delay: 2
    timeout: 30

- name: Check endpoint with retry
  ansible.builtin.uri:
    url: http://localhost/health
  register: health_check
  until: health_check.status == 200
  retries: 5
  delay: 3

Herramientas e Integración

Testinfra para Verificación

Aunque Molecule usa Ansible para verificación por defecto, también puedes usar Testinfra (testing basado en Python):

pip install testinfra

molecule/default/tests/test_default.py:

import os
import testinfra.utils.ansible_runner

testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
    os.environ['MOLECULE_INVENTORY_FILE']
).get_hosts('all')

def test_nginx_is_installed(host):
    nginx = host.package("nginx")
    assert nginx.is_installed

def test_nginx_running_and_enabled(host):
    nginx = host.service("nginx")
    assert nginx.is_running
    assert nginx.is_enabled

def test_nginx_listening(host):
    assert host.socket("tcp://0.0.0.0:80").is_listening

def test_index_html_content(host):
    content = host.file("/var/www/html/index.html").content_string
    assert "Deployed with Ansible" in content

Configurar Testinfra en molecule.yml:

verifier:
  name: testinfra
  options:
    v: 1

Integración GitLab/GitHub CI

GitHub Actions avanzado con testing de matriz:

---
name: Ansible Role Testing

on:
  push:
    branches: [main]
  pull_request:
  schedule:
    - cron: '0 0 * * 0'  # Semanal

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-python@v4
        with:
          python-version: '3.11'
      - name: Install dependencies
        run: pip install ansible-lint yamllint
      - name: Lint Ansible role
        run: ansible-lint .
      - name: Lint YAML files
        run: yamllint .

  test:
    needs: lint
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        distro:
          - ubuntu2004
          - ubuntu2204
          - debian11
        scenario:
          - default
          - production
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-python@v4
        with:
          python-version: '3.11'
      - name: Install Molecule
        run: pip install "molecule[docker,lint]" ansible
      - name: Run Molecule test
        run: molecule test -s ${{ matrix.scenario }}
        env:
          PY_COLORS: '1'
          ANSIBLE_FORCE_COLOR: '1'
          MOLECULE_DISTRO: ${{ matrix.distro }}

Integración con Ansible Galaxy

Al publicar roles en Ansible Galaxy, incluye pruebas de Molecule para aumentar credibilidad:

# .github/workflows/release.yml
---
name: Release to Galaxy

on:
  push:
    tags:
      - 'v*'

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Test with Molecule
        run: |
          pip install "molecule[docker,lint]"
          molecule test

  release:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Release to Galaxy
        uses: robertdebock/galaxy-action@1.2.0
        with:
          galaxy_api_key: ${{ secrets.GALAXY_API_KEY }}

Enlaza a tu badge de CI en README.md:

# Ansible Role: Nginx

[![CI](https://github.com/username/ansible-role-nginx/workflows/CI/badge.svg)](https://github.com/username/ansible-role-nginx/actions)
[![Ansible Galaxy](https://img.shields.io/badge/galaxy-username.nginx-blue.svg)](https://galaxy.ansible.com/username/nginx)

Probado con Molecule en:
- Ubuntu 20.04
- Ubuntu 22.04
- Debian 11

Conclusión

Molecule transforma el desarrollo de roles de Ansible de un proceso manual y propenso a errores en un flujo de trabajo robusto y automatizado. Al implementar estrategias de testing comprehensivas—desde verificaciones básicas de funcionalidad hasta escenarios multi-plataforma—aseguras que tu código de infraestructura sea confiable, mantenible y listo para producción.

Puntos Clave:

  • Siempre prueba tus roles en múltiples sistemas operativos y escenarios
  • Aprovecha el testing de idempotencia para prevenir deriva de configuración
  • Integra Molecule en tu pipeline de CI/CD para validación continua
  • Usa Docker para velocidad durante desarrollo, Vagrant para testing complejo a nivel de sistema
  • Escribe pruebas de verificación claras y enfocadas que actúen como documentación viva

Próximos Pasos:

  1. Explora escenarios avanzados: Implementa testing multi-nodo para sistemas distribuidos (aprende más en nuestra guía de Mejores Prácticas de Gestión de Contenedores Docker)
  2. Integra con tu pipeline de CI/CD: Agrega pruebas de Molecule a tus pipelines existentes (revisa Estrategias de Optimización de Pipeline CI/CD)
  3. Contribuye a la comunidad: Comparte tus roles probados en Ansible Galaxy
  4. Aprende herramientas complementarias de testing: Explora Testinfra, InSpec y ServerSpec para validación más profunda de infraestructura

Para más sobre automatización de infraestructura y mejores prácticas de DevOps, explora nuestra guía completa sobre Infraestructura como Código con Terraform o sumérgete en Estrategias de Despliegue en Kubernetes para testing de infraestructura cloud-native.

Recursos Adicionales:

Comienza a probar tu código de infraestructura hoy—tu yo futuro (y tu equipo) te lo agradecerán cuando los despliegues se vuelvan predecibles, confiables y libres de estrés.