Ansible Molecule

Siehe auch

Verwandte Artikel
Offizielle Dokumentation
Linuxfabrik

Molecule ist das Standard-Test-Framework für Ansible-Rollen und -Collections. Es automatisiert das Aufsetzen einer isolierten Testumgebung (typischerweise ein Container), spielt dort die zu testende Rolle ein, prüft das Ergebnis und räumt hinterher wieder auf. Damit lassen sich Ansible-Automatisierungen reproduzierbar testen, ohne eine echte Zielmaschine zu beanspruchen. Molecule gehört zu den ansible-dev-tools und wird von Red Hat als offizielles Testwerkzeug gepflegt.

Begriffe
  • converge: die eigentliche Test-Phase - hier läuft das zu testende Playbook gegen die Testumgebung.

  • Driver: das Backend, das die Testumgebung provisioniert. Gebräuchlich sind podman, docker, vagrant und delegated (für bereits vorhandene Umgebungen).

  • idempotence: zweiter Lauf von converge. Ansible muss dabei changed=0 melden, sonst ist die Rolle nicht idempotent.

  • Szenario: ein Satz Testdateien unter extensions/molecule/<name>/. Jede Collection bringt mindestens ein Szenario (typischerweise default) mit. Weitere Szenarien für spezifische OS-Varianten (z.B. rhel, debian) sind üblich.

  • verify: optionale Akzeptanzprüfung mit einem externen Tool, z.B. Testinfra oder Ansible-Assertions.

Installation

Die Installation erfolgt in einer dedizierten venv. Als Driver-Backend wird podman verwendet - rootless und auf RHEL 8+ standardmässig verfügbar.

dnf --assumeyes install podman

python3 -m venv ~/venvs/molecule
source ~/venvs/molecule/bin/activate

python3 -m pip install --upgrade pip
python3 -m pip install ansible-dev-tools 'molecule-plugins[podman]'

ansible-galaxy collection install containers.podman community.general

Versionen prüfen:

molecule --version
ansible --version

Szenario in einer Collection anlegen

Innerhalb einer bestehenden Ansible-Collection (z.B. lfops) wird ein Default-Szenario initialisiert:

source ~/venvs/molecule/bin/activate

cd lfops
mkdir --parents extensions
cd extensions

molecule init scenario
# optional: additional scenarios for specific OS variants
molecule init scenario rhel

Struktur nach init:

lfops/extensions/molecule/
+-- default/
|   +-- converge.yml
|   +-- create.yml
|   +-- destroy.yml
|   +-- molecule.yml
|   +-- verify.yml
+-- rhel/
    +-- ...

Verschachtelte und gruppierte Szenarien

Molecule erlaubt es, Szenarien verschachtelt und gruppiert anzulegen:

lfops/extensions/molecule/
+-- config.yml
+-- default/
|   +-- converge.yml
|   +-- create.yml
|   +-- destroy.yml
|   +-- molecule.yml
|   +-- verify.yml
+-- rhel/
|   +-- rhel8/
|   |   +-- converge.yml
|   |   +-- create.yml
|   |   +-- destroy.yml
|   |   +-- molecule.yml
|   |   +-- verify.yml
|   +-- rhel9/
|   |   +-- ...
|   +-- rhel10/
|       +-- ...
+-- debian/
    +-- debian11/
    |   +-- ...
    +-- debian12/
    |   +-- ...
    +-- debian13/
        +-- ...

Die einzelnen Szenarien werden dann mit ihrem relativen Pfad bezüglich extensions/molecule aufgerufen. Bei diesem Beispiellayout wird das RHEL-9-Szenario mit molecule test --scenario-name rhel/rhel9 ausgeführt.

Alle Szenarien einer Gruppe können gleichzeitig ausgeführt werden, indem eine Pfad-ähnliche Wildcard verwendet wird. Beim oben genannten Beispiel kann die gesamte debian-Gruppe mit molecule test --scenario-name 'debian/*' auf einmal getestet werden.

Bemerkung

Dieses Molecule-Konzept ist eine reine Gruppierung. Es gibt keine Vererbung der Testkonfiguration oder der Playbooks zwischen den Szenarien.

Konfiguration

Zentrale Datei ist molecule.yml pro Szenario. Beispiel mit Podman-Driver und einem Rocky-9-Container:

extensions/molecule/default/molecule.yml
driver:
  name: 'podman'

platforms:
  - name: 'rocky9'
    image: 'rockylinux/rockylinux:9'
    pre_build_image: true
    privileged: true
    command: '/usr/sbin/init'

provisioner:
  name: 'ansible'

verifier:
  name: 'ansible'

Der zu testende Code landet in converge.yml:

extensions/molecule/default/converge.yml
- name: 'Converge'
  hosts: 'all'
  tasks:
    - name: 'apply my role'
      ansible.builtin.include_role:
        name: 'my_role'

Testablauf

Molecule unterteilt einen Testlauf in einzelne Phasen:

  • dependency: Installation aller benötigten Abhängigkeiten auf dem Ansible Controller (Collections, Rollen, Playbooks).

  • create: Provisionierung der Testumgebung (Container, VM, Cloud-Instanz).

  • prepare: Vorbereitungen in der Testumgebung, die nicht zum eigentlichen Test gehören (z.B. SSH-Keys einrichten, python3 nachinstallieren).

  • converge: der eigentliche Test - hier wird die zu testende Automatisierung ausgeführt.

  • idempotence: zweiter converge-Lauf. Wenn Ansible dabei Änderungen meldet, ist die Rolle nicht idempotent.

  • side_effect: separate Automatisierung, die auf unerwünschte Nebeneffekte testet.

  • verify: Validierung expliziter Akzeptanzkriterien. Typischerweise mit Testinfra oder mit Ansible-Assertions.

  • cleanup: Entfernen temporärer Daten, die während des Tests entstanden sind.

  • destroy: Abbau der in create aufgesetzten Testumgebung.

Reihenfolge und Umfang der Phasen werden in molecule.yml definiert:

extensions/molecule/default/molecule.yml
scenario:
  test_sequence:
    - 'dependency'
    - 'create'
    - 'converge'
    - 'verify'
    - 'side_effect'
    - 'verify'
    - 'destroy'

Mit molecule test wird die komplette Testsequenz ausgeführt. Einzelne Phasen lassen sich auch gezielt aufrufen, z.B. um Container oder VMs nach converge zu inspizieren, bevor sie gelöscht werden. Dabei werden stets alle Phasen der Testsequenz bis zur angegebenen Phase mitgeführt - ein molecule converge durchläuft bei der Standardsequenz also dependency, create, prepare und converge.

Molecule Cheat Sheet

source ~/venvs/molecule/bin/activate
cd lfops

# full test sequence
molecule test

# only the rhel scenario
molecule test --scenario-name rhel

# step by step, for debugging
molecule create                   # bring up the container
molecule converge                 # apply the role
molecule login                    # log into the container
molecule verify                   # only the verify phase
molecule destroy                  # clean up

# verbose output
molecule --debug test

# reset Molecule's internal state after scenario config (molecule.yml) changes
# (test infra should be fully deprovisioned before running this command)
molecule reset

Troubleshooting

Error while fetching server API version oder podman.service: Failed to start

Der Podman-Socket ist nicht erreichbar. Für den aktuellen Benutzer den User-Socket starten: systemctl --user enable --now podman.socket. Im CI-Umfeld zusätzlich DOCKER_HOST=unix:///run/user/$(id -u)/podman/podman.sock exportieren.

Failed to import the required Python library (requests) beim Podman-Driver

Das Python der venv findet den Podman-Client nicht, oder die Abhängigkeiten fehlen. python3 -m pip install 'molecule-plugins[podman]' in der venv erneut installieren.

Molecule bricht mit idempotence: changed tasks ab

Die Rolle ist nicht idempotent: ein zweiter Lauf würde auf der produktiven Maschine erneut Änderungen anwenden. Typische Ursachen sind command/shell ohne changed_when, copy ohne mode:, oder Template-Rendering, das Zeitstempel oder eine zufällige Reihenfolge enthält.

The scenario config file (...) has been modified since the scenario was created am Anfang eines Runs

Molecule ist für interaktive, iterative Nutzung gebaut, die Phasen lassen sich also einzeln aufrufen. Deshalb prüft Molecule zwischen den Aufrufen, ob sich die Szenario-Definition geändert hat. Nach einer Änderung an der molecule.yml muss vor dem nächsten Testlauf molecule reset den internen Zustand zurücksetzen; existiert die Test-Infrastruktur noch, vorher mit molecule destroy aufräumen. Ein molecule destroy allein reicht nicht. Die Warnung ist an dieser Stelle ungünstig bis irreführend formuliert.