Programmieren eigener Erweiterungen

Ansible ist ein äußerst vielseitiges Automatisierungs-Tool, das in vielen Bereichen der IT-Verwaltung eingesetzt wird. Obwohl es Hunderte von Modulen und Erweiterungen bietet, gibt es manchmal Szenarien, in denen die vorhandenen Module nicht alle Anforderungen abdecken. In solchen Fällen ist es möglich, eigene Erweiterungen für Ansible zu programmieren.

In diesem Blogbeitrag werden wir erläutern, wie du eigene Module in Python erstellst und diese in deinem Ansible-Setup nutzt. Wir behandeln Schritt für Schritt den Aufbau eines benutzerdefinierten Moduls und zeigen, wie du es in Playbooks integrieren kannst.


1. Warum eigene Erweiterungen?

Es gibt mehrere Gründe, warum du eigene Ansible-Erweiterungen programmieren möchtest:

  • Spezifische Anforderungen: Du benötigst Funktionen, die in den Standardmodulen nicht vorhanden sind.
  • Integration mit eigener Software: Du möchtest Ansible verwenden, um eigene Software oder maßgeschneiderte Dienste zu steuern.
  • Komplexere Logik: Du hast einen speziellen Anwendungsfall, der komplexere Logik oder Verzweigungen erfordert, als es die Standard-Module zulassen.

Ansible bietet die Möglichkeit, eigene Module und Plugins zu schreiben, die nahtlos in Playbooks und den Workflow integriert werden können.


2. Voraussetzungen

Für das Schreiben eigener Module benötigst du:

  • Grundkenntnisse in Python: Ansible-Module werden in Python geschrieben.
  • Ansible-Installation: Stelle sicher, dass Ansible auf deinem System installiert ist.

Du kannst die Ansible-Version überprüfen, indem du folgendes ausführst:

ansible --version

3. Aufbau eines Ansible-Moduls

Ein Ansible-Modul ist im Wesentlichen ein Python-Skript, das auf den Ziel-Hosts ausgeführt wird. Es muss bestimmte Strukturen und Regeln einhalten, damit es von Ansible korrekt erkannt und verwendet werden kann.

Grundstruktur eines Moduls

Ein einfaches Ansible-Modul besteht aus den folgenden Abschnitten:

  • Parameter-Definition: Welche Argumente das Modul akzeptiert.
  • Hauptlogik: Die eigentliche Funktionalität des Moduls.
  • Ergebnis zurückgeben: Das Modul muss ein Ergebnis (oder Fehler) zurückgeben, damit Ansible damit arbeiten kann.

Lass uns ein einfaches Modul erstellen, das eine Nachricht auf dem Remote-Host ausgibt.

Beispiel: Einfaches Hello-World-Modul

Erstelle eine neue Datei namens my_hello_module.py und füge folgenden Code ein:

#!/usr/bin/python

from ansible.module_utils.basic import AnsibleModule

def run_module():
    # Parameter, die vom Modul akzeptiert werden
    module_args = dict(
        name=dict(type='str', required=True)
    )

    # Initialisieren des Moduls mit den definierten Parametern
    module = AnsibleModule(
        argument_spec=module_args,
        supports_check_mode=True
    )

    # Parameter erhalten
    name = module.params['name']

    # Ergebnis-Daten vorbereiten
    result = dict(
        changed=False,
        message=''
    )

    # Logik: Wenn der Name "Ansible" ist, geben wir eine spezielle Nachricht aus
    if name == 'Ansible':
        result['message'] = 'Hallo Ansible!'
    else:
        result['message'] = f'Hallo {name}!'

    # Erfolgsmeldung zurückgeben
    module.exit_json(**result)

def main():
    run_module()

if __name__ == '__main__':
    main()

4. Integration des Moduls in Ansible

Damit Ansible dein Modul erkennen und verwenden kann, muss es an einem bestimmten Ort liegen oder explizit im Playbook referenziert werden.

Lokale Modulverwendung

Du kannst dein Modul im Verzeichnis library/ deines Playbook-Projekts ablegen. Ansible sucht automatisch nach Modulen in diesem Verzeichnis.

Ordnerstruktur:

my_playbook/
├── library/
│   └── my_hello_module.py
└── hello_playbook.yml

Verwendung im Playbook

Sobald du das Modul platziert hast, kannst du es in einem Playbook verwenden, als wäre es ein natives Ansible-Modul:

---
- hosts: localhost
  tasks:
    - name: Begrüße den Benutzer
      my_hello_module:
        name: "Ansible"

Führe das Playbook aus:

ansible-playbook hello_playbook.yml

Die Ausgabe sollte so aussehen:

TASK [Begrüße den Benutzer] 
ok: [localhost] => {
    "changed": false,
    "message": "Hallo Ansible!"
}

5. Erweiterung des Moduls mit zusätzlicher Funktionalität

Unser erstes Modul war sehr einfach, aber oft möchtest du komplexere Aufgaben ausführen. Lassen uns nun ein Modul erweitern, das Dateien auf dem Remote-Host erstellt und überprüft, ob die Datei bereits vorhanden ist.

Beispiel: Datei-Erstellungs-Modul

Hier ist ein erweitertes Modul, das eine Datei erstellt und überprüft, ob sie bereits existiert:

#!/usr/bin/python

import os
from ansible.module_utils.basic import AnsibleModule

def run_module():
    # Parameter-Definition
    module_args = dict(
        path=dict(type='str', required=True),
        content=dict(type='str', required=True)
    )

    # Initialisieren des Moduls
    module = AnsibleModule(
        argument_spec=module_args,
        supports_check_mode=True
    )

    # Parameter erhalten
    path = module.params['path']
    content = module.params['content']

    # Ergebnis-Objekt
    result = dict(
        changed=False,
        message='',
    )

    # Wenn die Datei nicht existiert, wird sie erstellt
    if not os.path.exists(path):
        try:
            with open(path, 'w') as f:
                f.write(content)
            result['changed'] = True
            result['message'] = f'Datei {path} erstellt.'
        except Exception as e:
            module.fail_json(msg=f'Fehler beim Erstellen der Datei: {e}')
    else:
        result['message'] = f'Datei {path} existiert bereits.'

    # Erfolgsmeldung zurückgeben
    module.exit_json(**result)

def main():
    run_module()

if __name__ == '__main__':
    main()

6. Test des erweiterten Moduls

Füge das Modul wieder in das library/-Verzeichnis ein und erstelle ein neues Playbook:

---
- hosts: localhost
  tasks:
    - name: Erstelle eine Datei mit Inhalt
      my_file_module:
        path: "/tmp/testfile.txt"
        content: "Hallo, dies ist ein Test!"

Führe das Playbook aus:

ansible-playbook create_file_playbook.yml

Wenn die Datei erstellt wurde, zeigt Ansible an, dass sich der Zustand geändert hat:

TASK [Erstelle eine Datei mit Inhalt]
changed: [localhost] => {
    "changed": true,
    "message": "Datei /tmp/testfile.txt erstellt."
}

Führst du das Playbook erneut aus, wird es erkennen, dass die Datei bereits existiert und keine Änderungen vornehmen:

TASK [Erstelle eine Datei mit Inhalt]
ok: [localhost] => {
    "changed": false,
    "message": "Datei /tmp/testfile.txt existiert bereits."
}

7. Debugging und Fehlerbehandlung

Es ist wichtig, dass dein Modul Fehler richtig behandelt. Ansible bietet dafür die Methode fail_json, mit der du Fehler sauber abfangen und melden kannst. Hier ein Beispiel:

module.fail_json(msg='Ein Fehler ist aufgetreten')

Dies gibt eine strukturierte Fehlermeldung zurück, die von Ansible verarbeitet und angezeigt wird.


Fazit

Die Programmierung eigener Ansible-Module ermöglicht es dir, Ansible um spezifische Funktionen zu erweitern, die in deiner IT-Umgebung benötigt werden. In diesem Tutorial haben wir ein einfaches Python-basiertes Modul erstellt, in Ansible integriert und erweitert. Der Vorteil der Eigenentwicklung liegt in der Flexibilität und der Möglichkeit, eigene Logiken und Aufgaben zu automatisieren, die mit den Standard-Modulen nicht abgedeckt sind.

Mit diesen Grundlagen kannst du nun komplexere Module entwickeln und Ansible an deine individuellen Anforderungen anpassen. Wenn du spezifische Anwendungsfälle hast oder Fragen zur Modul-Entwicklung, hinterlasse gerne einen Kommentar!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert