Get Rewarded! We will reward you with up to €50 credit on your account for every tutorial that you write and we publish!

Ansible-Rollen mit Molecule testen

profile picture
Author
Harshavardhan Musanalli
Published
2024-05-06
Time to read
11 minutes reading time

Einführung

Ansible Molecule ist ein leistungsstarkes Test-Framework, das den Prozess des Testens von Ansible-Rollen in verschiedenen Szenarien vereinfacht. Dieses Tutorial führt durch den Prozess der Einrichtung und Verwendung von Ansible Molecule, um Ansible-Rollen effektiv zu testen.

Warum Molecule zum Testen von Ansible verwenden?

Gründe für Molecule:

  • Automatisiertes Testen: Molecule automatisiert den Testprozess für Ansible-Rollen und ermöglicht die einfache Definition und Ausführung von Testszenarien. Diese Automatisierung hilft, Probleme frühzeitig im Entwicklungszyklus zu erkennen und stellt sicher, dass sich die Rollen wie erwartet verhalten.
  • Isolierung von Umgebungen: Molecule verwendet verschiedene Treiber (z. B. Docker, Vagrant), um isolierte Umgebungen für Tests zu schaffen. Dadurch wird sichergestellt, dass die Tests über verschiedene Systeme hinweg konsistent und reproduzierbar sind, was die Wahrscheinlichkeit von umgebungsbezogenen Problemen verringert.
  • Mehrere Test-Szenarien: Molecule unterstützt die Definition mehrerer Szenarien, welche es ermöglichen, Rollen unter verschiedenen Bedingungen zu testen. So kannst du beispielsweise verschiedene Betriebssysteme, Ansible-Versionen oder Konfigurationen testen, um die Kompatibilität der Rollen sicherzustellen.
  • Continuous Integration (CI): Molecule ist so konzipiert, dass es nahtlos mit CI-Systemen wie Travis CI, Jenkins oder GitLab CI zusammenarbeitet. Dadurch kannst du den Testprozess jedes Mal automatisieren, wenn Änderungen in dein Versionskontrollsystem übertragen werden, und so eine kontinuierliche Qualitätssicherung gewährleisten.
  • Unterstützung der Rollenentwicklung: Molecule enthält Tools für die Rollenentwicklung, wie z. B. Rolleninitialisierung, Linting und Abhängigkeitsmanagement. Dies rationalisiert den Entwicklungsworkflow und trägt zur Erhaltung einer konsistenten Codebasis bei.
  • Parallele Ausführung: Molecule unterstützt die parallele Ausführung von Tests, was beim Testen mehrerer Szenarien gleichzeitig Zeit sparen kann. Dies ist entscheidend für die Beschleunigung der Feedbackschleife während der Entwicklung.
  • Dokumentation und Best Practices: Molecule fördert bewährte Praktiken bei der Rollenentwicklung und beim Testen. Die Dokumentation des Tools bietet klare Anleitungen zur Strukturierung von Rollen, zum Schreiben effektiver Testfälle und zur Einhaltung empfohlener Konventionen.
  • Gemeinschaftliche Akzeptanz: Molecule ist in der Ansible-Community weit verbreitet. Viele Ansible-Rollen und -Projekte verwenden Molecule zum Testen, was es zu einer gut unterstützten und zuverlässigen Wahl für Rollenentwickler macht.

Voraussetzungen

Bevor wir uns in die Demonstration stürzen, stelle sicher, dass die folgenden Voraussetzungen erfüllt sind. Für CI-Workloads wird docker ohne die Notwendigkeit von virtualenv dringend empfohlen.


Beispiel-Installation unter Ubuntu 20.04 / 22.04
    sudo apt update && sudo apt install -y python3 python3-pip libssl-dev
    python3 -m pip install molecule ansible-core
    export PATH="$PATH:$HOME/.local/bin"
    pip3 install python-dateutil
    ansible-galaxy collection install hetzner.hcloud

  • python: Ansible basiert auf Python. Daher ist es die erste Voraussetzung. Python kann entweder mit dem Paketmanager des Betriebssystems oder durch Kompilieren aus den Quellen installiert werden. Python 3 wird dringend empfohlen.
  • pip: Pip ist der Paketmanager von Python. Wir installieren Molecule mit pip, da es noch nicht als OS-RPM verfügbar ist.
  • ansible: Ansible muss installiert sein. Wie Python kann auch dies entweder mit dem Paketmanager des Betriebssystems oder mit pip installiert werden.
    pip3 install ansible
  • molecule: Auch Molecule kann mit pip installiert werden.
    pip3 install --no-cache-dir molecule[ansible]
  • hetzner.hcloud collections (Optional): Dies hängt vom Anwendungsfall ab. Für diese Demo testen wir die Ansible-Rolle auf der hetzner-Infrastruktur, indem wir eine VM bereitstellen, uns über SSH verbinden und die Rolle auf der Ziel-VM ausführen. Die Sammlungen installieren wir mit dem Befehl ansible-galaxy collection install hetzner.hcloud.

Schritt 1 – Beispiel-Ansible-Rolle hinzufügen

Eine übliche Ansible-Rollenverzeichnisstruktur würde in etwa wie folgt aussehen:

holu@<your_host>:~/ansible_example_role$ ls -l
total 56
drwxr-xr-x   3 holu  staff    96 21 Nov 12:24 defaults
drwxr-xr-x   3 holu  staff    96 21 Nov 12:24 files
drwxr-xr-x   3 holu  staff    96 21 Nov 12:24 meta
drwxr-xr-x   3 holu  staff    96 21 Nov 12:24 tasks
drwxr-xr-x   3 holu  staff    96 21 Nov 12:24 vars

In dieser Demo werden wir unsere OS-Hardening-Rolle auf unserer VM-Infrastruktur anwenden. Angenommen die VM-Infrastruktur umfasst eine Mischung verschiedener Betriebssystemversionen, Haupt- und Nebenversionen. Eine kleine Änderung an der Hardening Rolle muss als Teil der Continuous Integration (CI) gründlich auf jeder OS-Variante getestet werden.

In diesem Tutorial wird ein sehr einfaches Beispiel verwendet, das so aussieht:

holu@<your_host>:~/os_hardening_role$ ls -l
drwxr-xr-x   3 holu  staff    96 21 Nov 12:24 tasks
holu@<your_host>:~/os_hardening_role/tasks$ ls -l
-rw-rw-r--   1 holu  staff   208 21 Nov 12:30 main.yml

Inhalt von os_hardening_role/tasks/main.yml:

Dies ist ein sehr einfaches Beispiel, das du verwenden kannst, um dem Tutorial zu folgen.

---
- name: OS Hardening
  hosts: localhost
  tasks:
    - name: OS Hardening task
      debug:
        msg: "Performing OS hardening tasks for {{ ansible_distribution }} {{ ansible_distribution_version }}"

Schritt 2 – Molecule-Tests zu einer vorhandenen Rolle hinzufügen

Führe im Rollenverzeichnis (in diesem Beispiel ~/os_hardening_role) den Befehl molecule init scenario aus. Dadurch wird das neue Unterverzeichnis molecule erstellt. Das Unterverzeichnis molecule enthält ein Standardverzeichnis mit Beispieldateien in folgender Struktur:

os_hardening_role/
├── tasks/
│       └── main.yml
└── molecule/
    └── <scenario_name>/
        ├── converge.yml
        ├── create.yml
        ├── destroy.yml
        └── molecule.yml

Szenarien dienen als Grundlage für eine Vielzahl leistungsstarker Funktionen innerhalb von Molecule. Betrachte ein Szenario als eine dedizierte Testsuite für Rollen oder Playbooks innerhalb einer Sammlung. Du kannst mehrere Szenarien erstellen und Molecule führt diese nacheinander aus.

Schritt 3 - Das Scenario-Layout

File Purpose
molecule.yml Dies ist der Schlüsselkonfigurationseinstiegspunkt für Molecule pro Szenario. Mit dieser Datei kannst du jedes Tool konfigurieren, das Molecule beim Testen deiner Rolle verwendet.
create.yml Diese Playbook-Datei wird zum Erstellen der Testumgebung verwendet, bevor deine Ansible-Rolle ausgeführt wird. Dies kann das Erstellen von Instanzen, Docker-Containern oder anderer Infrastruktur umfassen, die zum Testen der Ansible-Rolle erforderlich ist.
converge.yml Diese Playbook-Datei enthält den Aufruf der Rolle. Molecule ruft dieses Playbook mit ansible-playbook <your_playbook_file> in der Testumgebung auf, die mit create.yml eingerichtet wurde.
verify.yml Diese Playbook-Datei validiert die Rolle in der Testumgebung. Es ist mehr oder weniger gleichbedeutend mit assert in Unit-Tests.
destroy.yml Diese Playbook-Datei wird zum Zerstören und Entfernen der Testumgebung verwendet, nachdem die Rolle getestet wurde, z. B. Lösche eine Instanz, einen Docker-Container oder eine andere Infrastruktur, die während des Testprozesses erstellt wurde.

Anwendungsfall (Ein Beispiel)

Die folgenden Beispieldateien erstellen einen neuen Hetzner Cloud Server für die Testumgebung, testen eine Ansible-Beispielrolle namens os_hardening_role und löschen den Hetzner Cloud Server, sobald der Test abgeschlossen ist.

  • molecule.yml

    Gib Informationen zu erforderlichen Einstellungen und Konfigurationen für die Testumgebung an.

    ---
    dependency:
      name: galaxy
    driver:
      name: default
    platforms:
      - name: molecule-test-vm-ubuntu22
        image: "ubuntu-22.04"
      - name: molecule-test-vm-ubuntu24
        image: "ubuntu-24.04"
    provisioner:
      name: ansible
      connection_options:
        ansible_ssh_common_args: " -o ControlMaster=auto -o ControlPersist=60s -o PreferredAuthentications=publickey,password -F /tmp/ssh_config -o StrictHostKeychecking=no"
    verifier:
      name: ansible
    scenario:
      name: default
      ## Die folgende Testsequenz beginnt mit `destroy`, um eine saubere Infrastruktur sicherzustellen.
      test_sequence:
        - destroy
        - create
        - converge
        - verify
        - destroy
    # Du kannst den Lint bei Bedarf deaktivieren, es wird jedoch dringend empfohlen, ihn zu aktivieren, da YAML-Linting für die Verbesserung der Codequalitätsprüfungen sehr wichtig ist
    lint: |
     ansible-lint --exclude molecule/default/
    dependency Standardmäßig verlässt sich Molecule auf den Galaxy-Entwicklungsleitfaden, um Rollenabhängigkeiten zu handhaben.
    driver Standardmäßig verwendet Molecule den Delegated-Treiber, um Aufgaben zur Instanzerstellung auszulagern.
    platforms Molecule verwendet diese Informationen, um die Erstellung, Benennung und Gruppierung von Instanzen zu bestimmen. Wenn du deine Rolle anhand verschiedener Ubuntu-Varianten testen möchten (z. B. 18.04, 20.04, 22.04, 24.04 oder sogar mit anderen Distributionen wie CentOS usw.), kannst du diese in diesem Abschnitt definieren.
    provisioner Molecule bietet ausschließlich einen Ansible-Provisioner an, der den Instanzlebenszyklus gemäß dieser Konfiguration regelt.
    verifier Standardmäßig verwendet Molecule Ansible zum Erstellen gezielter Zustandsprüfungstests (z. B. Deployment-Smoke-Tests) auf der Zielinstanz.
    scenario Diese Konfiguration bestimmt die Reihenfolge, in welcher die Szenarien von Molecule ausgeführt werden.
  • create.yml

    Dadurch wird ein neuer Hetzner Cloud Server erstellt.

    Außerdem wird ssh_config generiert (weitere Informationen folgen in "Schritt 4"). Ansible benötigt diese Informationen, um sich per SSH mit dem neu erstellten Hetzner Cloud Server zu verbinden.

    Im Code unten:

    • Ersetze <your_ssh_key> mit dem Namen des SSH-Keys, den du in der Cloud Console hinterlegt hast.
    • Ersetze <your_hetzner_api_token> durch deinen tatsächlichen API-Token.
    ---
    - name: Create the test servers
      hosts: localhost
      connection: local
      tasks:
        - name: Create Hetzner cloud server with Ubuntu 24.04 und 22.04
          hetzner.hcloud.server:
            name: "{{ item.name }}"
            server_type: cx11
            image: "{{ item.image }}"
            location: fsn1
            ssh_keys:
              - <your_ssh_key>
            api_token: <your_api_token>
            state: present
          register: vm_output
          with_items:
            - { name: molecule-test-vm-ubuntu24, image: ubuntu-24.04 }
            - { name: molecule-test-vm-ubuntu22, image: ubuntu-22.04 }
    
        - name: Generate ssh_config
          template:
            src: ssh_config.j2
            dest: /tmp/ssh_config
          vars:
            hosts: "{{ vm_output.results }}"
    
        - name: Pause for 1 minute to wait for the SSH process to come up
          pause:
            seconds: 60
  • converge.yml

    Dadurch wird die Ansible-Beispielrolle os_hardening_role auf die Testumgebung angewendet. Mit der obigen Beispieldatei create.yml besteht die Testumgebung aus einem Hetzner Cloud Server mit Ubuntu 24.04 und einem Hetzner Cloud Server mit Ubuntu 22.04.

    Wenn du einen anderen Pfad verwendet hast, ersetze ../../../os_hardening_role/tasks entsprechend.

    ---
    - name: Converge
      hosts: all
      become: yes
      gather_facts: true
      tasks:
        - name: "Include os_hardening_role"
          include_role:
            name: "../../../os_hardening_role/tasks"
  • verify.yml

    Hier kannst du weitere Checks hinzufügen. Für diese Demo stellen wir sicher, dass die root-Anmeldung im Rahmen der Absicherung deaktiviert ist.

    ---
    - name: Verify OS Hardening Control
      hosts: all
      become: true
      tasks:
        - name: Ensure root login is disabled
          command: grep '^\s*#*PermitRootLogin' /etc/ssh/sshd_config
          register: root_login_config
          failed_when: "'yes' in root_login_config.stdout"
    
        - name: Print root login status
          debug:
            msg: "{{ root_login_config.stdout_lines[0] }}"
  • destroy.yml

    Dies entfernt den Server, der zuvor erstellt wurde. Der Dateiinhalt ist mehr oder weniger derselbe wie in create.yml, außer dass der "state" als "absent" markiert werden muss.

    Ersetze im unten stehenden Code <your_api_token> durch deinen eigenen API-Token.

    ---
    - name: Destroy the test servers
      hosts: all
      connection: local
      tasks:
        - name: Delete Hetzner cloud server with Ubuntu {{ item.image }}
          hetzner.hcloud.server:
            name: "{{ item.name }}"
            api_token: <your_api_token>
            state: absent
          with_items:
            - { name: molecule-test-vm-ubuntu24, image: ubuntu-24.04 }
            - { name: molecule-test-vm-ubuntu22, image: ubuntu-22.04 }

Schritt 4 - SSH-Konfiguration erstellen

Ansible verlässt sich in erster Linie auf SSH, um eine Verbindung zu einem Zielgerät herzustellen und Aufgaben auszuführen. Da wir für unsere Tests "Wegwerf"-VMs bereitstellen, erstellen wir für jede VM eine SSH-Konfiguration, um das Inventar aufzubauen.

  • Mit create.yml werden die Variablen in ssh_config.j2 ersetzt und unter /tmp/ssh_config als neue Datei gespeichert.

  • Mit molecule.yml nutzt Ansible die Informationen aus /tmp/ssh_config, um eine Verbindung zum neuen Server herzustellen.


Ein einfaches Jinja2-Template würde so aussehen:

Pfad: <role_name>/molecule/<your-scenario>/ssh_config.j2

Ersetze ~/.ssh/id_ed25519 durch den Pfad zu deinem eigenen privaten SSH-Schlüssel.

holu@<your_host>:~/os_hardening_role$ cat molecule/default/ssh_config.j2 
{% for host in hosts -%}
Host {{ host.hcloud_server.name }}
    HostName {{ host.hcloud_server.ipv4_address }}
    User root
    IdentityFile ~/.ssh/id_ed25519
{% endfor %}

Weitere Informationen zur Variable hcloud_server (z. B. name und ipv4_address) findest du in der Ansible-Dokumentation.

Schritt 5 - Molecule ausführen

Molecule bietet Befehle zum manuellen Verwalten des Lebenszyklus der Instanz, des Szenarios, der Entwicklungs- und Testwerkzeuge. Wir können Molecule jedoch auch mitteilen, dies automatisch innerhalb einer Szenariosequenz zu verwalten.

Vollständiger Lebenszyklusablauf von Molecule
└── default
    ├── dependency
    ├── cleanup
    ├── destroy
    ├── syntax
    ├── create
    ├── prepare
    ├── converge
    ├── idempotence
    ├── side_effect
    ├── verify
    ├── cleanup
    └── destroy

Für das Standardszenario kannst du die vollständige Lebenszyklussequenz im Rollenverzeichnis (in diesem Beispiel ~/os_hardening_role) mit dem Befehl molecule test aufrufen.

Wenn du den Namen des Szenarios angeben möchtest, kannst du das mit molecule test --scenario-name <your_scenario>.

Zusätzliche Lebenszyklus-Szenarien

Das oberenstehende Beispiel beinhaltet idempotence, was in einigen Fällen wichtig sein kann. Du kannst solche Szenarien in der Datei molecule.yml einfügen. Ansible wird damit erneut ausgeführt, um sicherzustellen, dass die Rolle die Kriterien für idempotence erfüllt. Weitere Informationen zu Szenarien findest du unter molecule-scenarios.

Ergebnis

Herzlichen Glückwunsch! Du hast erfolgreich eine Ansible-Rolle mit Molecule eingerichtet und getestet. Wir haben die Grundlagen und Test-Szenarien auf verschiedenen Ubuntu-Versionen behandelt. Erkunde weiter und wende Molecule auf deine Ansible-Projekte an, um robuste und zuverlässige Rollen zu erstellen.

Zusätzliche Ressourcen:

License: MIT
Want to contribute?

Get Rewarded: Get up to €50 in credit! Be a part of the community and contribute. Do it for the money. Do it for the bragging rights. And do it to teach others!

Report Issue
Try Hetzner Cloud

Get €20/$20 free credit!

Valid until: 31 December 2025 Valid for: 3 months and only for new customers
Get started
Want to contribute?

Get Rewarded: Get up to €50 credit on your account for every tutorial you write and we publish!

Find out more