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!