Realisierung eigener Module in Bash oder Python

Ansible ist ein leistungsfähiges Automatisierungstool, das zahlreiche integrierte Module für die Verwaltung von Infrastrukturen bietet. Manchmal reichen diese jedoch nicht aus, um spezielle Anforderungen zu erfüllen. In solchen Fällen können eigene Module in Ansible geschrieben werden, entweder in Bash oder Python. In diesem Blogbeitrag zeigen wir, wie Sie ein eigenes Ansible-Modul erstellen, testen und verwenden können.

1. Grundlagen der Ansible-Module

Ein Ansible-Modul ist ein kleines Programm, das von Ansible auf den verwalteten Hosts (Zielsystemen) ausgeführt wird, um eine bestimmte Aufgabe zu erledigen. Jedes Ansible-Modul gibt eine JSON-Antwort zurück, die Informationen über den Status der Ausführung und die vorgenommenen Änderungen enthält.

Typische Aufgaben von Modulen:

  • Ändern von Dateien oder Konfigurationen auf einem Remote-Host
  • Ausführen von Befehlen und Skripten
  • Bereitstellen von Software und Diensten

Standardmäßig sind viele Ansible-Module in Python geschrieben, da es auf fast allen Linux-Systemen verfügbar ist. Allerdings kann auch jede andere Sprache verwendet werden, solange das Modul eine JSON-kompatible Ausgabe generiert und die erforderlichen Rückgabewerte liefert.

2. Modulstruktur

Ein Ansible-Modul muss bestimmte Rückgabewerte liefern:

  • changed: Gibt an, ob eine Änderung auf dem Zielsystem vorgenommen wurde (boolean).
  • failed: Gibt an, ob ein Fehler aufgetreten ist (boolean).
  • Andere Schlüssel: Können benutzerdefinierte Informationen oder Ergebnisse der Modulausführung enthalten.

Die Ausgabe muss im JSON-Format erfolgen, da Ansible die Ausgabe in dieser Form verarbeitet.

3. Erstellung eines Moduls in Bash

Wir beginnen mit der Erstellung eines einfachen Bash-Moduls. Stellen Sie sich vor, wir möchten ein Modul erstellen, das prüft, ob eine Datei existiert, und optional eine Datei erstellt.

3.1 Bash-Modul erstellen

Erstellen Sie eine Datei namens check_file.sh:

#!/bin/bash

# Parameter aus Ansible lesen
FILE_PATH=$1

# JSON-Ausgabe vorbereiten
if [[ -f "$FILE_PATH" ]]; then
  # Datei existiert, keine Änderung
  echo "{\"changed\": false, \"msg\": \"Datei existiert bereits\", \"path\": \"$FILE_PATH\"}"
  exit 0
else
  # Datei existiert nicht, erzeuge Datei
  touch "$FILE_PATH"
  if [[ $? -eq 0 ]]; then
    echo "{\"changed\": true, \"msg\": \"Datei wurde erstellt\", \"path\": \"$FILE_PATH\"}"
    exit 0
  else
    echo "{\"failed\": true, \"msg\": \"Konnte Datei nicht erstellen\", \"path\": \"$FILE_PATH\"}"
    exit 1
  fi
fi

Dieses Bash-Skript:

  1. Liest den Dateipfad als Eingabeparameter.
  2. Überprüft, ob die Datei existiert.
  3. Wenn sie nicht existiert, wird die Datei erstellt.
  4. Gibt eine JSON-Antwort zurück, die den Status der Änderung anzeigt.

3.2 Integration in Ansible Playbook

Um dieses Modul in einem Ansible Playbook zu verwenden, können wir es mit dem command Modul aufrufen.

---
- hosts: localhost
  tasks:
    - name: Überprüfe und erstelle Datei
      command: /path/to/check_file.sh /tmp/testdatei.txt
      register: result

    - name: Ausgabe des Ergebnisses
      debug:
        var: result.stdout

4. Erstellung eines Moduls in Python

Python ist aufgrund seiner Integration in Ansible die empfohlene Sprache für die Erstellung von Modulen. Hier ist ein einfaches Beispiel für ein Python-Modul, das dieselbe Aufgabe wie das Bash-Skript übernimmt.

4.1 Python-Modul erstellen

Erstellen Sie eine Datei namens check_file.py:

#!/usr/bin/python

import os
import json
import sys

def main():
    # Parameter von Ansible erhalten
    file_path = sys.argv[1]

    result = {
        "changed": False,
        "failed": False,
        "msg": "",
        "path": file_path
    }

    # Überprüfe, ob die Datei existiert
    if os.path.exists(file_path):
        result["msg"] = "Datei existiert bereits"
    else:
        # Versuche, die Datei zu erstellen
        try:
            with open(file_path, "w") as file:
                file.write("")
            result["changed"] = True
            result["msg"] = "Datei wurde erstellt"
        except Exception as e:
            result["failed"] = True
            result["msg"] = f"Konnte Datei nicht erstellen: {str(e)}"

    # JSON-Antwort ausgeben
    print(json.dumps(result))

if __name__ == "__main__":
    main()

4.2 Integration in Ansible Playbook

Ähnlich wie beim Bash-Skript können wir das Python-Modul in einem Ansible Playbook verwenden:

---
- hosts: localhost
  tasks:
    - name: Überprüfe und erstelle Datei (Python)
      command: /path/to/check_file.py /tmp/testdatei.txt
      register: result

    - name: Ausgabe des Ergebnisses
      debug:
        var: result.stdout

5. Entwicklung von Ansible-Modulen mit ansible.module_utils.basic

Ansible bietet eine spezielle Python-Bibliothek, ansible.module_utils.basic, die die Erstellung eigener Module vereinfacht. Sie nimmt einem das Parsen von Eingabedaten und das Erstellen von JSON-Antworten ab.

5.1 Verbesserte Version des Python-Moduls mit AnsibleModule

#!/usr/bin/python

from ansible.module_utils.basic import AnsibleModule
import os

def main():
    module_args = dict(
        path=dict(type='str', required=True)
    )

    module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)

    file_path = module.params['path']

    result = {
        "changed": False,
        "path": file_path
    }

    # Check-Modus: Keine Änderungen vornehmen
    if module.check_mode:
        if os.path.exists(file_path):
            module.exit_json(**result)
        else:
            result["changed"] = True
            module.exit_json(**result)

    # Überprüfe, ob die Datei existiert
    if os.path.exists(file_path):
        result["msg"] = "Datei existiert bereits"
    else:
        # Versuche, die Datei zu erstellen
        try:
            with open(file_path, "w") as file:
                file.write("")
            result["changed"] = True
            result["msg"] = "Datei wurde erstellt"
        except Exception as e:
            module.fail_json(msg=f"Konnte Datei nicht erstellen: {str(e)}")

    module.exit_json(**result)

if __name__ == "__main__":
    main()

Dieses Modul nutzt AnsibleModule, um Eingaben zu verarbeiten und die JSON-Ausgabe zu erstellen. Es unterstützt auch den Check-Modus, der ohne Änderungen auf den Hosts getestet werden kann.

5.2 Verwendung im Playbook

---
- hosts: localhost
  tasks:
    - name: Überprüfe und erstelle Datei (AnsibleModule)
      check_mode: yes
      command: /path/to/check_file.py /tmp/testdatei.txt
      register: result

    - name: Ausgabe des Ergebnisses
      debug:
        var: result.stdout

6. Testen und Validieren eigener Module

Um ein selbst erstelltes Modul gründlich zu testen:

  1. Modultests: Führen Sie es mit verschiedenen Szenarien aus (Datei existiert bereits, Schreibrechte fehlen, etc.).
  2. Check-Modus verwenden: Testen Sie, ob Ihr Modul den Check-Modus korrekt unterstützt.
  3. Integrationstests: Verwenden Sie das Modul in verschiedenen Playbooks, um sicherzustellen, dass es robust ist.

Fazit

Die Erstellung eigener Module in Ansible, sei es in Bash oder Python, ist eine mächtige Möglichkeit, spezifische Aufgaben zu automatisieren. Python-Module bieten dabei den Vorteil einer besseren Integration in Ansible und die Möglichkeit, die AnsibleModule-Bibliothek zu nutzen. Durch die Erstellung eigener Module können Sie die Grenzen der Standardmodule erweitern und maßgeschneiderte Lösungen für Ihre Infrastruktur schaffen.

Schreibe einen Kommentar

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