Module für Ansible - so geht's

Ansible: Eigene Module für Ansible aufsetzen

Daniel Stender

© Shutterstock / PowerUp

Ansible von Red Hat hat sich in den letzten Jahren zu einem beliebten Konfigurationswerkzeug gemausert und spielt eine wichtige Rolle bei DevOps und Cloud Computing. Der reiche Fundus an eingebauten Modulen begründet die umfangreiche Funktionalität. Dieser Artikel zeigt, wie Sie selbst Module aufsetzen können, um diese Funktionsvielfalt weiter zu vergrößern. Dabei kommt Python zu Einsatz.

Egal ob Provisioner, Fernkonfigurations-Werkzeug oder Tool für Infrastructure-as-Code: Ansible aus dem Portfolio von Red Hat zählt mittlerweile zu den beliebtesten Lösungen für die automatisierte Steuerung von physischen und virtuellen Server-Landschaften sowie für das Aufspielen von Applikationen. Die Open-Source-Software ist ausgereift (aktuelle Version 2.8) und verfolgt für die Konfiguration von hauptsächlich Linux-Servern, gegenüber anderen deklarativen Lösungen („was“ soll erreicht werden) wie Puppet und Chef, einen alternativen imperativen Ansatz („wie“ soll etwas erreicht werden). Ansible kommt ohne einen Agenten auf Zielmaschinen aus, wobei das unkomplizierte SSH-Protokoll als Zugang dient. Ansible wird auf breiter Front beim Cloud Computing verwendet und dort unter anderem auch zur Bestückung von Maschinen-Images eingesetzt, aber auch in vielen DevOps-Toolchains hat es einen festen Platz. Die Bedeutung der Software lässt sich auch an der Tatsache ablesen, dass unter den abgefragten Themengebieten des Linux Professional Institute (LPI), für das Zertifikat 701 „DevOps Tools Engineer“, Ansible noch vor Docker, die stärkste Gewichtung zukommt.

In einem älteren Artikel [1] ging es darum, wie Sie mit dem Einsatz von Rollen (Roles) ein komplexes Multi-Tier-Setup mit Load Balancer, redundanten Web-Frontends und Datenbank-Backend für die Kernkomponente Ansible-Engine (der auf CLI-Werkzeugen basierte Provisioner wird, im Gegensatz zu der Enterprise-Variante Ansible Tower, so bezeichnet) aufsetzen können. Dabei ist das Zusammenspiel von Maschineninventar (Inventory), Ablaufplan (Playbook) und den eingebauten Modulen vorgestellt worden. Diesmal möchte ich speziell das Thema der Module noch weiter vertiefen. Insbesondere geht es darum, wie Sie selbst solch eine Komponente für einen beliebigen Anwendungszweck aufsetzen und verwenden können.

Ansible-Module

Die mitgelieferten Module sind sozusagen der Kern von Ansible. Mittlerweile ist die Zahl der offiziell eingebundenen Stücke bereits bei Version 2.7 auf über 2000 angewachsen (die Zahl kann auf Linux-Kontrollknoten ermittelt werden mit: $ ansible-doc -l | wc -l). Das gibt zunächst einmal die relativ übersichtliche Anzahl von Standardmodulen für Handgriffe auf Linux-Servern und das Aufspielen von Dateien und Jinja2-Templates. Darüber hinaus existieren viele spezielle Module, welche einen gesamten, für die Provisionierung von Software benötigten, Werkzeugkasten abbilden. Dieser beinhaltet den Umgang mit Versionskontrollsystemen, Codehostern wie Github, das Einspielen von Softwarepaketen für die verwendete Linux-Distribution und von Paketen aus offiziellen Paketquellen wie dem Python Package Index oder Ruby Gems usw. Eine weitere große Gruppe bilden die vielen Module für die Kontrolle von Applikationen, wie zum Beispiel der Webserver Apache2 und Nginx. Außerdem gibt es viele Module für die Benutzung der Services von Public Cloud-Providern. Eine besondere Stellung nehmen die Module für die Steuerung von Network-Appliances wie Router, Switches oder Firewall-Systeme ein, für die Ansible mittlerweile eine gewisse Domäne zukommt. Da diese Systeme oftmals über die normale Vorgehensweise des Provisioners (per SSH einloggen, Module mitsamt Ausführungspaket auf dem Zielsystem aufspielen und diese dort ausführen) nicht zugänglich sind, muss die Steuerung einer solchen Hardware dabei anders umgesetzt werden.

Die Architektur von Ansible ist insgesamt für die prozedurale Ausführung von Modulen ausgelegt. Dabei sind die vom Anwender zu schreibenden Playbooks dafür da, die zur Verfügung stehenden Module, auf eigene Art und Weise zusammenzustellen, um auf den im Inventar verzeichneten Zielmaschinen (Hosts), bestimmte Ziele zu erreichen. Das bedeutet aber auch, dass die Funktionalität des Provisioners vollständig durch seine Module bestimmt ist – wenn man von der Möglichkeit absieht, mit Ansible Shellbefehle auf Hosts auszuführen. Zudem hat sich der Anwender immer danach zu richten, wie die Entwickler eines Moduls vorgesehen haben, es zu verwenden. Ob darunterliegende Werkzeuge wie etwa git, svn (Subversion), sed und reguläre Ausdrücke durch ein darüberliegendes Modul angemessen repräsentiert sind, daran kann in dem ein oder anderen Fall durchaus Kritik geübt werden.

Bei Ansible gehören die Module zum eingebauten Plugin-System, weshalb beliebige Drittanbieter-Lösungen und auch eigene Entwicklungen unkompliziert eingesetzt werden können, um Unzulänglichkeiten bei den offiziell eingebundenen und mitgelieferten Stücken zu überwinden. Bei Modulen handelt es sich immer um vollständige, selbstständig laufende, kleinere Programme. Und da Ansible an der Schnittstelle zu den auf der Zielmaschine ausgeführten Modulen lediglich ein bestimmtes JSON-Objekt als Rückgabe erwartet, sind Sie bei der Wahl der Programmiersprache für eigene Lösungen grundsätzlich völlig frei. Sie geben in einem Playbook unter tasks: immer den Namen einer ausführbaren Datei im Modul-Suchpfad an (ohne Suffixe wie .py). Da Ansible selbst, mitsamt den mitgelieferten Modulen, in Python geschrieben ist, und da aus dem Code der Engine auch einige Hilfsbibliotheken für eigene Entwicklungen zu Verfügung stehen, soll diese Sprache hier im Mittelpunkt stehen.

 
vagrant@contrib-stretch:~$ sudo mysql_secure_installation

NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB
      SERVERS IN PRODUCTION USE!  PLEASE READ EACH STEP CAREFULLY!

In order to log into MariaDB to secure it, we'll need the current
password for the root user.  If you've just installed MariaDB, and
you haven't set the root password yet, the password will be blank,
so you should just press enter here.

Enter current password for root (enter for none):
OK, successfully used password, moving on...

Setting the root password ensures that nobody can log into the MariaDB
root user without the proper authorisation.

Set root password? [Y/n] Y
New password:
Re-enter new password:
Password updated successfully!
Reloading privilege tables..
 ... Success!

By default, a MariaDB installation has an anonymous user, allowing anyone
to log into MariaDB without having to have a user account created for
them.  This is intended only for testing, and to make the installation
go a bit smoother.  You should remove them before moving into a
production environment.

Remove anonymous users? [Y/n] Y
 ... Success!

Normally, root should only be allowed to connect from 'localhost'.  This
ensures that someone cannot guess at the root password from the network.

Disallow root login remotely? [Y/n] Y
 ... Success!

By default, MariaDB comes with a database named 'test' that anyone can
access.  This is also intended only for testing, and should be removed
before moving into a production environment.

Remove test database and access to it? [Y/n] Y
 - Dropping test database...
 ... Success!
 - Removing privileges on test database...
 ... Success!

Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.

Reload privilege tables now? [Y/n] Y
 ... Success!

Cleaning up...

All done!  If you've completed all of the above steps, your MariaDB
installation should now be secure.

Thanks for using MariaDB!

MySQL-Server absichern

Ein MySQL-Server und auch der Fork MariaDB werden etwa in Linux-Paketen gewöhnlich mit dem Shellskript mysql_secure_installation ausgeliefert (es gibt vereinzelt Binärcode-Varianten davon). Vom Hersteller wird empfohlen, dieses Skript direkt nach der Installation zunächst einmal auszuführen. Das Skript behebt eine Reihe von Sicherheitslücken, welche – wenn nicht geschlossen – den Datenbank-Server angreifbar machen. Das Skript fragt zunächst ein eventuell noch nicht gesetztes Root-Kennwort ab und stellt es ein. Außerdem macht es den Zugriff des Root-Users – von außerhalb des eigenen Hosts – unmöglich und löscht einen voreingestellten anonymen User sowie eine eventuell vorhandene Testdatenbank. Die meisten der Punkte spielen bei aktuelleren Versionen oftmals keine Rolle mehr und auch ein Root-Kennwort wird bei der manuell ausgelösten Installation des Linux-Paketes des Datenbank-Servers bereits verlangt. Nichtsdestotrotz ist es weiterhin empfehlenswert, das Skript, nach der Installation des Servers, einmal auszuführen (Listing 1) und diese Themen ohne großen Aufwand abzuräumen.

DevOpsCon Istio Cheat Sheet

Free: BRAND NEW DevOps Istio Cheat Sheet

Ever felt like service mesh chaos is taking over? As a follow-up to our previous cheat sheet featuring the most important commands and functions, DevOpsCon speaker Michael Hofmann has put together the 8 best practices you should keep in mind when using Istio.

Dieses Shellskript mit dem shell-Modul auf einem Host von Ansible aus auszulösen, ist nicht zu empfehlen (die erwarteten Eingaben von „Y“(es) und des gewünschten Root-Kennworts lassen sich mit echo in das Skript pipen). Selbst wenn es zunächst funktionieren sollte, so hat Ansible beim Durchlauf keinerlei Kontrolle darüber, was dabei auf dem Host stattfindet, wodurch alles dem „im Dunkeln“ laufenden Skript überlassen ist. Außerdem fragt das Skript zu Beginn nach dem aktuellen Root-Kennwort (leer oder nicht) und so müssen Sie ziemlich herumbasteln, damit Ihr Playbook auch beim mehrmaligen Auslösen an dieser Stelle immer sauber durchläuft. Beim Cloud Computing, wo es schnell und ständig frische Server gibt, wird auch gerne mal ignoriert, dass ein Ansible-Playbook mehrmals durchlaufen werden können muss und dabei immer dasselbe Ergebnis sicherstellt (das ist das Prinzip der Idempotenz). Einen „Kamikaze“-Stil sollten Sie, auch bei der Entwicklung von Modulen, aber grundsätzlich vermeiden.

Etwas eleganter ist die Lösung, sich die für die Hardening-Operationen am Datenbank-Server benötigten SQL-Anweisungen aus mysql_secure_installation herauszusuchen (siehe jeweils unter action in Listing 2) und diese anschließend einzeln mit den CLI-Clients mysql oder mysqladmin und dem command-Modul auf Hosts nacheinander abzusetzen. Auf diese Weise können dabei eventuell auftretenden Fehler an Ansible zurückgemeldet werden.

Ein noch besserer Ansatz ist hierbei allerdings das mysql_secure_installation Skript mit den zur Verfügung stehenden Modulen in einem Playbook nachzustellen. Dabei könnten Sie die MySQL-Module von Ansible einsetzen, um diese Hardening-Maßnahmen vorzunehmen. Mit mysql_user stellen Sie ein Root-Kennwort ein und stellen den Zugang „%“ für Root (Zugriff von außen) und den User „“ (anonym) auf absent. Mit mysql_db legen Sie für die Datenbank „test“ fest, damit sie auch absent ist. Ansible-Module arbeiten grundsätzlich statusbasiert: Gibt es gar keinen anonymen User und keine Testdatenbank, ist das genau das, was Sie anstreben. Zwar gibt hierbei noch einen Fallstrick mit dem Root-Kennwort bei mehrmaligem Durchlauf (es muss in /root/.my.cnf hinterlegt werden, siehe unten) aber dieselben Ergebnisse wie von mysql_secure_installation können Sie auf diese Weise erreichen, ohne Ansible allzu „dreckig“ einzusetzen.

Das Shellskript mit Ansible-Module auf diese Weise zu ersetzen, benötigt einige Schritte im Playbook. Dann haben Sie mehrere Zeilen „Boilerplate“-Code, der dann eventuell immer wieder in neue Projekte mit MySQL-Servern rüberkopiert werden kann. Das ist genau die richtige Gelegenheit, sich ein eigenes, einfach wiederzuverwendendes Modul genau für diesen Zweck aufzusetzen!

#!/usr/bin/python
# -*- coding: utf-8 -*-

import datetime
import os
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.mysql import mysql_driver, mysql_driver_fail_msg

def sql_anweisung(cursor, module, action, description):
    try:
        cursor.execute(action)
    except Exception as e:
        failmsg = 'Fehler beim ' + description + ': ' + e.args[1]
        module.fail_json(msg=failmsg)
    return True

def main():
    args = {'rootpw': {'required': True, 'type': 'str'}}
    module = AnsibleModule(argument_spec=args, supports_check_mode=True)

    if mysql_driver is None:
        module.fail_json(msg=mysql_driver_fail_msg)

    config_file = '/root/.my.cnf'
    try:
        if os.path.exists(config_file):
            mydb = mysql_driver.connect(read_default_file=config_file)
        else:
            mydb = mysql_driver.connect()
    except Exception:
        module.fail_json(msg='Verbindung zum Datenbank-Server nicht möglich!')

    cursor = mydb.cursor()

    if module.check_mode:
        module.exit_json(changed=True)

    startd = datetime.datetime.now()

    action = "UPDATE mysql.user SET Password=PASSWORD('%s') WHERE User='root';" % module.params['rootpw']
    sql_anweisung(cursor, module, action, 'Setzen des Root-Kennworts')

    action = "DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');"
    sql_anweisung(cursor, module, action, 'Ändern der Zugänge für Root')

    action = "DELETE FROM mysql.user WHERE User='';"    
    sql_anweisung(cursor, module, action, 'Löschen des anonymen Users')

    action = 'DROP DATABASE IF EXISTS test;'
    sql_anweisung(cursor, module, action, 'Löschen der Test-Datenbank')

    action = 'FLUSH PRIVILEGES;'
    changed = sql_anweisung(cursor, module, action, 'Modulabschluss')

    endd = datetime.datetime.now()
    delta = endd - startd

    result = {
        'changed': changed,
        'start': str(startd),
        'end': str(endd),
        'delta': str(delta),
        'rootpw': module.params['rootpw'],
        'message': 'Have a nice day!'
    }

    module.exit_json(**result)

if __name__ == '__main__':
    main()

Eigenes Modul

Listing 2 zeigt ein Ansible-Modul für das Hardening eines MySQL-Datenbankservers nach seiner Installation, welches das Maintenance-Skript mysql_secure_installation ersetzt. Das Modul ist für Python 2 geschrieben, das zurzeit noch der Default-Interpreter von Ansible ist. Module laufen zwar, wie erwähnt, grundsätzlich selbstständig, dennoch werden im Beispiel Bibliotheken aus der Ansible Engine importiert, die im Suchpfad von einem Python 3-Interpreter erst einmal nicht verfügbar sind.

Die im Beispiel importierte allgemeine Hilfsbibliothek module_utils/basic.py  bietet mit der Klasse AnsibleModule ein ausgebautes Framework für eigene Module, zu denen die Methoden exit_json() und fail_json() gehören, welche konforme Rückgabe-Objekte erzeugen. Bei der Instanziierung der Klasse – im Beispiel als module in main() – werden unter argument_spec, die gewünschten Modulparameter als Dictionary festgelegt. Mit args wird eingestellt, dass das Modul einen String rootpw beim Aufruf im Playbook erwartet. Darüber hinaus legen sie bei AnsibleModule mit dem Parameter supports_check_mode fest, dass das Modul einen „Dry Run“ mit der Kommandozeilenoption –check von dem CLI-Tool ansible-playbook mitmacht. Steht dieser Schalter auf False, wird das Modul beim Dry Run eines Playbooks bei Verwendung übersprungen.

Danach importieren Sie aus der Engine die Hilfsbibliothek module_utils/mysql.py, die auch von den oben genannten Modulen mysql_user und mysql_db genutzt wird. Diese Hilfsbibliothek importiert selbst die für die Kommunikation mit einem MySQL-Server benötigte Python-Bibliothek auf dem Host, wobei alternativ entweder PyMySQL (import pymysql) oder MySQL-Python (import MySQLdb)eingebunden werden können. Die jeweils vorhandene Bibliothek steht danach aus mysql.py als mysql_driver zur Verfügung. Die Hilfsbibliothek stellt für den Fall, dass der Import der MySQL-Bibliothek scheitert, mit mysql_driver_fail eine Standardfehlermeldung zur Verfügung. In Ihrem Modul fragen Sie unter main() als zweiten Schritt zunächst ab, ob die MySQL-Bibliothek eingebunden worden ist und beenden es im gegenteiligen Fall (mysql_driver ist in dem Fall None) mit module.json_fail(), wobei hier diese Fehlermeldung als msg zurückgegeben wird.

Die Hilfsbibliothek mysql.py stellt darüber hinaus die Funktion mysql_connect() zur Verfügung, die mit mysql_driver.connect() die Verbindung zum Datenbank-Server aufbaut. Zudem wird damit ein sogenannter Cursor zur Verfügung gestellt, den die beiden unterstützten MySQL-Bibliotheken anbieten, um SQL-Anweisungen an den Server abzusetzen. Diese Funktion ist etwas kompliziert einzusetzen, allerdings kann in ihrem Modul, wie auch im Beispiel, direkt mit mysql_driver.connect() gearbeitet werden. In dem Fall müssen Sie nur den Cursor noch einmal selbst generieren – im Beispiel geschieht das mit mydb.cursor(). Ein weiteres Anwendungsbeispiel für MySQL-Python finden Sie in einem Vorgängerartikel [1].

In die Abfrage, ob die Konfigurationsdatei /root/.my.cnf auf dem Host existiert (das ist mit os.path.exists() aus der Python-Standardbibliothek möglich), betten sie am besten den Aufruf von mysql_driver.connect() ein . Diese Datei bewahrt das Root-Kennwort für den MySQL-Server auf und ist notwendig für die Verbindung dahin, wenn (etwa bei einem vorherigen Durchlauf) bereits ein Root-Kennwort gesetzt worden ist. Geben Sie in dem Fall den Pfad zu der Datei mit dem Argument read_default_file bei mysql_driver.connect() mit, um das Kennwort daraus zu berücksichtigen. Wie Sie diese Datei auf dem Host im Ansible-Playbook generieren, dazu weiter unten. Gibt es bei der Verbindung zum MySQL-Server Schwierigkeiten und tritt dabei ein Fehler mit einer Exception auf (die try-except-Konstruktion im Beispiel überprüft das), dann brechen Sie das Modul an dieser Stelle wieder mit module.exit_fail() ab.

Ob ein Dry Run stattfindet, können Sie über AnsibleModule.check_mode abfragen. Das Modul beendet sich in dem Fall mit exit_json() und mit changed auf True gesetzt – der Einfachheit halber noch bevor SQL-Anweisungen zum Datenbank-Server abgesetzt werden. Die Checkmode-Funktionalität können Sie hier noch aufwändiger implementieren, doch für das Beispiel soll es als Ergebnis genügen, dass die MySQL-Bibliothek erfolgreich importiert worden ist und die Verbindung zum MySQL-Server gelingt, was doch recht erfolgversprechend ist.

Der Hauptteil des Moduls setzt die vor main() definierte Funktion sql_anweisung() ein paarmal ein, um die gewünschten SQL-Anweisungen (jeweils als action) für das Server-Hardening der Reihe nach mit cursor.execute() an den MySQL-Server im Hintergrund abzusetzen. Sie geben hier jeweils mit description eine Kurzbeschreibung der jeweiligen Aktion mit, die im Falle irgendeines Fehlers, zusammen mit der Exception-Meldung wieder mit fail_json() als msg zurückgegeben wird.

Zum Abschluss packen Sie ein result-Objekt, das als changed-Status „True“ vom letzten erfolgreichen Aufruf von sql_anweisung() zurückgibt, das noch einmal rootpw auswirft und das auch noch eine message an den Anwender mitschickt. Es enthält darüber hinaus, wie bei vielen anderen Modulen, einen Start- und einen Beendigungs-Zeitstempel mit Delta, die Sie wie im Beispiel mit datetime.datetime.now() aus der Stdlib gewinnen können. Notwendig für das von exit_json() zurückgegebene JSON-Objekt ist alleine changed (der „Change“), alle anderen Informationen (in Ansible-Sprech „State“ genannt) können Sie völlig frei gestalten.

---
- hosts: all
  tasks:
  - name: MariaDB und Python-Bibliothek installieren
    apt:
      name:
        - default-mysql-server
        - python-mysqldb
      state: latest
      update_cache: yes

  - name: neues Root-Kennwort erzeugen
    command: "openssl rand -hex 7"
    register: new_rootpw
    check_mode: no

  - mymodule:
      rootpw: "{{ new_rootpw.stdout }}"

  - name: Root-Kennwort hinterlegen
    template:
      src: my.cnf.j2
      dest: /root/.my.cnf


Listing 4: my.cnf.j2
[client]
user=root
password={{ new_rootpw.stdout }}

Modul verwenden

Listing 3 zeigt ein Ansible-Playbook, mit dem Sie Ihr selbst geschriebenes Modul laufen lassen können. Das Playbook ist für Debian geschrieben. Als ersten Schritt installieren Sie mit dem Paketmanager-Modul apt den MySQL-Server und die vom Modul benötigte MySQL-Bibliothek (das Metapaket default-mysql-server zieht in Debian 9.9 zum Beispiel das Paket mariab-server-core-10.1).

Als zweiten Schritt generieren Sie per command-Modul auf dem Host, dynamisch mit dem CLI-Tool openssl, von der standardmäßig installierten OpenSSL-Bibliothek ein Kennwort (es gibt eine Reihe Alternativen dazu). Mit register bewahren Sie die Rückgabe davon in der Variable new_rootpw auf. Diesen Schritt stellen Sie mit check_mode: no dann noch so ein, dass er auch bei einem Dry Run dieses Playbooks mit ausgeführt wird. Der Grund dafür ist, dass mymodule – für welches Sie im folgenden Schritt new_rootpw.stdout (das beinhaltet die Ausgabe von openssl aus der Rückgabe von command) für den Parameter rootpw auswerten – crasht, wenn diese Variable gar nicht existiert und folglich auch nichts übergeben wird, wenn im Dry Run der vorherige Schritt übersprungen worden ist (einen Schutz vor einem solchen Crash ließe sich im Modul zusätzlich implementieren).

Im letzten Schritt des Playbooks legen Sie auf dem Host, mit dem Modul template, die Konfigurationsdatei /root/.my.cnf an, die Sie als Template im Arbeitsverzeichnis auf dem Kontrollknoten bereitlegen und damit beim Einspielen new_rootpw nocheinmal auswerten (Listing 4). Das Playbook ist der Einfachheit halber erst einmal so geschrieben, dass bei jedem Durchlauf ein neues Kennwort generiert wird, dieses dann für den Root-User im MySQL-Server gesetzt und danach in der Konfigurationsdatei auf dem Host abgelegt wird. So kann mymodule sich bei jedem neuen Durchlauf erst einmal wieder erfolgreich mit dem Server verbinden und anschließend das jeweils neugenerierte Root-Kennwort schreiben.

Sie können das Modul in einen für Drittanbieter-Module vorgesehenen Suchpfad legen (auf einem Linux-Kontrollknoten ist das unter anderem ~/.ansible/plugins/modules) oder es direkt aus dem Arbeitsverzeichnis verwenden, wenn Sie in Ihrer ansible.cfg im selben Verzeichnis die Zeile library=./ ergänzen. Mit dem Tool ansible-playbook lassen Sie das Playbook, wie üblich auf in einem Maschineninventar verzeichneten Server, mit Debian-Installationen laufen. Die Logs von einem Lauf dieses Playbooks sehen Sie in Listing 5.

$ ansible-playbook -i hosts playbook.yml -v

PLAY [all] ***********************************************************************************

TASK [Gathering Facts] ***********************************************************************************
ok: [127.0.0.1]

TASK [MariaDB und Python-Bibliothek installieren] ***********************************************************************************
ok: [127.0.0.1] => {"cache_update_time": 1562836055, "cache_updated": false,
"changed": false}

TASK [neues Root-Kennwort erzeugen] ***********************************************************************************
changed: [127.0.0.1] => {"changed": true, "cmd": ["openssl", "rand", "-hex",
"7"], "delta": "0:00:00.006694", "end": "2019-07-11 13:35:56.148883", "rc": 0,
"start": "2019-07-11 13:35:56.142189", "stderr": "", "stderr_lines": [],
"stdout": "89f39f3ca646c0", "stdout_lines": ["89f39f3ca646c0"]}

TASK [mymodule] ***********************************************************************************
changed: [127.0.0.1] => {"changed": true, "delta": "0:00:00.023014", "end":
"2019-07-11 13:35:56.460611", "message": "Have a nice day!", "rootpw":
"89f39f3ca646c0", "start": "2019-07-11 13:35:56.437597"}

TASK [Root-Kennwort hinterlegen] ***********************************************************************************
changed: [127.0.0.1] => {"changed": true, "checksum":
"dd90474efc6d8edf9a73c749398a8ca21c7eab02", "dest": "/root/.my.cnf", "gid": 0,
"group": "root", "md5sum": "74adcf37f01d9bd5e5a0f612ff855238", "mode": "0644",
"owner": "root", "size": 43, "src": "/home/vagrant/.ansible/tmp/ansible-tmp-
1562852158.83-130054503160835/source", "state": "file", "uid": 0}

PLAY RECAP ***********************************************************************************
127.0.0.1                  : ok=5    changed=3    unreachable=0    failed=0   

Fazit

Mit eigenen Modulen lässt sich der Funktionsumfang von Ansible beliebig erweitern. Im „Developer‘s Guide“ in der Ansible-Dokumentation gibt es weitere Informationen zu diesem Thema.
Da der Provisioner und die vielen offiziell eingebundenen Module selbst in Python geschrieben sind, bietet es sich an, diese Programmiersprache für eigene Entwicklungen einzusetzen. Für diesen Zweck gibt es in der Ansible Engine einen Fundus von Hilfsbibliotheken, die das Aufsetzen von eigenen Modulen stark vereinfachen. Das Beispiel ist durchaus funktionell, obwohl etwa noch Checks fehlen, die danach fragen, ob die gewünschten Ergebnisse nicht schon bereits vorliegen. An dem Timedelta sehen Sie dennoch, dass der Ressourcenverbrauch durch das gegebenenfalls unnötige Absetzen dieser SQL-Anweisungen hier vernachlässigbar klein ist. Bei größeren Projekten und bei aufwändigeren Operationen kann das allerdings durchaus ein Missstand sein.

Auf jeden Fall fehlen hier aus Platzgründen die Elemente für die Moduldokumentation (die Sektionen für ANSIBLE_METADATA, DOCUMENTATION, EXAMPLES und RETURN), die aber verlangt sind, falls Sie planen, Ihre eigenen Entwicklungen als Kandidaten für die Aufnahme in den offiziellen Fundus der Module von Ansible aufzustellen.

Geschrieben von
Daniel Stender
Daniel Stender
Daniel Stender (https://danielstender.com) ist freier DevOps Engineer und arbeitet unter anderem für die ITP Nord (Potsdam) und Ratbacher (Stuttgart) als Techniker und Berater bei großen Kunden aus dem Bereich Banken und Finanzdienstleistung.
Kommentare

Hinterlasse einen Kommentar

Hinterlasse den ersten Kommentar!

avatar
4000
  Subscribe  
Benachrichtige mich zu: