There is a bug in UDM, which causes the imports from hooks to potentially conflict with each other and result in a traceback. Steps to reproduce: Create the two following files: /usr/lib/python3/dist-packages/univention/admin/hooks.d/import_conflict_hook.py ``` from datetime import datetime from univention.admin.hook import simpleHook class ImportConflictHook(simpleHook): type = 'simpleHook' def hook_ldap_pre_modify(self, obj): time=datetime.now() ``` /usr/lib/python3/dist-packages/univention/admin/hooks.d/import_conflict_hook2.py ``` import datetime from univention.admin.hook import simpleHook class ImportConflictHook2(simpleHook): type = 'simpleHook' def hook_ldap_pre_modify(self, obj): time=datetime.datetime.now() ``` Create two extended attributes: ``` udm settings/extended_attribute create --set name=myhook1 --set CLIName=myhook1 --set shortDescription="myhook1" --set longDescription="myhook1" --set ldapMapping=univentionFreeAttribute20 --set objectC lass=univentionFreeAttributes --set module=users/user --set hook=ImportConflictHook --position "cn=custom attributes,cn=univention,$(ucr get ldap/base)" udm settings/extended_attribute create --set name=myhook2 --set CLIName=myhook2 --set shortDescription="myhook2" --set longDescription="myhook2" --set ldapMapping=univentionFreeAttribute21 --set objectC lass=univentionFreeAttributes --set module=users/user --set hook=ImportConflictHook2 --position "cn=custom attributes,cn=univention,$(ucr get ldap/base)" ``` Make sure that you kill any udm cli server process before you can trigger the error with: ``` udm users/user modify --dn uid=Administrator,cn=users,$(ucr get ldap/base) --set myhook1="test" ``` We assume that this is caused by the shared global state from the import logic in hooks.py: ``` def import_hook_files() -> None: """Load all additional hook files from :file:`.../univention/admin/hooks.d/*.py`""" for dir_ in sys.path: hooks_d = os.path.join(dir_, 'univention/admin/hooks.d/') if os.path.isdir(hooks_d): hooks_files = (os.path.join(hooks_d, f) for f in os.listdir(hooks_d) if f.endswith('.py')) for fn in hooks_files: try: with open(fn, 'rb') as fd: exec(fd.read(), sys.modules[__name__].__dict__) # noqa: S102 log.debug('admin.hook.import_hook_files: importing %r', fn) except Exception: log.exception('admin.hook.import_hook_files: loading %r failed', fn) ```
The relevant error is: Traceback (most recent call last): File "/usr/lib/python3/dist-packages/ucsschool/importer/mass_import/mass_import.py", line 117, in import_users user_import.delete_users(users_to_delete) # 0% - 10% File "/usr/lib/python3/dist-packages/ucsschool/importer/mass_import/user_import.py", line 498, in delete_users success = self.do_delete(user) File "/usr/lib/python3/dist-packages/ucsschool/importer/mass_import/sisopi_user_import.py", line 235, in do_delete success = user.modify(lo=self.connection) File "/usr/lib/python3/dist-packages/ucsschool/importer/models/import_user.py", line 1066, in modify lo, validate, move_if_necessary, check_password_policies=True File "/usr/lib/python3/dist-packages/ucsschool/lib/models/user.py", line 326, in modify return super(User, self).modify(lo=lo, validate=validate, move_if_necessary=move_if_necessary) File "/usr/lib/python3/dist-packages/ucsschool/lib/models/base.py", line 619, in modify success = self.modify_without_hooks(lo, validate, move_if_necessary) File "/usr/lib/python3/dist-packages/ucsschool/importer/models/import_user.py", line 1107, in modify_without_hooks return super(ImportUser, self).modify_without_hooks(lo, validate, move_if_necessary) File "/usr/lib/python3/dist-packages/ucsschool/lib/models/base.py", line 646, in modify_without_hooks self.do_modify(udm_obj, lo) File "/usr/lib/python3/dist-packages/ucsschool/lib/models/user.py", line 379, in do_modify return super(User, self).do_modify(udm_obj, lo) File "/usr/lib/python3/dist-packages/ucsschool/lib/models/base.py", line 681, in do_modify udm_obj.modify(ignore_license=1) File "/usr/lib/python3/dist-packages/univention/admin/handlers/users/user.py", line 1288, in modify return super(object, self).modify(*args, **kwargs) File "/usr/lib/python3/dist-packages/univention/admin/handlers/__init__.py", line 693, in modify dn = self._modify(modify_childs, ignore_license=ignore_license, response=response, serverctrls=serverctrls) File "/usr/lib/python3/dist-packages/univention/admin/handlers/__init__.py", line 1399, in _modify ml = self.call_udm_property_hook('hook_ldap_modlist', self, ml) File "/usr/lib/python3/dist-packages/univention/admin/handlers/__init__.py", line 1121, in call_udm_property_hook changes = func(module, changes) File "<string>", line 59, in hook_ldap_modlist File "<string>", line 73, in convert_ts_in_list File "<string>", line 95, in udm2ldap AttributeError: type object 'datetime.datetime' has no attribute 'datetime'
Let's not mix in the whole hook module contents but only those which match `inspect.getmembers(x, lambda m: inspect.isclass(m) and and issubclass(m, (simpleHook, AttributeHook)) and m not in (simpleHook, AttributeHook))`
MR: https://git.knut.univention.de/univention/ucs/-/merge_requests/1412
Second time the customer ran into this. After they upgraded to 5.2-1 their hook, maybe our temporary fix was overwritten, caused the user import to fail again
Merged after functional QA: c2643de7579 | restrict namespace of hooks c26fa798778 | restrict namespace of syntax extension modules 1605c0350a2 | Changelog and advisory Successful build Package: univention-directory-manager-modules Version: 17.0.34 Branch: 5.2-0 Scope: errata5.2-1
Florian warned that there is a risk of regression for people that didn't properly import their dependencies in a hook or syntax extension module, e.g. doing this in a syntax.d/foo.py: class Foo(string): pass Without "from univention.admin.syntax import string". Those modules would now fail to load. In the case of syntax extensions I discovered during QA that there is no log message written into /var/log/univention/directory-manager-cmd.log maybe because logging is not yet initialized at the point of import. Maybe we can try: newbehavior except: log warning and do oldbehavior?
First only restrict namespace of hook extension modules, as syntax extensions may currently depend on implicit imports. 76711fe09e3 | revert(udm): restrict namespace of syntax extension modules Package: univention-directory-manager-modules Version: 17.0.35 Branch: 5.2-0 Scope: errata5.2-1
Verified: * Code review & functional test * CI tests
<https://errata.software-univention.de/#/?erratum=5.2x90>
*** Bug 53350 has been marked as a duplicate of this bug. ***