Bug 41354 - ucsschool-import: support hooks using python code
ucsschool-import: support hooks using python code
Status: CLOSED FIXED
Product: UCS@school
Classification: Unclassified
Component: Import scripts
UCS@school 4.1 R2
Other Linux
: P5 normal (vote)
: UCS@school 4.1 R2
Assigned To: Daniel Tröder
:
Depends on:
Blocks: 41239
  Show dependency treegraph
 
Reported: 2016-05-26 09:35 CEST by Daniel Tröder
Modified: 2016-09-30 12:24 CEST (History)
2 users (show)

See Also:
What kind of report is it?: Feature Request
What type of bug is this?: ---
Who will be affected by this bug?: ---
How will those affected feel about the bug?: ---
User Pain:
Enterprise Customer affected?:
School Customer affected?:
ISV affected?:
Waiting Support:
Flags outvoted (downgraded) after PO Review:
Ticket number:
Bug group (optional):
Max CVSS v3 score:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Daniel Tröder univentionstaff 2016-05-26 09:35:32 CEST
Support hooks using python code

Additionally to the hooks supported by the ucs-school-lib (using expensive subprocess calls, but allowing to run any executable), the import-API should support calling pre- and post-hooks for add/modify/delete actions using Python code.
Comment 1 Daniel Tröder univentionstaff 2016-05-26 15:53:38 CEST
Implemented in r69557.

Subclasses of ucsschool.importer.mass_import.user_import.UserImport can overwrite create_and_modify_hook(ImportUser, hook_time) and delete_hook(ImportUser, hook_time). (hook_time == pre|post)

Modifications of user in create_and_modify_hook(user, "pre") will directly change the user before saving it in LDAP.

I had thought about dynamically loading classes from predefined Python module paths. But the subclass approach is more in line with the rest of the API concept. The UserImport object can be retrieved from the factory with make_user_importer().
Comment 2 Sönke Schwardt-Krummrich univentionstaff 2016-05-26 17:45:50 CEST
What is passed to create_and_modify_hook in "pre" and "post" condition?
I think, an LDAP connection object should also be passed to the hook because there are hooks that alter other objects than the new/modified user.
E.g. if a customer wants to create a samba share object for each created user.
Comment 3 Daniel Tröder univentionstaff 2016-05-30 08:29:41 CEST
The UserImport object has a "connection" attribute. It is documented in the docstring:


def create_and_modify_hook(self, user, hook_time):
	"""
	Run code before or after creating or modifying a user.

	IMPLEMENT ME if you want to use a hook. You'll have full access to the
	data being saved to LDAP. It is much faster than running executables
	from /usr/share/ucs-school-import/hooks/*.

	* See user.action to know which action it is ("A" or "M").
	* With action=A, if hook_time=pre the ImportUser does not exist in
	LDAP, yet. user.dn will be None. If hook_time=post user will be a
	opened ImportUser, loaded from LDAP.
	* With action=M, user is always a opened ImportUser, loaded from LDAP.
	* Use self.connection if you need a LDAP connection.

	:param user: ImportUser
	:param hook_time: str: either "pre" or "post"
	:return: None
	"""
	pass

def delete_hook(self, user, hook_time):
	"""
	Run code before or after deleting a user.

	IMPLEMENT ME if you want to use a hook. You'll have full access to the
	data being saved to LDAP. It is much faster than running executables
	from /usr/share/ucs-school-import/hooks/*.

	* user is a opened ImportUser, loaded from LDAP.
	* Use self.connection if you need a LDAP connection.

	:param user: ImportUser
	:param hook_time: str: either "pre" or "post"
	:return: None
	"""
	pass
Comment 4 Florian Best univentionstaff 2016-05-30 12:32:09 CEST
Why don't you split create_and_modify_hook(..., hook_time) into:
pre_create_hook(), post_create_hook(), pre_modify_hook(), post_modify_hook()?
Comment 5 Daniel Tröder univentionstaff 2016-05-30 14:45:42 CEST
(In reply to Florian Best from comment #4)
> Why don't you split create_and_modify_hook(..., hook_time) into:
> pre_create_hook(), post_create_hook(), pre_modify_hook(), post_modify_hook()?
I can't explain why I didn't do that before, but they are separated as proposed now: r69606.
(Also removes a bug what action=="D".)
Comment 6 Daniel Tröder univentionstaff 2016-06-14 12:43:50 CEST
r70160: Added pyhooks for user.move operation.
Comment 7 Daniel Tröder univentionstaff 2016-06-14 12:44:22 CEST
PS: and an example: /usr/share/doc/ucs-school-import/hook_example.py
Comment 8 Daniel Tröder univentionstaff 2016-06-14 16:33:27 CEST
r70174: PyHook objects can now access the LDAP connection through the uldap object at self.lo.
Comment 9 Sönke Schwardt-Krummrich univentionstaff 2016-06-15 12:27:15 CEST
Tested PyHooks via 34_import-users_via_cli_v2:
- all (pre|post)(create|modify|remove) hooks are called as expected
- input data can be modified in "pre" phase
- working lo object is passed to hook

Create a python hook file with filename suffix ".py" in 
/usr/share/ucs-school-import/pyhooks/user_(create|modify|remove)(pre|post).d/
and place there a subclass of PyHook.
See /usr/share/doc/ucs-school-import/hook_example.py for an example.
Comment 10 Florian Best univentionstaff 2016-06-28 18:24:53 CEST
UCS@school 4.1 R2 has been released:
http://docs.software-univention.de/release-notes-ucsschool-4.1R2v1-de.pdf

If this error occurs again, please use "Clone This Bug".