Graphic Listen to me!

Listener modules support you in your administrative work by synchronizing and controlling all changes in the UCS’ OpenLDAP Einacross all connected services – Learn how to build and use them!

You are surely using a variety of (cloud) services in your organization and, if required, these services will make changes to your directory service, either Active Directory or OpenLDAP. In heterogeneous environments, where UCS is typically used, the question is, how can service A notice the changes that service B has made to certain objects in the directory, and that are relevant to both services? For example, when a new printer has been added to the network, and has joined the UCS domain, the list of printers is updated in the configuration file of the printer service (CUPS) and the service reloaded.

I can also ask the above question in a simpler way as UCS is based on OpenLDAP, which is processing and storing all important information:

“How can service A notice any changes in OpenLDAP?”

Direct queries to OpenLDAP

A very common tool is the direct query (ldapsearch) in OpenLDAP, already described by my colleague Timo Denissen in How to Integrate with LDAP: “Generic LDAP Connection.

The advantage here is that this kind of query is widely used and thus has been implemented by a great deal of open source libraries in all kinds of possible programming languages. For simple queries, such as authentication, a service provider here is almost never forced to program something.

The disadvantage, however, is that direct queries in OpenLDAP are relatively rigid to handle:

  1. To request changes in LDAP, you must program queries on your own.
  2. If you want to get to know the changes of many objects, you have to execute as many queries.
  3. The objects always exist only in the most current state. This means that you can not easily see whether only certain attributes might have changed.

Benefits of listener modules

Exactly these drawbacks are solved by listener modules. In a UCS domain, they are used as a powerful tool to monitor changes and events in the LDAP in all details and, if required, to query the state of objects.

The advantages of listener modules are evident:

  1. Changes from the LDAP are recorded in all details.
  2. The objects are available in the “old” and “new” status.
  3. It works asynchronously. This means, if a service is temporarily unavailable, changes are also applied later on.

Graphic about the interaction of UMC, OpenLDAP and listener modules

 

Overview of listener modules

Listener modules can be written, registered and used by anyone in a UCS domain. They are Python scripts – some of them very simple – that follow the UCS API. They are designed in such a way that the information about changes in the directory service will be communicated to the listener modules in an easy way. A detailed description can be found in our developer manual.

The UCS system itself often uses listener modules as it acts as a powerful interface. For example, the complete replication of the [OpenLDAP directory from UCS] master to backups or slaves takes place via listener/notifier mechanism.

In addition, many other services such as the following:

  1. The generation of Windows logon scripts for students and teachers in schools in UCS@school
  2. The assignment of printers to computer objects or groups in Windows domains
  3. The opsi client management to synchronize computers.

Rough Listener Sequence

The information itself comes from the LDAP. A UCS-specific overlay module (TransLog) logs the [LDAP] transactions in the directory and transmits them to the notifier service [running on the UCS master and Backup roles]. The listener establishes a connection with the notifier and is therefore informed if relevant changes have occurred. Listeners can also be located on different systems. The most important feature is a connection between notifier and listener. The listener itself, in turn, passes the information on to those listener modules registered with it.

Graphic about processes in the UMC with notifier and listener

 

Detailed Sequence

  1. Using an overlay module (TransLog), changes (transactions) are written to a file (/var/lib/univention-ldap/notify/transaction). Specified are a unique ID, the DN, and the type of operation (add, modify, delete).
  2. The notifier reads the transaction file.
  3. The notifier instructs the listeners and they query the current status of the object by referring to the ID, DN, and the type of operation.
  4. The listener has [in the local directory] the old object, and has now the new object.
  5. The listener then transfers the objects to the listener modules.
  6. The listener modules independently decide via the use of LDAP filters if they need/want to react to these LDAP changes, this includes the replication of the new object to the local directory.
  7. The listener finally saves the ID of the processed transaction.

Detailed listener module process in UCS

 

Helpful commands for listener modules

  • For an overview of installed listener modules, the following command can be used:
root@ucsma01:~# univention-directory-listener-ctrl modules
  • To completely re-synchronize existing listener modules, the following command can be used:
univention-directory-listener-ctrl resync modulname
  • For the above examples this would be:
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” regenerates all logon scripts at /var/lib/samba/netlogon/user/.

“univention-directory-listener-ctrl resync univention-printer-assignment” regenerates all VBS scripts at /var/lib/samba/netlogon/printerassignment/.

“univention-directory-listener-ctrl resync opsilistener” resynchronizes all computers from the LDAP to the opsi database.

Further possibilities can be found in the administrator manual.

  • Restart the listener including the loading of all modules with:
root@ucsma01:~# service univention-directory-listener restart
  • The logs are written to the listener.log at /var/log/univention/listener.log.
  • With the following command you can change the log level {0,1,2,3,4}:
root@ucsma01:~# ucr set listener/debug/level=XY

How do I build a listener module?

To demonstrate the whole process better, I would like to give you a practical example by writing a small listener module that queries a Web API in order to create teachers in a web service that previously had been created in the LDAP. A valuable source of further information here is the developer manual. I call the listener module “Web-Connector”.

1. Generally it is sufficient to start by putting a file into /usr/lib/univention-directory-listener/system/:

root@ucsma01:~# vim /usr/lib/univention-directory-listener/system/web_connector.py

2. Each listener module requires a few definitions.

name = "web_connector"
description = "the Web-Connector refers to a Web-API."
filter = "(objectClass=ucsschoolTeacher)"
attribute = ["ucsschoolSchool", "departmentNumber:"]
  • “name” is probably self-explanatory
  • “description” probably, too
  • “filter” is the LDAP filter, which selects the objects to be processed. Here we recommend to use the univention-ldapsearch. In this case, all teachers (objectClass=ucsschoolTeacher) are processed.

3. In addition, at least one method (handler) must be implemented:

def handler(dn, new, old): pass

This already would be a “Hello World!” example and will work without problems.

1. With the following command (see also above “Helpful commands for listener modules”) you can load the listener module:

root@ucsma01:~# service univention-directory-listener restart

2. You can check this with the following command:

root@ucsma01:~# univention-directory-listener-ctrl modules
[...]
0       web_connector   /usr/lib/univention-directory-listener/system/web_connector.py
[...]

If the listener module does not appear in the list of the modules, you should first look in the listener.log at /var/log/univention/listener.log, to find out what could be the cause.

1. In the next step I want to extend the listener module a little bit as shown in the following complete example:


__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
  • Row 1 __package__ = “” # workaround for PEP 366 is for relative imports.
  • Row 2 import univention.debug as ud imports Univention’s own modules for debugging / logging. Here, of course, you could also directly use Python’s own logging tools.
  • Row 3 import requests imports the request library.
  • The definitions in the rows 4 to 7 have been described above.
  • Row 8 attribute = [“ucsschoolSchool”, “departmentNumber:”] defines on top a Python list of the object’s attributes in which the listener module is activated if something changes.
  • Row 10 def handler(dn, new, old): defines the handler function.
  • Row 11 ud.debug(ud.LISTENER, ud.ERROR, ‘New teacher “%s”‘ % new) logs the new object in LDAP. In this case, the log level is set to ud.ERROR, in order to definitely see something in the listener.log.
  • Row 12 ud.debug(ud.LISTENER, ud.ERROR, ‘Old teacher “%s”‘ % old) logs the old object in the LDAP.
  • Row 13 if new and not old: defines an IF-statement which is activated only if an object has been created in LDAP.
  • Row 14 r = requests.post(“https://call.webservice.org”, data={‘name’: new[‘uid’], ‘type’: ‘teacher’, ‘action’: ‘create’}) defines an example of a web API.
  • Rows 15 & 16 close the example.

For further examples, you may also look in the developer manual.

Additional links we recommend:
1. Univention Directory Listener
2. Listener/notifier domain replication

We hope that we have given you a good overview about the function of listener modules and tips on how to build them by yourself. If you have any further questions, please do not hesitate to contact us via our forum or

Comment below

Use UCS Core Edition for Free!

Download now
Michel Smidt

Michel joined Univention in January 2014, initially working in the Professional Services team as an education project manager. Here he was involved in various projects in the school administration environment. Currently, as Product Manager Education, he is responsible for the entire education sector at Univention and is working on sustainably advancing digital education in Germany. When he finds time next to family and work, his personal interests are running, football and cooking.

What's your opinion? Leave a comment!

Your email address will not be published. Required fields are marked *