|
10 |
<indexterm><primary>Univention Directory Listener</primary><see>Directory Listener</see></indexterm> |
10 |
<indexterm><primary>Univention Directory Listener</primary><see>Directory Listener</see></indexterm> |
11 |
</title> |
11 |
</title> |
12 |
|
12 |
|
13 |
<remark>PMH: Bug #29420</remark> |
|
|
14 |
|
15 |
<para> |
13 |
<para> |
16 |
Replication of the directory data within a UCS domain occurs via the Univention |
14 |
Replication of the directory data within a UCS domain is provided by the Univention |
17 |
Directory Listener/Notifier mechanism: |
15 |
Directory Listener/Notifier mechanism: |
18 |
|
16 |
|
19 |
<itemizedlist> |
17 |
<itemizedlist> |
|
24 |
<listitem><simpara> |
22 |
<listitem><simpara> |
25 |
On the &ucsMaster; (and possibly existing &ucsBackup; systems) the <emphasis>&ucsUDN;</emphasis> service monitors |
23 |
On the &ucsMaster; (and possibly existing &ucsBackup; systems) the <emphasis>&ucsUDN;</emphasis> service monitors |
26 |
changes in the LDAP directory and makes the selected changes available to the &ucsUDL; |
24 |
changes in the LDAP directory and makes the selected changes available to the &ucsUDL; |
27 |
services on the other UCS systems. |
25 |
services on all UCS systems joined into the domain. |
28 |
</simpara></listitem> |
26 |
</simpara></listitem> |
29 |
</itemizedlist> |
27 |
</itemizedlist> |
30 |
</para> |
28 |
</para> |
|
33 |
The active &ucsUDL; instances in the domain connect to a &ucsUDN; |
31 |
The active &ucsUDL; instances in the domain connect to a &ucsUDN; |
34 |
service. If an LDAP change is performed on the &ucsMaster; (all other LDAP |
32 |
service. If an LDAP change is performed on the &ucsMaster; (all other LDAP |
35 |
servers in the domain are read-only), this is registered by the &ucsUDN; |
33 |
servers in the domain are read-only), this is registered by the &ucsUDN; |
36 |
and notified to the listener instances. |
34 |
and reported to the listener instances. |
37 |
</para> |
35 |
</para> |
38 |
|
36 |
|
39 |
<para> |
37 |
<para> |
40 |
Each &ucsUDL; instance uses a range of &ucsUDL; |
38 |
Each &ucsUDL; instance hosts a range of &ucsUDL; |
41 |
modules. These modules are shipped by the installed applications; the print server package |
39 |
modules. These modules are shipped by the installed applications; the print server package |
42 |
includes, for example, listener modules which generate the CUPS configuration. |
40 |
includes, for example, listener modules which generate the CUPS configuration. |
43 |
</para> |
41 |
</para> |
|
48 |
read from the LDAP, but instead from the file <filename>/etc/cups/printers.conf</filename>. |
46 |
read from the LDAP, but instead from the file <filename>/etc/cups/printers.conf</filename>. |
49 |
Now, if a printer is saved in the printer management of the &ucsUMC;, it is stored |
47 |
Now, if a printer is saved in the printer management of the &ucsUMC;, it is stored |
50 |
in the LDAP directory. This change is detected by the &ucsUDL; module |
48 |
in the LDAP directory. This change is detected by the &ucsUDL; module |
51 |
<emphasis>cups-printers</emphasis> and an entry added to, modified or deleted in |
49 |
<emphasis>cups-printers</emphasis> and an entry gets added to, modified in or deleted from |
52 |
<filename>/etc/cups/printers.conf</filename> based on the data in the LDAP. |
50 |
<filename>/etc/cups/printers.conf</filename> based on the modification in the LDAP directory. |
53 |
</para> |
51 |
</para> |
54 |
|
52 |
|
55 |
<section id="listener:handler"> |
53 |
<section id="listener:handler"> |
56 |
<title>Structure of Listener modules</title> |
54 |
<title>Structure of Listener Modules</title> |
57 |
|
55 |
|
58 |
<para> |
56 |
<para> |
59 |
Each listener module must declare several string constants. |
57 |
Each listener module must declare several string constants. |
60 |
They are required by the &ucsUDL; to handle and process each module. |
58 |
They are required by the &ucsUDL; to handle each module. |
61 |
They should be defined in the header at the beginning of the module. |
59 |
They should be defined at the beginning of the module. |
62 |
</para> |
60 |
</para> |
63 |
<programlisting language="python"><![CDATA[ |
61 |
<programlisting language="python"><![CDATA[ |
64 |
name = "module_name" |
62 |
name = "module_name" |
|
96 |
</para> |
94 |
</para> |
97 |
<itemizedlist> |
95 |
<itemizedlist> |
98 |
<listitem><simpara>it is case sensitive</simpara></listitem> |
96 |
<listitem><simpara>it is case sensitive</simpara></listitem> |
99 |
<listitem><simpara>it only support equal matches</simpara></listitem> |
97 |
<listitem><simpara>it only supports equal matches</simpara></listitem> |
100 |
</itemizedlist> |
98 |
</itemizedlist> |
101 |
<note> |
99 |
<note> |
102 |
<para> |
100 |
<para> |
103 |
The name <literal>filter</literal> was historically poorly chosen, since it overwrite the built-in Python function <function>filter()</function>. |
101 |
The name <literal>filter</literal> has the drawback that it shadows the Python built-in function <function>filter()</function>, but its use has historical reasons. |
104 |
If that function is required for implementing the listener module, a alias-reference must be defined before overwriting the reference or <programlisting language="python">sys.modules["__builtin__"].filter</programlisting> can be used to reference the function. |
102 |
If that function should be required for implementing the listener module, an alias-reference may be defined before overwriting the name or it may be explicitly accessed via the Python <literal>__builtin__</literal> module. |
105 |
</para> |
103 |
</para> |
106 |
</note> |
104 |
</note> |
107 |
</listitem> |
105 |
</listitem> |
|
110 |
<term><varname>attributes</varname></term> |
108 |
<term><varname>attributes</varname></term> |
111 |
<listitem> |
109 |
<listitem> |
112 |
<para> |
110 |
<para> |
113 |
A Python list of attribute names as string, which further filters the condition, when the Listener module should be called. |
111 |
A Python list of LDAP-attribute names which further narrows down the condition under which the listener module gets called. |
114 |
By default the empty list invokes the module on all changes. |
112 |
By default the module is called on all attribute changes of objects matching the filter. |
115 |
Otherwise the module is only invoked, when at least one attribute mentioned in the list is changed. |
113 |
If the list is specified, the module is only invoked when at least one of the listed attributes is changed. |
116 |
</para> |
114 |
</para> |
117 |
</listitem> |
115 |
</listitem> |
118 |
</varlistentry> |
116 |
</varlistentry> |
|
128 |
</variablelist> |
126 |
</variablelist> |
129 |
|
127 |
|
130 |
<para> |
128 |
<para> |
131 |
In addition to the static string a module must implement several functions. |
129 |
In addition to the static strings a module must implement several functions. |
132 |
They are called in different situations of the live-cycle of the module. |
130 |
They are called in different situations of the live-cycle of the module. |
133 |
</para> |
131 |
</para> |
134 |
<programlisting language="python"><![CDATA[ |
132 |
<programlisting language="python"><![CDATA[ |
|
144 |
<term><function>handler(dn, old, new, command='')</function></term> |
142 |
<term><function>handler(dn, old, new, command='')</function></term> |
145 |
<listitem> |
143 |
<listitem> |
146 |
<para> |
144 |
<para> |
147 |
This function is called for each change matching the <varname>filter</varname> and <varname>attributes</varname> expressions as declared in the header above. |
145 |
This function is called for each change matching the <varname>filter</varname> and <varname>attributes</varname> as declared in the header of the module. |
148 |
The distinguished name (<abbrev>dn</abbrev>) of the object is supplied as the first argument <varname>dn</varname>. |
146 |
The distinguished name (<abbrev>dn</abbrev>) of the object is supplied as the first argument <varname>dn</varname>. |
149 |
</para> |
147 |
</para> |
150 |
<para> |
148 |
<para> |
151 |
Depending on the type of modification, <varname>old</varname> and <varname>new</varname> are either <literal>None</literal> or reference a dictionary of arrays, representing the multi-valued attributes of the object. |
149 |
Depending on the type of modification, <varname>old</varname> and <varname>new</varname> may each independently either be <literal>None</literal> or reference a Python dictionary of arrays. Each array represents one of the multi-valued attributes of the object. |
152 |
The &ucsUDL; uses a local cache to cache the latest values of each object. |
150 |
The &ucsUDL; uses a local cache to cache the values of each object as it was seen most recently. |
153 |
This cache is used to supply the values for <varname>old</varname>, while the values in <varname>new</varname> are those retrieved from the LDAP directory service. |
151 |
This cache is used to supply the values for <varname>old</varname>, while the values in <varname>new</varname> are those retrieved from that LDAP directory service which is running on the same server as the &ucsUDN; (&ucsMaster; or &ucsBackup; servers in the domain). |
154 |
</para> |
152 |
</para> |
155 |
<para> |
153 |
<para> |
156 |
If and only if the global <varname>modrdn</varname> setting is enabled, <varname>command</varname> is passed as a fourth argument. |
154 |
If and only if the global <varname>modrdn</varname> setting is enabled, <varname>command</varname> is passed as a fourth argument. |
157 |
It contains a single letter, which indicates the type of modification. |
155 |
It contains a single letter, which indicates the type of modification. |
158 |
This can be used to distinguish an <literal>modrdn</literal> operation from a delete operation followed by a create operation. |
156 |
This can be used to distinguish an <firstterm>modrdn</firstterm> operation from a delete operation followed by a create operation. |
159 |
</para> |
157 |
</para> |
160 |
<variablelist> |
158 |
<variablelist> |
161 |
<varlistentry> |
159 |
<varlistentry> |
162 |
<term>modify (<literal>m</literal>)</term> |
160 |
<term><literal>m</literal> (modify)</term> |
163 |
<listitem> |
161 |
<listitem> |
164 |
<para> |
162 |
<para> |
165 |
Signals a modify operation, where an existing object is changed. |
163 |
Signals a modify operation, where an existing object is changed. |
|
168 |
</listitem> |
166 |
</listitem> |
169 |
</varlistentry> |
167 |
</varlistentry> |
170 |
<varlistentry> |
168 |
<varlistentry> |
171 |
<term>add (<literal>a</literal>)</term> |
169 |
<term><literal>a</literal> (add)</term> |
172 |
<listitem> |
170 |
<listitem> |
173 |
<para> |
171 |
<para> |
174 |
Signals the addition of a new object. |
172 |
Signals the addition of a new object. |
|
177 |
</listitem> |
175 |
</listitem> |
178 |
</varlistentry> |
176 |
</varlistentry> |
179 |
<varlistentry> |
177 |
<varlistentry> |
180 |
<term>delete (<literal>d</literal>)</term> |
178 |
<term><literal>d</literal> (delete)</term> |
181 |
<listitem> |
179 |
<listitem> |
182 |
<para> |
180 |
<para> |
183 |
Signals the removal of a previously existing object. |
181 |
Signals the removal of a previously existing object. |
|
186 |
</listitem> |
184 |
</listitem> |
187 |
</varlistentry> |
185 |
</varlistentry> |
188 |
<varlistentry> |
186 |
<varlistentry> |
189 |
<term>modify relative distinguished name (<firstterm>modrdn</firstterm>, <literal>r</literal>)</term> |
187 |
<term><literal>r</literal> (rename: modification of distinguished name via <literal>modrdn</literal>)</term> |
190 |
<listitem> |
188 |
<listitem> |
191 |
<para> |
189 |
<para> |
192 |
Signals a change in the distinguished name, which might be caused by renaming a object or moving the object from one container into one other. |
190 |
Signals a change in the distinguished name, which might be caused by renaming a object or moving the object from one container into another. |
193 |
The module is called with this command instead of the <emphasis>delete</emphasis> command, so that the module can optimize that case and skip the deletion of the object. |
191 |
The module is called with this command instead of the <emphasis>delete</emphasis> command, so that modules can recognize this special case and skip the deletion of the object. |
194 |
The module will be called again with the <emphasis>add</emphasis> command just after the <emphasis>modrdn</emphasis> command, where it should perform the rename or move operation. |
192 |
The module will be called again with the <emphasis>add</emphasis> command just after the <emphasis>modrdn</emphasis> command, where it should process the rename or move operation. |
195 |
The module is responsible for keeping track of the rename-case by internally storing the previous distinguished name. |
193 |
Each module is responsible for keeping track of the rename-case by internally storing the previous distinguished name during the <emphasis>modrdn</emphasis> phase of this two phased operation. |
196 |
</para> |
194 |
</para> |
197 |
</listitem> |
195 |
</listitem> |
198 |
</varlistentry> |
196 |
</varlistentry> |
199 |
<varlistentry> |
197 |
<varlistentry> |
200 |
<term><literal>z</literal></term> |
198 |
<term><literal>n</literal> (new or schema change)</term> |
201 |
<listitem> |
199 |
<listitem> |
202 |
<para> |
|
|
203 |
This should be ignored. |
204 |
<remark>PMH: Unknown</remark> |
205 |
</para> |
206 |
</listitem> |
207 |
</varlistentry> |
208 |
<varlistentry> |
209 |
<term>new or schema change (<literal>n</literal>)</term> |
210 |
<listitem> |
211 |
<para>This command can signal two changes:</para> |
200 |
<para>This command can signal two changes:</para> |
212 |
<itemizedlist> |
201 |
<itemizedlist> |
213 |
<listitem> |
202 |
<listitem> |
|
214 |
<simpara>If <varname>dn</varname> is <literal>cn=Subschema</literal>, it signals that a schema change occurred.</simpara> |
203 |
<simpara>If <varname>dn</varname> is <literal>cn=Subschema</literal>, it signals that a schema change occurred.</simpara> |
215 |
</listitem> |
204 |
</listitem> |
216 |
<listitem> |
205 |
<listitem> |
217 |
<simpara>All other cases signal the initialization of a new object, which should be handles just like a normal <function>add</function> operation.</simpara> |
206 |
<simpara>All other cases signal the initialization of a new object, which should be handled just like a normal <function>add</function> operation.</simpara> |
218 |
</listitem> |
207 |
</listitem> |
219 |
</itemizedlist> |
208 |
</itemizedlist> |
220 |
</listitem> |
209 |
</listitem> |
|
231 |
This is recorded persistently in the file <filename>/var/lib/univention-directory-listener/<replaceable>name</replaceable></filename>, where <varname>name</varname> equals the value from the header. |
220 |
This is recorded persistently in the file <filename>/var/lib/univention-directory-listener/<replaceable>name</replaceable></filename>, where <varname>name</varname> equals the value from the header. |
232 |
</para> |
221 |
</para> |
233 |
<para> |
222 |
<para> |
234 |
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 command <command>univention-directory-listener-ctrl resync <replaceable>name</replaceable></command>. |
223 |
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 command <command>univention-directory-listener-ctrl resync <replaceable>name</replaceable></command>. |
235 |
In that case the function <function>initialize()</function> will be called again. |
224 |
In that case the function <function>initialize()</function> will be called again. |
236 |
</para> |
225 |
</para> |
237 |
<para> |
226 |
<para> |
|
250 |
The opening is signaled by the invocation of the function <function>prerun()</function> and the closing by <function>postrun()</function>. |
239 |
The opening is signaled by the invocation of the function <function>prerun()</function> and the closing by <function>postrun()</function>. |
251 |
</para> |
240 |
</para> |
252 |
<para> |
241 |
<para> |
253 |
The function <function>postrun()</function> is most often used to restart services, as restarting a service takes some time and makes the service unavailable during that time: |
242 |
The function <function>postrun()</function> is most often used to restart services, as restarting a service takes some time and makes the service unavailable during that time. |
254 |
The stream of changes is only used to generate new configuration files, which are only activated by restarting the service in the <function>postrun()</function> handler. |
243 |
It's best practice to use the <function>handler()</function> only to process the stream of changes, set UCR variables or generate new configuration files and delay a restart of associated services to the <function>postrun()</function> function. |
255 |
</para> |
244 |
</para> |
256 |
<warning> |
245 |
<warning> |
257 |
<para> |
246 |
<para> |
258 |
The function <function>postrun()</function> is only called, when no change happens for 15 seconds. |
247 |
The function <function>postrun()</function> is only called, when no change happens for 15 seconds. |
259 |
This is not on a per-module basis, but globally. |
248 |
This is not on a per-module basis, but globally. |
260 |
In an ever changing system, where the stream of changes never pauses for 15 seconds, the functions would be called never! |
249 |
In an ever changing system, where the stream of changes never pauses for 15 seconds, the functions may never be called! |
261 |
</para> |
250 |
</para> |
262 |
</warning> |
251 |
</warning> |
263 |
</listitem> |
252 |
</listitem> |
|
266 |
<term><function>setdata(key, value)</function></term> |
255 |
<term><function>setdata(key, value)</function></term> |
267 |
<listitem> |
256 |
<listitem> |
268 |
<para> |
257 |
<para> |
269 |
This function is called several times by the main &ucsUDL; to pass configuration data into the modules. |
258 |
This function is called several times by the &ucsUDL; main process to pass configuration data into the modules. |
270 |
The following <varname>key</varname>s are supplied: |
259 |
The following <varname>key</varname>s are supplied: |
271 |
</para> |
260 |
</para> |
272 |
<variablelist> |
261 |
<variablelist> |
273 |
<varlistentry> |
262 |
<varlistentry> |
274 |
<term><literal>ldapserver</literal></term> |
263 |
<term><literal>ldapserver</literal></term> |
275 |
<listitem><simpara>The host-name of the <abbrev>LDAP</abbrev> server the &ucsUDL; is using.</simpara></listitem> |
264 |
<listitem><simpara>The hostname of the <abbrev>LDAP</abbrev> server the &ucsUDL; is currently reading from.</simpara></listitem> |
276 |
</varlistentry> |
265 |
</varlistentry> |
277 |
<varlistentry> |
266 |
<varlistentry> |
278 |
<term><literal>binddn</literal></term> |
267 |
<term><literal>binddn</literal></term> |
279 |
<listitem><simpara>The bind distinguished name the &ucsUDL; is using to authenticate with the <abbrev>LDAP</abbrev>.</simpara></listitem> |
268 |
<listitem><simpara>The distinguished name the &ucsUDL; is using to authenticate to the <abbrev>LDAP</abbrev> server (via <literal>simple bind</literal>).</simpara></listitem> |
280 |
</varlistentry> |
269 |
</varlistentry> |
281 |
<varlistentry> |
270 |
<varlistentry> |
282 |
<term><literal>bindpw</literal></term> |
271 |
<term><literal>bindpw</literal></term> |
283 |
<listitem><simpara>The simple bind password the &ucsUDL; is using to authenticate with the <abbrev>LDAP</abbrev>.</simpara></listitem> |
272 |
<listitem><simpara>The password the &ucsUDL; is using to authenticate to the <abbrev>LDAP</abbrev> server.</simpara></listitem> |
284 |
</varlistentry> |
273 |
</varlistentry> |
285 |
<varlistentry> |
274 |
<varlistentry> |
286 |
<term><literal>basedn</literal></term> |
275 |
<term><literal>basedn</literal></term> |
|
293 |
</section> |
282 |
</section> |
294 |
|
283 |
|
295 |
<section id="listener:example"> |
284 |
<section id="listener:example"> |
296 |
<title>Listener tasks and examples |
285 |
<title>Listener Tasks and Examples |
297 |
<indexterm><primary>Directory Listener</primary><secondary>Example module</secondary></indexterm> |
286 |
<indexterm><primary>Directory Listener</primary><secondary>Example module</secondary></indexterm> |
298 |
</title> |
287 |
</title> |
299 |
<para> |
288 |
<para> |
|
302 |
</para> |
291 |
</para> |
303 |
|
292 |
|
304 |
<section id="listener:example:simple"> |
293 |
<section id="listener:example:simple"> |
305 |
<title>Basic example</title> |
294 |
<title>Basic Example</title> |
306 |
<para> |
295 |
<para> |
307 |
The following boiler-plate delegates each change type to a separate function. |
296 |
The following boilerplate code delegates each change type to a separate function. |
308 |
It does not handle renames and moves explicitly, but only through the removal of the object at the old <abbrev>dn</abbrev> and the following addition at the new <abbrev>dn</abbrev>. |
297 |
It does not handle renames and moves explicitly, but only as the removal of the object at the old <abbrev>dn</abbrev> and the following addition at the new <abbrev>dn</abbrev>. |
309 |
</para> |
298 |
</para> |
310 |
<para> |
299 |
<para> |
311 |
Source code: <ulink url="&websvn;doc/developer-reference/listener/simple.py"/> |
300 |
Source code: <ulink url="&websvn;doc/developer-reference/listener/simple.py"/> |
|
314 |
</section> |
303 |
</section> |
315 |
|
304 |
|
316 |
<section id="listener:example:modrdn"> |
305 |
<section id="listener:example:modrdn"> |
317 |
<title>Rename and move |
306 |
<title>Rename and Move |
318 |
<indexterm><primary>Directory Listener</primary><secondary>modrdn</secondary></indexterm> |
307 |
<indexterm><primary>Directory Listener</primary><secondary>modrdn</secondary></indexterm> |
319 |
</title> |
308 |
</title> |
320 |
<para> |
309 |
<para> |
321 |
In case rename and move actions should be handled separately, use the following code: |
310 |
In case rename and move actions should be handled separately, the following code may be used: |
322 |
</para> |
311 |
</para> |
323 |
<para> |
312 |
<para> |
324 |
Source code: <ulink url="&websvn;doc/developer-reference/listener/modrdn.py"/> |
313 |
Source code: <ulink url="&websvn;doc/developer-reference/listener/modrdn.py"/> |
|
326 |
<programlisting language="python"><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="modrdn.py" parse="text"/></programlisting> |
315 |
<programlisting language="python"><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="modrdn.py" parse="text"/></programlisting> |
327 |
<warning> |
316 |
<warning> |
328 |
<para> |
317 |
<para> |
329 |
Please be aware that tracking the two subsequent calls for <literal>modrdn</literal> in memory might cause duplicates, if the &ucsUDL; is terminated while such an operation is performed. |
318 |
Please be aware that tracking the two subsequent calls for <literal>modrdn</literal> in memory might cause duplicates, in case the &ucsUDL; is terminated while such an operation is performed. |
330 |
If this is problematic, saving the state on a persistent disk mist be implemented. |
319 |
If this is critical, the state should be stored persistently into a temporary file. |
331 |
</para> |
320 |
</para> |
332 |
</warning> |
321 |
</warning> |
333 |
</section> |
322 |
</section> |
334 |
|
323 |
|
335 |
<section id="listener:example:user"> |
324 |
<section id="listener:example:user"> |
336 |
<title>Full example with packaging</title> |
325 |
<title>Full Example with Packaging</title> |
337 |
<para> |
326 |
<para> |
338 |
The following example shows a listener module, which logs all changes to users into the file <filename>/tmp/UserList.txt</filename>. |
327 |
The following example shows a listener module, which logs all changes to users into the file <filename>/tmp/UserList.txt</filename>. |
339 |
</para> |
328 |
</para> |
|
342 |
</para> |
331 |
</para> |
343 |
<programlisting language="python"><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="printusers/printusers.py" parse="text"/></programlisting> |
332 |
<programlisting language="python"><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="printusers/printusers.py" parse="text"/></programlisting> |
344 |
<para> |
333 |
<para> |
345 |
Some comments: |
334 |
Some comments on the code: |
346 |
</para> |
335 |
</para> |
347 |
<itemizedlist> |
336 |
<itemizedlist> |
348 |
<listitem> |
337 |
<listitem> |
349 |
<simpara> |
338 |
<simpara> |
350 |
Overwriting <varname>__package__</varname> is currently necessary, as the &ucsUDL; imports the Listener module by its own mechanism, which is incompatible with the mechanism normally used by Python itself. |
339 |
Overwriting <varname>__package__</varname> is currently necessary, as the &ucsUDL; imports the listener module by its own mechanism, which is incompatible with the mechanism normally used by Python itself. |
351 |
Be aware, that this might cause problems when use <package>pickle</package>. |
340 |
Be aware, that this might cause problems when using <package>pickle</package>. |
|
|
341 |
<remark>AREQ: And what's the recommendation?</remark> |
352 |
</simpara> |
342 |
</simpara> |
353 |
</listitem> |
343 |
</listitem> |
354 |
<listitem> |
344 |
<listitem> |
355 |
<simpara> |
345 |
<simpara> |
356 |
The <abbrev>LDAP</abbrev> filter is cleverly chosen to only match user objects, but not computer objects, which end on <literal>$</literal>. |
346 |
The <abbrev>LDAP</abbrev> filter is specifically chosen to only match user objects, but not computer objects, which have a uid characteristically terminated by a <literal>$</literal>-sign. |
357 |
</simpara> |
347 |
</simpara> |
358 |
</listitem> |
348 |
</listitem> |
359 |
<listitem> |
349 |
<listitem> |
|
364 |
<listitem> |
354 |
<listitem> |
365 |
<simpara> |
355 |
<simpara> |
366 |
Writing a file as <emphasis>root</emphasis> in a public location like <filename class="directory">/tmp/</filename> should be avoided. |
356 |
Writing a file as <emphasis>root</emphasis> in a public location like <filename class="directory">/tmp/</filename> should be avoided. |
|
|
357 |
<remark>AREQ: Why? What's the point here? Relevant?</remark> |
367 |
It is only done here to show how it works. |
358 |
It is only done here to show how it works. |
368 |
</simpara> |
359 |
</simpara> |
369 |
</listitem> |
360 |
</listitem> |
370 |
<listitem> |
361 |
<listitem> |
371 |
<simpara> |
362 |
<simpara> |
372 |
For testing run a command like <command>tail -f /tmp/UserList.txt &</command>. |
363 |
To test this run a command like <command>tail -f /tmp/UserList.txt &</command>. |
373 |
Then create a new user or modify the <emphasis>lastname</emphasis> of an existing user to trigger the module. |
364 |
Then create a new user or modify the <emphasis>lastname</emphasis> of an existing one to trigger the module. |
374 |
</simpara> |
365 |
</simpara> |
375 |
</listitem> |
366 |
</listitem> |
376 |
</itemizedlist> |
367 |
</itemizedlist> |
|
402 |
</section> |
393 |
</section> |
403 |
|
394 |
|
404 |
<section id="listener:example:setdata"> |
395 |
<section id="listener:example:setdata"> |
405 |
<title>A little bit more object oriented</title> |
396 |
<title>A Little Bit more Object Oriented</title> |
406 |
<para> |
397 |
<para> |
407 |
For larger modules it is recommended to use a more object-oriented design like the following example, which logs referential integrity violations into a file. |
398 |
For larger modules it might be preferrable to use a more object oriented design like the following example, which logs referential integrity violations into a file. |
408 |
</para> |
399 |
</para> |
409 |
<para> |
400 |
<para> |
410 |
Source code: <ulink url="&websvn;doc/developer-reference/listener/obj.py"/> |
401 |
Source code: <ulink url="&websvn;doc/developer-reference/listener/obj.py"/> |
|
414 |
</section> |
405 |
</section> |
415 |
|
406 |
|
416 |
<section id="listener:details"> |
407 |
<section id="listener:details"> |
417 |
<title>Technical details |
408 |
<title>Technical Details |
418 |
<indexterm><primary>Directory Listener</primary><secondary>Debug</secondary></indexterm> |
409 |
<indexterm><primary>Directory Listener</primary><secondary>Debug</secondary></indexterm> |
419 |
</title> |
410 |
</title> |
420 |
|
411 |
|
|
429 |
--> |
420 |
--> |
430 |
|
421 |
|
431 |
<section id="listener:details:credentials"> |
422 |
<section id="listener:details:credentials"> |
432 |
<title>User-ID and credentials |
423 |
<title>User-ID and Credentials |
433 |
<indexterm><primary>Directory Listener</primary><secondary>Credentials</secondary></indexterm> |
424 |
<indexterm><primary>Directory Listener</primary><secondary>Credentials</secondary></indexterm> |
434 |
</title> |
425 |
</title> |
435 |
<para> |
426 |
<para> |
436 |
The Listener runs with the effective permissions of the user <literal>listener</literal>. |
427 |
The Listener runs with the effective permissions of the user <literal>listener</literal>. |
437 |
If root-privileges are required, <function>listener.setuid()</function> can be used to switch the effective UID. |
428 |
If <literal>root</literal>-privileges are required, <function>listener.setuid()</function> can be used to switch the effective UID. |
438 |
When done, <function>listener.unsetuid()</function> should be called to drop back to the <literal>listener</literal> UID. |
429 |
When done, <function>listener.unsetuid()</function> should be called to drop back to the <literal>listener</literal> UID. It's best practice to code this as <literal>try</literal>/<literal>finally</literal> clauses in Python. |
439 |
</para> |
430 |
</para> |
440 |
</section> |
431 |
</section> |
441 |
|
432 |
|
442 |
<section id="listener:details:cache"> |
433 |
<section id="listener:details:cache"> |
443 |
<title>Internal cache |
434 |
<title>Internal Cache |
444 |
<indexterm><primary>Directory Listener</primary><secondary>Cache</secondary></indexterm> |
435 |
<indexterm><primary>Directory Listener</primary><secondary>Cache</secondary></indexterm> |
445 |
</title> |
436 |
</title> |
446 |
<para> |
437 |
<para> |
|
459 |
This is required when a new module is added, which is invoked for all already existing objects when the &ucsUDL; is restarted. |
450 |
This is required when a new module is added, which is invoked for all already existing objects when the &ucsUDL; is restarted. |
460 |
</para> |
451 |
</para> |
461 |
<para> |
452 |
<para> |
462 |
On Domaincontrollers the cache could be replaced by doing a query to the local LDAP server, before the new values are written into it. |
453 |
On domain controllers the cache could be replaced by doing a query to the local LDAP server, before the new values are written into it. |
463 |
But &ucsMember; do not have a local LDAP server, so there the cache is needed. |
454 |
But &ucsMember; do not have a local LDAP server, so there the cache is needed. |
464 |
Also note that the cache keeps track of the associated Listener modules, which is not available from the LDAP. |
455 |
Also note that the cache keeps track of the associated listener modules, which is not available from the LDAP. |
465 |
</para> |
456 |
</para> |
466 |
</listitem> |
457 |
</listitem> |
467 |
</varlistentry> |
458 |
</varlistentry> |
|
469 |
<term><filename>notifier_id</filename></term> |
460 |
<term><filename>notifier_id</filename></term> |
470 |
<listitem> |
461 |
<listitem> |
471 |
<para> |
462 |
<para> |
472 |
This file contains the <firstterm>notifier id</firstterm> as last queried from the &ucsUDN;. |
463 |
This file contains the last <firstterm>notifier ID</firstterm> read from the &ucsUDN;. |
473 |
</para> |
464 |
</para> |
474 |
</listitem> |
465 |
</listitem> |
475 |
</varlistentry> |
466 |
</varlistentry> |
|
478 |
<listitem> |
469 |
<listitem> |
479 |
<para> |
470 |
<para> |
480 |
For each module the directory contains a text file consisting of a single number. |
471 |
For each module the directory contains a text file consisting of a single number. |
481 |
The name of the file is derived from the values of the variable <varname>name</varname> as defined in each Listener module. |
472 |
The name of the file is derived from the values of the variable <varname>name</varname> as defined in each listener module. |
482 |
The number is to be interpreted as a bit-field of <constant>HANDLER_INITIALIZED=0x1</constant> and <constant>HANDLER_READY=0x2</constant>. |
473 |
The number is to be interpreted as a bit-field of <constant>HANDLER_INITIALIZED=0x1</constant> and <constant>HANDLER_READY=0x2</constant>. |
483 |
If both bits are set, it indicates that the module was successfully initialized by running the function <function>initialize()</function>. |
474 |
If both bits are set, it indicates that the module was successfully initialized by running the function <function>initialize()</function>. |
484 |
Otherwise both bits are unset. |
475 |
Otherwise both bits are unset. |
|
488 |
</variablelist> |
479 |
</variablelist> |
489 |
<para> |
480 |
<para> |
490 |
The package <package>univention-directory-listener</package> contains several commands useful for controlling and debugging problems with the &ucsUDL;. |
481 |
The package <package>univention-directory-listener</package> contains several commands useful for controlling and debugging problems with the &ucsUDL;. |
491 |
This can be useful for debugging Listener cache inconsistencies. |
482 |
This can be useful for debugging listener cache inconsistencies. |
492 |
</para> |
483 |
</para> |
493 |
|
484 |
|
494 |
<section id="listener:commands:ctrl"> |
485 |
<section id="listener:commands:ctrl"> |
495 |
<title>univention-directory-listener-ctrl</title> |
486 |
<title>univention-directory-listener-ctrl</title> |
496 |
<para> |
487 |
<para> |
497 |
The command <command>univention-directory-listener-ctrl resync <replaceable>name</replaceable></command> can be used to reset and re-initialize a Module. |
488 |
The command <command>univention-directory-listener-ctrl resync <replaceable>name</replaceable></command> can be used to reset and re-initialize a module. |
498 |
It stops any currently running listener process, removes the state file for the specified module and starts the listener process again. |
489 |
It stops any currently running listener process, removes the state file for the specified module and starts the listener process again. |
499 |
This forces the functions <function>clean()</function> and <function>initialize()</function> to be called one after each other. |
490 |
This forces the functions <function>clean()</function> and <function>initialize()</function> to be called one after the other. |
500 |
</para> |
491 |
</para> |
501 |
</section> |
492 |
</section> |
502 |
|
493 |
|
|
505 |
<para> |
496 |
<para> |
506 |
The command <command>univention-directory-listener-dump</command> can be used to dump the cache file <filename>/var/lib/univention-directory-listener/cache.db</filename>. |
497 |
The command <command>univention-directory-listener-dump</command> can be used to dump the cache file <filename>/var/lib/univention-directory-listener/cache.db</filename>. |
507 |
The &ucsUDL; must be stopped first by invoking <command>service univention-directory-listener stop</command>. |
498 |
The &ucsUDL; must be stopped first by invoking <command>service univention-directory-listener stop</command>. |
508 |
It outputs the cache in a <abbrev>LDAP</abbrev> Data Interchange Format (<abbrev>LDIF</abbrev>) compatible format. |
499 |
It outputs the cache in format compatible to the <abbrev>LDAP</abbrev> Data Interchange Format (<abbrev>LDIF</abbrev>). |
509 |
</para> |
500 |
</para> |
510 |
</section> |
501 |
</section> |
511 |
|
502 |
|
|
517 |
The command <command>univention-directory-listener-verify</command> can be used to compare the content of the cache file <filename>/var/lib/univention-directory-listener/cache.db</filename> to the content of an <abbrev>LDAP</abbrev> server. |
508 |
The command <command>univention-directory-listener-verify</command> can be used to compare the content of the cache file <filename>/var/lib/univention-directory-listener/cache.db</filename> to the content of an <abbrev>LDAP</abbrev> server. |
518 |
The &ucsUDL; must be stopped first by invoking <command>service univention-directory-listener stop</command>. |
509 |
The &ucsUDL; must be stopped first by invoking <command>service univention-directory-listener stop</command>. |
519 |
<abbrev>LDAP</abbrev> credentials must be supplied at the command line. |
510 |
<abbrev>LDAP</abbrev> credentials must be supplied at the command line. |
520 |
For example, the following command would use the machine secrets: |
511 |
For example, the following command would use the machine password: |
521 |
<programlisting language="sh"> |
512 |
<programlisting language="sh"> |
522 |
univention-directory-listener-verify \ |
513 |
univention-directory-listener-verify \ |
523 |
-b "$(ucr get ldap/base)" \ |
514 |
-b "$(ucr get ldap/base)" \ |
|
535 |
The command <command>/usr/share/univention-directory-listener/get_notifier_id.py</command> can be used to get the latest ID from the notifier. |
526 |
The command <command>/usr/share/univention-directory-listener/get_notifier_id.py</command> can be used to get the latest ID from the notifier. |
536 |
This is done by querying the &ucsUDN; running on the <abbrev>LDAP</abbrev> server configured through the &ucsUCRV; <envar>ldap/master</envar>. |
527 |
This is done by querying the &ucsUDN; running on the <abbrev>LDAP</abbrev> server configured through the &ucsUCRV; <envar>ldap/master</envar>. |
537 |
The returned value should be equal to the value currently stored in the file <filename>/var/lib/univention-directory-listener/notifier_id</filename>. |
528 |
The returned value should be equal to the value currently stored in the file <filename>/var/lib/univention-directory-listener/notifier_id</filename>. |
538 |
Otherwise the &ucsUDL; might still be processing a transaction or might indicate a problem with the &ucsUDL; |
529 |
Otherwise the &ucsUDL; might still be processing a transaction or it might indicate a problem with the &ucsUDL; |
539 |
</para> |
530 |
</para> |
540 |
</section> |
531 |
</section> |
541 |
</section> |
532 |
</section> |
|
549 |
The Listener/Notifier mechanism is used to trigger arbitrary actions when changes occur in the <abbrev>LDAP</abbrev> directory service. |
540 |
The Listener/Notifier mechanism is used to trigger arbitrary actions when changes occur in the <abbrev>LDAP</abbrev> directory service. |
550 |
In addition to the <abbrev>LDAP</abbrev> server <command>slapd</command> it consists of two other services: |
541 |
In addition to the <abbrev>LDAP</abbrev> server <command>slapd</command> it consists of two other services: |
551 |
The &ucsUDN; service runs next to the <abbrev>LDAP</abbrev> server and broadcasts change information to interested parties. |
542 |
The &ucsUDN; service runs next to the <abbrev>LDAP</abbrev> server and broadcasts change information to interested parties. |
552 |
The &ucsUDL; service listens for those notifications, downloads the changes and runs arbitrary local actions like storing the data in a local <abbrev>LDAP</abbrev> server for replication or generating configuration files for non-<abbrev>LDAP</abbrev>-aware local services. |
543 |
The &ucsUDL; service listens for those notifications, downloads the changes and runs listener modules performing arbitrary local actions like storing the data in a local <abbrev>LDAP</abbrev> server for replication or generating configuration files for non-<abbrev>LDAP</abbrev>-aware local services. |
553 |
</para> |
544 |
</para> |
554 |
<figure id="listener:schema"><title>Listener/Notifier mechanism</title> |
545 |
<figure id="listener:schema"><title>Listener/Notifier mechanism</title> |
555 |
<graphic scalefit="1" width="80%" fileref="illustrations/ListenerNotifier.png"/> |
546 |
<graphic scalefit="1" width="80%" fileref="illustrations/ListenerNotifier.png"/> |
|
561 |
<title>Listener/Notifier prcoedure</title> |
552 |
<title>Listener/Notifier prcoedure</title> |
562 |
<step> |
553 |
<step> |
563 |
<para> |
554 |
<para> |
564 |
The <abbrev>LDAP</abbrev> object is modified on the &ucsMaster;. |
555 |
An <abbrev>LDAP</abbrev> object is modified on the &ucsMaster;. |
565 |
Changes initiated on all other system roles are re-directed to the master. |
556 |
Changes initiated on all other system roles are re-directed to the master. |
566 |
</para> |
557 |
</para> |
567 |
</step> |
558 |
</step> |
568 |
<step> |
559 |
<step> |
569 |
<para> |
560 |
<para> |
570 |
The overlay-module <filename>translog</filename> appends the <abbrev>DN</abbrev> to the file <filename>/var/lib/univention-ldap/listener/listener</filename><footnote><simpara><varname>FILE_NAME_LISTENER</varname>, <varname>TRANSACTION_FILE</varname></simpara></footnote>. |
561 |
The UCS-specific overlay-module <filename>translog</filename> appends the <abbrev>DN</abbrev> to the file <filename>/var/lib/univention-ldap/listener/listener</filename><footnote><simpara>Referred to as <varname>FILE_NAME_LISTENER</varname>, <varname>TRANSACTION_FILE</varname> in the source code</simpara></footnote>. |
571 |
</para> |
562 |
</para> |
572 |
</step> |
563 |
</step> |
573 |
<step> |
564 |
<step> |
574 |
<para> |
565 |
<para> |
575 |
The &ucsUDN; watches that file, picks up and removes the modification. |
566 |
The &ucsUDN; watches that file, picks up and removes each line it processed. |
576 |
It assigns the next transaction number and writes it into the file <filename>/var/lib/univention-ldap/notify/transaction</filename><footnote><simpara><varname>FILE_NAME_TF</varname></simpara></footnote>, including the <abbrev>DN</abbrev> and change-type. |
567 |
It assigns the next transaction number and writes it into the file <filename>/var/lib/univention-ldap/notify/transaction</filename><footnote><simpara>Referred to as <varname>FILE_NAME_TF</varname> in the source code</simpara></footnote>, including the <abbrev>DN</abbrev> and change type. |
577 |
For efficient access by transaction ID the index <filename>transaction.index</filename> is updated. |
568 |
For efficient access by transaction ID the index <filename>transaction.index</filename> is updated. |
578 |
</para> |
569 |
</para> |
579 |
</step> |
570 |
</step> |
|
584 |
</step> |
575 |
</step> |
585 |
<step> |
576 |
<step> |
586 |
<para> |
577 |
<para> |
587 |
Each Listener such notified queries the Notifier for the latest transaction ID, <abbrev>DN</abbrev> and change-type. |
578 |
Each Listener triggered in this way queries the Notifier for the latest transaction ID, <abbrev>DN</abbrev> and change type. |
588 |
The ID is written into the file <filename>/var/lib/univention-directory-listener/notifier_id</filename>. |
579 |
The ID is written into the local file <filename>/var/lib/univention-directory-listener/notifier_id</filename>. |
589 |
</para> |
580 |
</para> |
590 |
</step> |
581 |
</step> |
591 |
<step> |
582 |
<step> |
592 |
<para> |
583 |
<para> |
593 |
Each Listener opens a connection to their LDAP server configured through &ucsUCRV; <envar>ldap/master</envar> and <envar>ldap/server/addition:</envar>. |
584 |
Each Listener opens a connection to the LDAP server running on the UCS system which was used to query the Notifier (configured through &ucsUCRV; <envar>ldap/master</envar> and <envar>ldap/server/addition:</envar>). |
594 |
It tries to retrieve the latest state of the object identified through the <abbrev>DN</abbrev>, which might be blocked by <firstterm>selective replication</firstterm>. |
585 |
It tries to retrieve the latest state of the object identified through the <abbrev>DN</abbrev>, which might be blocked by <firstterm>selective replication</firstterm>. |
595 |
If that fails and nothing is returned, the process stops here and closes the <abbrev>LDAP</abbrev> connection. |
586 |
If that fails and nothing is returned, the process stops here and closes the <abbrev>LDAP</abbrev> connection. |
|
|
587 |
<remark>AREQ: Uh, really? A d operation should be processed as well? Maybe rephrase "the process"?</remark> |
596 |
</para> |
588 |
</para> |
597 |
</step> |
589 |
</step> |
598 |
<step> |
590 |
<step> |
599 |
<para> |
591 |
<para> |
600 |
On a &ucsBackup; the &ucsUDL; writes the transaction data to the file <filename>/var/lib/univention-ldap/listener/listener</filename><footnote><simpara><varname>FILE_NAME_LISTENER</varname>, <varname>TRANSACTION_FILE</varname></simpara></footnote> to allow the &ucsUDN; to be cascaded. |
592 |
On a &ucsBackup; the &ucsUDL; writes the transaction data to the file <filename>/var/lib/univention-ldap/listener/listener</filename><footnote><simpara>Referred to as <varname>FILE_NAME_LISTENER</varname>, <varname>TRANSACTION_FILE</varname> in the source code</simpara></footnote> to allow the &ucsUDN; to be cascaded. |
601 |
This can be configured with the option <option>-o</option> of <command>univention-directory-listener</command> and is done for load balancing and reliability reasons. |
593 |
This is automatically internally configured with the option <option>-o</option> of <command>univention-directory-listener</command> and is done for load balancing and failover reasons. |
602 |
</para> |
594 |
</para> |
603 |
</step> |
595 |
</step> |
604 |
<step> |
596 |
<step> |
605 |
<para> |
597 |
<para> |
606 |
The old state of the object is fetched from the Listener cache. |
598 |
The old state of the object is fetched from the local listener cache. |
607 |
</para> |
599 |
</para> |
608 |
</step> |
600 |
</step> |
609 |
<step> |
601 |
<step> |
610 |
<para> |
602 |
<para> |
611 |
For each module it is checked, if the module matches either the old or new state according to the variables <varname>filter</varname> and <varname>attributes</varname>. |
603 |
For each module it is checked, if either the old or new state of the object matches the <varname>filter</varname> and <varname>attributes</varname> specified in the corresponding Python variables. |
612 |
If not, the module is skipped. |
604 |
If not, the module is skipped. |
613 |
</para> |
605 |
</para> |
614 |
</step> |
606 |
</step> |
615 |
<step> |
607 |
<step> |
616 |
<para> |
608 |
<para> |
617 |
If the function <function>prerun()</function> of module was not yet called, this is done to signal the start of changes. |
609 |
If the function <function>prerun()</function> of module was not called yet, this is done to signal the start of changes. |
618 |
</para> |
610 |
</para> |
619 |
</step> |
611 |
</step> |
620 |
<step> |
612 |
<step> |
621 |
<para> |
613 |
<para> |
622 |
The function <function>handler()</function> is called for the module, passing in the <abbrev>DN</abbrev> with the old and new state.<footnote><simpara> |
614 |
The function <function>handler()</function> specified in the module is called, passing in the <abbrev>DN</abbrev> and the old and new state. |
623 |
In previous releases of the &ucsUDL; modules could modify the new state, which was written to the local <abbrev>LDAP</abbrev> server by the last module. |
|
|
624 |
This lead to some very strange problems and was disabled therefore. |
625 |
Each module now gets its own new copy of the values and thus can no longer communicate with subsequent modules. |
626 |
</simpara></footnote> |
627 |
</para> |
615 |
</para> |
628 |
</step> |
616 |
</step> |
629 |
<step> |
617 |
<step> |
630 |
<para> |
618 |
<para> |
631 |
The cache is updated with the new values, including the names of the modules which successfully handled that object. |
619 |
The main listener process updates its cache with the new values, including the names of the modules which successfully handled that object. |
632 |
This guarantees that the module is still called, even when the filter criteria would no longer match the object after modification. |
620 |
This guarantees that the module is still called, even when the filter criteria would no longer match the object after modification. |
633 |
</para> |
621 |
</para> |
634 |
</step> |
622 |
</step> |
|
635 |
<step> |
623 |
<step> |
636 |
<para> |
624 |
<para> |
637 |
After 15 seconds of inactivity the function <function>postrun()</function> is invoked for all prepared modules. |
625 |
After 15 seconds of inactivity the function <function>postrun()</function> is invoked for all prepared modules. |
638 |
This signals the end of changes and requests the module to release its resources and/or start pending operations. |
626 |
This signals a break in the stream of changes and requests the module to release its resources and/or start pending operations. |
639 |
</para> |
627 |
</para> |
640 |
</step> |
628 |
</step> |
641 |
</procedure> |
629 |
</procedure> |