Index: doc/manual/ucsschool-import-handbuch-4.1r2.xml =================================================================== --- doc/manual/ucsschool-import-handbuch-4.1r2.xml (Revision 80401) +++ doc/manual/ucsschool-import-handbuch-4.1r2.xml (Arbeitskopie) @@ -1400,8 +1400,8 @@ from usernames_with_zeros import MyUsernameHandler class MyUserImportFactory(DefaultUserImportFactory): - def make_username_handler(self, username_max_length): - return MyUsernameHandler(username_max_length) + def make_username_handler(self, username_max_length, dry_run=True): + return MyUsernameHandler(username_max_length, dry_run) Index: ucs-school-import/debian/changelog =================================================================== --- ucs-school-import/debian/changelog (Revision 80401) +++ ucs-school-import/debian/changelog (Arbeitskopie) @@ -1,3 +1,10 @@ +ucs-school-import (14.0.16-44) unstable; urgency=low + + * Bug #42465: UsernameHandler does not increase counter in LDAP with dry_run + anymore + + -- Daniel Troeder Thu, 22 Jun 2017 09:33:14 +0200 + ucs-school-import (14.0.16-43) unstable; urgency=low * Bug #44408: move PyHook code to ucsschool.lib Index: ucs-school-import/modules/ucsschool/importer/default_user_import_factory.py =================================================================== --- ucs-school-import/modules/ucsschool/importer/default_user_import_factory.py (Revision 80401) +++ ucs-school-import/modules/ucsschool/importer/default_user_import_factory.py (Arbeitskopie) @@ -214,15 +214,16 @@ """ return ucr - def make_username_handler(self, username_max_length): + def make_username_handler(self, username_max_length, dry_run=True): """ Get a UsernameHandler instance. :param username_max_length: int: created usernames must not be longer than this + :param dry_run: bool: set to False to actually commit changes to LDAP :return: UsernameHandler object """ - return UsernameHandler(username_max_length) + return UsernameHandler(username_max_length, dry_run) def make_user_writer(self, *arg, **kwargs): """ Index: ucs-school-import/modules/ucsschool/importer/models/import_user.py =================================================================== --- ucs-school-import/modules/ucsschool/importer/models/import_user.py (Revision 80401) +++ ucs-school-import/modules/ucsschool/importer/models/import_user.py (Arbeitskopie) @@ -528,7 +528,7 @@ raise FormatError("No username was created from scheme '{}'.".format( self.username_scheme), self.username_scheme, self.to_dict()) if not self.username_handler: - self.__class__.username_handler = self.factory.make_username_handler(self.username_max_length) + self.__class__.username_handler = self.factory.make_username_handler(self.username_max_length, self.config['dry_run']) self.name = self.username_handler.format_username(self.name) def modify(self, lo, validate=True, move_if_necessary=None): Index: ucs-school-import/modules/ucsschool/importer/utils/ldap_connection.py =================================================================== --- ucs-school-import/modules/ucsschool/importer/utils/ldap_connection.py (Revision 80401) +++ ucs-school-import/modules/ucsschool/importer/utils/ldap_connection.py (Arbeitskopie) @@ -37,6 +37,8 @@ _admin_connection = None _admin_position = None +_machine_connection = None +_machine_position = None def get_admin_connection(): @@ -47,3 +49,10 @@ except IOError: raise UcsSchoolImportFatalError("This script must be executed on a DC Master.") return _admin_connection, _admin_position + + +def get_machine_connection(): + global _machine_connection, _machine_position + if not _machine_connection or not _machine_position: + _machine_connection, _machine_position = uldap.getMachineConnection() + return _machine_connection, _machine_position Index: ucs-school-import/modules/ucsschool/importer/utils/username_handler.py =================================================================== --- ucs-school-import/modules/ucsschool/importer/utils/username_handler.py (Revision 80401) +++ ucs-school-import/modules/ucsschool/importer/utils/username_handler.py (Arbeitskopie) @@ -36,7 +36,7 @@ from ldap.dn import escape_dn_chars from univention.admin.uexceptions import noObject -from ucsschool.importer.utils.ldap_connection import get_admin_connection +from ucsschool.importer.utils.ldap_connection import get_admin_connection, get_machine_connection from ucsschool.importer.exceptions import FormatError from ucsschool.importer.utils.logging import get_logger @@ -108,27 +108,40 @@ """ allowed_chars = string.ascii_letters + string.digits + "." + _mem_store = dict() - def __init__(self, username_max_length): + def __init__(self, username_max_length, dry_run=True): + """ + :param username_max_length: int: created usernames will be no longer + than this + :param dry_run: bool: if False use LDAP to store already-used usernames + if True store for one run only in memory + """ self.username_max_length = username_max_length + self.dry_run = dry_run self.logger = get_logger() - self.connection, self.position = get_admin_connection() + if self.dry_run: + self.connection, self.position = get_machine_connection() + else: + self.connection, self.position = get_admin_connection() self.replacement_variable_pattern = re.compile(r'(%s)' % '|'.join(map(re.escape, self.counter_variable_to_function.keys())), flags=re.I) def add_to_ldap(self, username, first_number): assert isinstance(username, basestring) assert isinstance(first_number, basestring) - self.connection.add( - "cn={},cn=unique-usernames,cn=ucsschool,cn=univention,{}".format( - escape_dn_chars(username), self.connection.base), - [ - ("objectClass", "ucsschoolUsername"), - ("ucsschoolUsernameNextNumber", first_number) - ] - ) + if self.dry_run: + self._mem_store[username] = first_number + else: + self.connection.add( + "cn={},cn=unique-usernames,cn=ucsschool,cn=univention,{}".format( + escape_dn_chars(username), self.connection.base), + [ + ("objectClass", "ucsschoolUsername"), + ("ucsschoolUsernameNextNumber", first_number) + ] + ) - def get_next_number(self, username): - assert isinstance(username, basestring) + def _get_next_number_from_ldap(self, username): try: return self.connection.get( "cn={},cn=unique-usernames,cn=ucsschool,cn=univention,{}".format( @@ -137,15 +150,30 @@ except KeyError: raise noObject("Username '{}' not found.".format(username)) + def get_next_number(self, username): + assert isinstance(username, basestring) + if self.dry_run: + try: + res = self._mem_store[username] + except KeyError: + res = self._get_next_number_from_ldap(username) + self._mem_store[username] = res + else: + res = self._get_next_number_from_ldap(username) + return res + def get_and_raise_number(self, username): assert isinstance(username, basestring) cur = self.get_next_number(username) next = int(cur) + 1 - self.connection.modify( - "cn={},cn=unique-usernames,cn=ucsschool,cn=univention,{}".format( - escape_dn_chars(username), self.connection.base), - [("ucsschoolUsernameNextNumber", cur, str(next))] - ) + if self.dry_run: + self._mem_store[username] = str(next) + else: + self.connection.modify( + "cn={},cn=unique-usernames,cn=ucsschool,cn=univention,{}".format( + escape_dn_chars(username), self.connection.base), + [("ucsschoolUsernameNextNumber", cur, str(next))] + ) return cur def remove_bad_chars(self, name):