Werde Teil unseres Teams und sorge für mehr Digitale Souveränität!
- Teamleiter IT – Kundenprojekte (m/w/d)
- IT Consultant (m/w/d)
- Senior Backend / Software Developer Python (m/w/d)
- u.v.m.

Erfahren Sie, wie Sie über Listener Module sämtliche Änderungen im UCS Verzeichnisdienst quer über alle angeschlossenen Services abgleichen und kontrollieren können.
Mit Sicherheit setzen auch Sie in Ihrem Unternehmen diverse (Cloud-)Services ein und diese Services nehmen bei Bedarf Änderungen in Ihrem Verzeichnisdienst wie Active Directory oder OpenLDAP vor. In heterogenen Umgebungen, in denen UCS typischerweise eingesetzt wird, stellt sich daher schnell die Frage, wie bekommt eigentlich Service A Änderungen mit, die Service B an Objekten im Verzeichnisdienst vorgenommen hat, die aber für beide Services relevant sind? Beispiel: Ein Drucker wird zum Netzwerk hinzugefügt und tritt der UCS Domäne bei, woraufhin dann die Druckerliste in der Konfigurationsdatei des Druckerservices (CUPS) aktualisiert und der Dienst neu gestartet wird.
Ich kann die obige Frage auch noch einfacher stellen, da UCS im Kern auf OpenLDAP basiert, das alle wichtigen Informationen verarbeitet und speichert, und zwar:
„Wie bekommt Service A überhaupt mit, dass sich etwas im OpenLDAP geändert hat?“
Ein sehr übliches Tool ist die direkte Abfrage (ldapsearch) im OpenLDAP, die mein Kollege Timo Denissen bereits in seinem Artikel How to Integrate with LDAP: „Generische LDAP-Anbindung“ beschrieb.
Der Vorteil ist, dass diese Art der Abfrage sehr weit verbreitet ist und damit auch schon von sehr vielen Open-Source-Bibliotheken in allen möglichen Programmiersprachen implementiert wurde. Für einfache Abfragen wie beispielsweise die Authentifizierung muss ein Service-Anbieter hier also fast nie etwas selbst entwickeln.
Der Nachteil ist jedoch, dass direkte Abfragen im OpenLDAP relativ starr in der Handhabung sind:
Genau diese Nachteile lösen Listener-Module. Sie dienen in einer UCS Domäne als mächtiges Werkzeug, um Änderungen und Events im LDAP sehr granular zu monitoren und bei Bedarf die Zustände von Objekten abzufragen.
Die Vorteile von Listener-Modulen liegen dabei auf der Hand:
Sie selbst können auch Listener-Module in einer UCS-Domäne schreiben, anmelden und nutzen. Es sind – teilweise auch sehr einfache – Python-Skripte, die eine UCS-API erfüllen. Diese wurden so konzipiert, dass möglichst einfach Informationen über Änderungen im Verzeichnisdienst an die Listener-Module gegeben werden können. Eine detaillierte Beschreibung hierzu finden Sie im Univention Wiki.
Das UCS System verwendet selbst vielfach Listener-Module, da es eine sehr mächtige Schnittstelle darstellt. Beispielsweise findet die komplette Replikation von Master zu Backups oder Slaves per Listener-Mechanismus statt.
Außerdem viele weitere Services wie beispielsweise Folgende:
Die Informationen selbst kommen aus dem LDAP. Ein UCS-spezifisches Overlay-Modul (TransLog) schreibt die (LDAP) Transaktionen im Verzeichnis heraus und übermittelt sie an den sogenannten Notifier, der auf dem UCS Master und den Backups läuft. Mit diesem Notifier baut der Listener eine Verbindung auf und wird somit benachrichtigt, wenn für ihn relevante Änderungen stattgefunden haben. Listener können sich dabei auch auf verschiedenen Systemen befinden. Hauptsache ist, dass es eine Verbindung zwischen Notifier und Listener gibt. Der Listener selbst wiederum gibt seine Informationen an die bei ihm angemeldeten Listener-Module weiter.
root@ucsma01:~# univention-directory-listener-ctrl modules
univention-directory-listener-ctrl resync modulname
root@ucsma01:~# univention-directory-listener-ctrl resync ucs-school-user-logonscript root@ucsma01:~# univention-directory-listener-ctrl resync univention-printer-assignment root@ucsma01:~# univention-directory-listener-ctrl resync opsilistener
„univention-directory-listener-ctrl resync ucs-school-user-logonscript“ generiert alle Logon-Skripte unter /var/lib/samba/netlogon/user/ neu.
„univention-directory-listener-ctrl resync univention-printer-assignment“ generiert alle VBS-Skripte unter /var/lib/samba/netlogon/printerassignment/ neu.
„univention-directory-listener-ctrl resync opsilistener“ resynchronisiert alle Rechner aus dem LDAP in die opsi-Datenbank.
Weitergehende Möglichkeiten finden Sie im Administrationshandbuch.
root@ucsma01:~# service univention-directory-listener restart
root@ucsma01:~# ucr set listener/debug/level=XY
Um das Ganze etwas zu veranschaulichen, möchte ich Ihnen hiermit ein Praxisbeispiel zeigen, in dem ich ein kleines Listener-Modul schreibe, das eine Web-API anspricht, um Lehrer, die neu im LDAP angelegt wurden, auch in einem Web-Service anzulegen. Für eine weitere Dokumentation eignet sich darüber hinaus das Entwicklerhandbuch. Ich nenne das Listener-Modul „Web-Connector“.
1. Grundsätzlich reicht es zunächst, eine Datei in das Verzeichnis /usr/lib/univention-directory-listener/system/ zu legen:
root@ucsma01:~# vim /usr/lib/univention-directory-listener/system/web_connector.py
2. Jedes Listener-Modul benötigt ein paar Definitionen.
name = "web_connector" description = "Der Web-Connector spricht eine Web-API an." filter = "(objectClass=ucsschoolTeacher)" attribute = ["ucsschoolSchool", "departmentNumber:"]
3. Außerdem muss mindestens eine Methode (handler) implementiert werden:
def handler(dn, new, old): pass
Das wäre nun schon ein „Hello World!“-Beispiel und funktioniert ohne Weiteres.
1. Mit dem folgenden Kommando (siehe auch oben „Hilfreiche Kommandos für Listener-Module“) würde man das Listener-Modul laden:
root@ucsma01:~# service univention-directory-listener restart
2. Mit dem folgenden Kommando kann man dies prüfen:
root@ucsma01:~# univention-directory-listener-ctrl modules [...] 0 web_connector /usr/lib/univention-directory-listener/system/web_connector.py [...]
Erscheint das Listener-Modul nicht in der Liste der Module, sollte man zunächst im listener.log unter /var/log/univention/listener.log schauen, was die Ursache sein könnte.
1. Im nächsten Schritt möchte man nun noch das Listener-Modul ein klein wenig erweitern. Dazu folgt ein vollständiges Beispiel:
__package__ = "" # workaround for PEP 366
import univention.debug as ud
import requests
name = "web_connector"
description = "Der Web-Connector spricht eine Web-API an."
filter = "(objectClass=ucsschoolTeacher)"
attribute = ["ucsschoolSchool", "departmentNumber:"]
def handler(dn, new, old):
ud.debug(ud.LISTENER, ud.ERROR, 'New teacher "%s"' % new)
ud.debug(ud.LISTENER, ud.ERROR, 'Old teacher "%s"' % old)
if new and not old:
r = requests.post("https://call.webservice.org", data={'name': new['uid'], 'type': 'teacher', 'action': 'create'})
else:
pass
Für weitergehende Beispiele können Sie auch gerne im Entwicklerhandbuch nachsehen.
Zusätzliche Links, die wir Ihnen empfehlen, sind:
1. Univention Directory Listener
2. Listener/Notifier-Domänenreplikation
Wir hoffen, Ihnen einen guten Überblick über die Funktion von Listener-Modulen gegeben zu haben und Tipps, wie Sie diese selbst bauen können. Bei weiteren Fragen helfen wir Ihnen gern über unser Forum weiter oder nutzen Sie einfach unsere Kommentarfunktion auf dieser Seite.
Michel arbeitet seit Januar 2014 bei Univention zunächst im Team des Professional Services als Projektmanager im Bildungsbereich. Hier war er in verschiedenen Projekten im Schulträger-Umfeld involviert. Aktuell verantwortet er als Produkt Manager Education den gesamten Bildungsbereich bei Univention und arbeitet daran, in Deutschland die digitale Bildung nachhaltig voranzubringen. Wenn er neben Familie und Arbeit mal Zeit findet, sind seine persönlichen Interessen Laufen, Fußball und Kochen.