6.1. Structure of Listener Modules#
Listener modules can be implemented using the High-level Listener modules API or the Low-level Listener module.
New in version 4.2: New implementations should be based on the newer high-level API, which is available since UCS 4.2 erratum 311.
Each listener module must declare several string constants. They are required by the Univention Directory Listener to handle each module.
- your_module.name: str#
(optional)
This name is used to uniquely identify the module. It defaults to the filename containing this listener module without the
.py
suffix. The name is used to keep track of the module state in/var/lib/univention-directory-listener/handlers/
.
- your_module.description: str#
(required)
A short description. It is currently unused and displayed nowhere.
- your_module.get_description()#
- Return type:
For description, see
description
.
- your_module.filter: str#
(required)
Defines a LDAP filter which is used to match the objects the listener is interested in. This filter is similar to the LDAP search filter as defined in RFC 2254, but more restricted:
it is case sensitive
it only supports equal matches
- your_module.attributes: List[str]#
(optional)
A Python list of LDAP attribute names which further narrows down the condition under which the listener module gets called. By default the module is called on all attribute changes of objects matching the filter. If the list is specified, the module is only invoked when at least one of the listed attributes is changed.
- your_module.get_attributes()#
- Return type:
List[str]
For description, see
attributes
.
- your_module.modrdn: str#
(low-level API, optional)
Setting this variable to the string
1
changes the signature of the functionhandler()
. It receives an additional forth argument, which specifies the LDAP operation triggering the change.
- your_module.handle_every_delete: bool#
(low-level API, optional)
The Listener uses its cache to keep track of objects, especially their previous values and which modules handles which objects. The Univention Configuration Registry Variable
listener/cache/filter
can be used to prevent certain objects from being stored in the cache. But then the Listener no longer knows which module must be called when such an object is deleted. Setting this variable toTrue
will make the Listener call the functionhandler()
of this module whenever any object is deleted. The function then must use other means to determine itself if the deleted object is of the appropriate type asold
will be emptydict
.
- your_module.priority: float#
(optional)
This variable can be used to explicitly overwrite the default order in which the modules are executed. By default modules are executed in random order.
replication.py
defaults to0.0
as it must be executed first, all other modules default to50.0
.
6.1.1. Handle LDAP objects#
For handling changes to matching LDAP objects a handler must be implemented. This function is called for different events:
when the object is first created.
when attributes of an existing object are changed.
when the object is moved to a different location within the LDAP tree.
when the object is finally removed.
when a LDAP schema change happens.
The low-level API requires writing a single function handler()
to
handle all those cases. The high-level API already splits this into separate
methods create()
, modify()
and remove()
, which are
easier to overwrite.
6.1.2. Initialize and clean#
Each module gets initialized once by calling its function initialize()
. This
state of each module is tracked in a file below
/var/lib/univention-directory-listener/handlers/
.
- your_module.initialize()#
- Return type:
None
(optional)
The function
initialize()
is called once when the Univention Directory Listener loads the module for the first time. This is recorded persistently in the file/var/lib/univention-directory-listener/name
, wherename
equals the value from the header.If for whatever reason the listener module should be reset and re-run for all matching objects, the state can be reset by running the following command:
$ univention-directory-listener-ctrl resync $name
In that case the function
initialize()
will be called again.
- your_module.clean()#
- Return type:
None
(optional)
The function
clean()
is only called when the Univention Directory Listener is initialized for the first time or is forced to re-initialize from scratch using the option-g
,-i
, or-P
. The function should purge all previously generated files and return the module into a clean state.Afterwards the module will be re-initialized by calling the function
initialize()
.
6.1.3. Suspend and resume#
For efficiency reasons the API provides two functions, which resumes and
suspends modules when no transactions are processed for 15 seconds. All modules
start in the state suspended
. Before a suspended
modules is called to
handle a change, the function prerun()
is called for that module. If no
transactions happen within a time span of 15 seconds the Listener suspends all
active modules by calling the function postrun()
. This mechanism is
most often used to batch changes by collecting multiple changes and applying
them only on suspend.
- your_module.prerun()#
- Return type:
None
(optional);
For optimization the Univention Directory Listener does not keep open an LDAP connection all time. Instead the connection is opened once at the beginning of a change and closed only if no new change arrives within 15 seconds. The opening is signaled by the invocation of the function
prerun()
and the closing bypostrun()
.The function
postrun()
is most often used to restart services, as restarting a service takes some time and makes the service unavailable during that time. It’s best practice to use thehandler()
only to process the stream of changes, set UCR variables or generate new configuration files. Restarting associated services should be delayed to thepostrun()
function.
- your_module.postrun()#
- Rytpe:
None
For description, see
prerun()
.Warning
The function
postrun()
is only called, when no change happens for 15 seconds. This is not on a per-module basis, but globally. In an ever changing system, where the stream of changes never pauses for 15 seconds, the functions may never be called!