View | Details | Raw Unified | Return to bug 29420
Collapse All | Expand All

(-)listener/listener.xml (-102 / +90 lines)
 Lines 10-19    Link Here 
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>
 Lines 24-30    Link Here 
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>
 Lines 33-43    Link Here 
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>
 Lines 48-64    Link Here 
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"
 Lines 96-107    Link Here 
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>
 Lines 110-118    Link Here 
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>
 Lines 128-134    Link Here 
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[
 Lines 144-165    Link Here 
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.
 Lines 168-174    Link Here 
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.
 Lines 177-183    Link Here 
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.
 Lines 186-213    Link Here 
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>
 Lines 214-220    Link Here 
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>
 Lines 231-237    Link Here 
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>
 Lines 250-263    Link Here 
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>
 Lines 266-286    Link Here 
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>
 Lines 293-299    Link Here 
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>
 Lines 302-311    Link Here 
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"/>
 Lines 314-324    Link Here 
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"/>
 Lines 326-339    Link Here 
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>
 Lines 342-359    Link Here 
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>
 Lines 364-376    Link Here 
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 &amp;</command>.
363
						To test this run a command like <command>tail -f /tmp/UserList.txt &amp;</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>
 Lines 402-410    Link Here 
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"/>
 Lines 414-420    Link Here 
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
 Lines 429-446    Link Here 
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>
 Lines 459-467    Link Here 
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>
 Lines 469-475    Link Here 
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>
 Lines 478-484    Link Here 
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.
 Lines 488-502    Link Here 
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
 Lines 505-511    Link Here 
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
 Lines 517-523    Link Here 
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)" \
 Lines 535-541    Link Here 
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>
 Lines 549-555    Link Here 
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"/>
 Lines 561-579    Link Here 
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>
 Lines 584-634    Link Here 
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>
 Lines 635-641    Link Here 
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>
(-)listener/modrdn.py (-5 / +3 lines)
 Lines 24-40    Link Here 
24
			handler_schema()
24
			handler_schema()
25
		else:
25
		else:
26
			handler_add(dn, new)
26
			handler_add(dn, new)
27
	elif "z" == command:
28
		pass  # ignore
29
	else:
27
	else:
30
		pass  # error
28
		pass  # ignore, reserved for future use
31
29
32
30
33
def handler_move(old_dn, old, new_dn, dn):
31
def handler_move(old_dn, old, new_dn, dn):
34
	"""Handle rename or move of object."""
32
	"""Handle rename or move of object."""
35
	pass
33
	pass	## replace this
36
34
37
35
38
def handlee_schema():
36
def handlee_schema():
39
	"""Handle change in LDAP schema."""
37
	"""Handle change in LDAP schema."""
40
	pass
38
	pass	## replace this
(-)listener/simple.py (-4 / +4 lines)
 Lines 6-24    Link Here 
6
	elif not new and old:
6
	elif not new and old:
7
		handler_remove(dn, old)
7
		handler_remove(dn, old)
8
	else:
8
	else:
9
		pass  # error
9
		pass  # ignore
10
10
11
11
12
def handler_add(dn, new):
12
def handler_add(dn, new):
13
	"""Handle addition of object."""
13
	"""Handle addition of object."""
14
	pass
14
	pass	# replace this
15
15
16
16
17
def handler_modify(dn, old, new):
17
def handler_modify(dn, old, new):
18
	"""Handle modification of object."""
18
	"""Handle modification of object."""
19
	pass
19
	pass	# replace this
20
20
21
21
22
def handler_remove(dn, old):
22
def handler_remove(dn, old):
23
	"""Handle removal of object."""
23
	"""Handle removal of object."""
24
	pass
24
	pass	# replace this

Return to bug 29420