#9747 Nightly-previous-selinux ipa-4-10 failing in test_integration/test_simple_replication.py::TestSimpleRon::test_user_replication_to_master
Opened 2 months ago by dhanina. Modified 2 months ago

The nightly-previous-selinux ipa-4-10 test test_integration/test_simple_replication.py::TestSimpleReplication::test_user_replication_to_master fails at ldap.NO_SUCH_OBJECT: {'msgtype': 101, 'msgid': 4, 'result': 32, 'desc': 'No such object', 'ctrls': [], 'matched': 'cn=users,cn=accounts,dc=ufreeipa,dc=test'}.

This is possibly related to LDAP issues, for some reason LDAP can't find the created users. It seems that the replicate doesn't copy it's users over, however I'm not sure of that.

self = <ipatests.pytest_ipa.integration.host.LDAPClientWithoutCertCheck object at 0x7fae2b201890>
arg_desc = None

    @contextlib.contextmanager
    def error_handler(self, arg_desc=None):
        """Context manager that handles LDAPErrors
        """
        desc = None
        try:
            try:
>               yield

arg_desc   = None
desc       = 'No such object'
info       = ''
self       = <ipatests.pytest_ipa.integration.host.LDAPClientWithoutCertCheck object at 0x7fae2b201890>

../ipapython/ipaldap.py:1096: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <ipatests.pytest_ipa.integration.host.LDAPClientWithoutCertCheck object at 0x7fae2b201890>
filter = '(objectClass=*)', attrs_list = None
base_dn = ipapython.dn.DN('uid=testuser2,cn=users,cn=accounts,dc=ufreeipa,dc=test')
scope = 0, time_limit = -1.0, size_limit = 0, paged_search = False
get_effective_rights = False

    def find_entries(
            self, filter=None, attrs_list=None, base_dn=None,
            scope=ldap.SCOPE_SUBTREE, time_limit=None, size_limit=None,
            paged_search=False, get_effective_rights=False):
        """
        Return a list of entries and indication of whether the results were
        truncated ([(dn, entry_attrs)], truncated) matching specified search
        parameters followed by truncated flag. If the truncated flag is True,
        search hit a server limit and its results are incomplete.

        Keyword arguments:
        :param attrs_list: list of attributes to return, all if None
                           (default None)
        :param base_dn: dn of the entry at which to start the search
                        (default '')
        :param scope: search scope, see LDAP docs (default ldap2.SCOPE_SUBTREE)
        :param time_limit: time limit in seconds (default unlimited)
        :param size_limit: size (number of entries returned) limit
                           (default unlimited)
        :param paged_search: search using paged results control
        :param get_effective_rights: use GetEffectiveRights control

        :raises: errors.NotFound if result set is empty
                                 or base_dn doesn't exist
        """
        if base_dn is None:
            base_dn = DN()
        assert isinstance(base_dn, DN)
        if not filter:
            filter = '(objectClass=*)'
        res = []
        truncated = False

        if time_limit is None:
            time_limit = self.time_limit
        if time_limit == 0:
            time_limit = -1.0

        if size_limit is None:
            size_limit = self.size_limit

        if not isinstance(size_limit, int):
            size_limit = int(size_limit)
        if not isinstance(time_limit, float):
            time_limit = float(time_limit)

        if attrs_list:
            attrs_list = [a.lower() for a in set(attrs_list)]

        base_sctrls = []
        if get_effective_rights:
            base_sctrls.append(self.__get_effective_rights_control())

        cookie = ''
        page_size = (size_limit if size_limit > 0 else 2000) - 1
        if page_size == 0:
            paged_search = False

        # pass arguments to python-ldap
        with self.error_handler():
            if six.PY2:
                filter = self.encode(filter)
                attrs_list = self.encode(attrs_list)

            while True:
                if paged_search:
                    sctrls = base_sctrls + [
                        SimplePagedResultsControl(0, page_size, cookie)
                    ]
                else:
                    sctrls = base_sctrls or None

                try:
                    id = self.conn.search_ext(
                        str(base_dn), scope, filter, attrs_list,
                        serverctrls=sctrls, timeout=time_limit,
                        sizelimit=size_limit
                    )
                    while True:
                        result = self.conn.result3(id, 0)
                        objtype, res_list, _res_id, res_ctrls = result
                        if objtype == ldap.RES_SEARCH_RESULT:
                            break
                        res_list = self._convert_result(res_list)
                        if res_list:
                            res.append(res_list[0])

                    if paged_search:
                        # Get cookie for the next page
                        for ctrl in res_ctrls:
                            if isinstance(ctrl, SimplePagedResultsControl):
                                cookie = ctrl.cookie
                                break
                        else:
                            cookie = ''
                except ldap.ADMINLIMIT_EXCEEDED:
                    truncated = TRUNCATED_ADMIN_LIMIT
                    break
                except ldap.SIZELIMIT_EXCEEDED:
                    truncated = TRUNCATED_SIZE_LIMIT
                    break
                except ldap.TIMELIMIT_EXCEEDED:
                    truncated = TRUNCATED_TIME_LIMIT
                    break
                except ldap.LDAPError as e:
                    # If paged search is in progress, try to cancel it
                    if paged_search and cookie:
                        sctrls = [SimplePagedResultsControl(0, 0, cookie)]
                        try:
                            self.conn.search_ext_s(
                                str(base_dn), scope, filter, attrs_list,
                                serverctrls=sctrls, timeout=time_limit,
                                sizelimit=size_limit)
                        except ldap.LDAPError as e2:
                            logger.warning(
                                "Error cancelling paged search: %s", e2)
                        cookie = ''

                    try:
>                       raise e

attrs_list = None
base_dn    = ipapython.dn.DN('uid=testuser2,cn=users,cn=accounts,dc=ufreeipa,dc=test')
base_sctrls = []
cookie     = ''
filter     = '(objectClass=*)'
get_effective_rights = False
id         = 4
page_size  = 1999
paged_search = False
res        = []
scope      = 0
sctrls     = None
self       = <ipatests.pytest_ipa.integration.host.LDAPClientWithoutCertCheck object at 0x7fae2b201890>
size_limit = 0
time_limit = -1.0
truncated  = False

../ipapython/ipaldap.py:1600: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <ipatests.pytest_ipa.integration.host.LDAPClientWithoutCertCheck object at 0x7fae2b201890>
filter = '(objectClass=*)', attrs_list = None
base_dn = ipapython.dn.DN('uid=testuser2,cn=users,cn=accounts,dc=ufreeipa,dc=test')
scope = 0, time_limit = -1.0, size_limit = 0, paged_search = False
get_effective_rights = False

    def find_entries(
            self, filter=None, attrs_list=None, base_dn=None,
            scope=ldap.SCOPE_SUBTREE, time_limit=None, size_limit=None,
            paged_search=False, get_effective_rights=False):
        """
        Return a list of entries and indication of whether the results were
        truncated ([(dn, entry_attrs)], truncated) matching specified search
        parameters followed by truncated flag. If the truncated flag is True,
        search hit a server limit and its results are incomplete.

        Keyword arguments:
        :param attrs_list: list of attributes to return, all if None
                           (default None)
        :param base_dn: dn of the entry at which to start the search
                        (default '')
        :param scope: search scope, see LDAP docs (default ldap2.SCOPE_SUBTREE)
        :param time_limit: time limit in seconds (default unlimited)
        :param size_limit: size (number of entries returned) limit
                           (default unlimited)
        :param paged_search: search using paged results control
        :param get_effective_rights: use GetEffectiveRights control

        :raises: errors.NotFound if result set is empty
                                 or base_dn doesn't exist
        """
        if base_dn is None:
            base_dn = DN()
        assert isinstance(base_dn, DN)
        if not filter:
            filter = '(objectClass=*)'
        res = []
        truncated = False

        if time_limit is None:
            time_limit = self.time_limit
        if time_limit == 0:
            time_limit = -1.0

        if size_limit is None:
            size_limit = self.size_limit

        if not isinstance(size_limit, int):
            size_limit = int(size_limit)
        if not isinstance(time_limit, float):
            time_limit = float(time_limit)

        if attrs_list:
            attrs_list = [a.lower() for a in set(attrs_list)]

        base_sctrls = []
        if get_effective_rights:
            base_sctrls.append(self.__get_effective_rights_control())

        cookie = ''
        page_size = (size_limit if size_limit > 0 else 2000) - 1
        if page_size == 0:
            paged_search = False

        # pass arguments to python-ldap
        with self.error_handler():
            if six.PY2:
                filter = self.encode(filter)
                attrs_list = self.encode(attrs_list)

            while True:
                if paged_search:
                    sctrls = base_sctrls + [
                        SimplePagedResultsControl(0, page_size, cookie)
                    ]
                else:
                    sctrls = base_sctrls or None

                try:
                    id = self.conn.search_ext(
                        str(base_dn), scope, filter, attrs_list,
                        serverctrls=sctrls, timeout=time_limit,
                        sizelimit=size_limit
                    )
                    while True:
>                       result = self.conn.result3(id, 0)

attrs_list = None
base_dn    = ipapython.dn.DN('uid=testuser2,cn=users,cn=accounts,dc=ufreeipa,dc=test')
base_sctrls = []
cookie     = ''
filter     = '(objectClass=*)'
get_effective_rights = False
id         = 4
page_size  = 1999
paged_search = False
res        = []
scope      = 0
sctrls     = None
self       = <ipatests.pytest_ipa.integration.host.LDAPClientWithoutCertCheck object at 0x7fae2b201890>
size_limit = 0
time_limit = -1.0
truncated  = False

../ipapython/ipaldap.py:1560: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <ldap.ldapobject.SimpleLDAPObject object at 0x7fae2b201650>, msgid = 4
all = 0, timeout = None, resp_ctrl_classes = None

    def result3(self,msgid=ldap.RES_ANY,all=1,timeout=None,resp_ctrl_classes=None):
>     resp_type, resp_data, resp_msgid, decoded_resp_ctrls, retoid, retval = self.result4(
        msgid,all,timeout,
        add_ctrls=0,add_intermediates=0,add_extop=0,
        resp_ctrl_classes=resp_ctrl_classes
      )

all        = 0
msgid      = 4
resp_ctrl_classes = None
self       = <ldap.ldapobject.SimpleLDAPObject object at 0x7fae2b201650>
timeout    = None

/usr/lib64/python3.11/site-packages/ldap/ldapobject.py:543: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <ldap.ldapobject.SimpleLDAPObject object at 0x7fae2b201650>, msgid = 4
all = 0, timeout = -1, add_ctrls = 0, add_intermediates = 0, add_extop = 0
resp_ctrl_classes = None

    def result4(self,msgid=ldap.RES_ANY,all=1,timeout=None,add_ctrls=0,add_intermediates=0,add_extop=0,resp_ctrl_classes=None):
      if timeout is None:
        timeout = self.timeout
>     ldap_result = self._ldap_call(self._l.result4,msgid,all,timeout,add_ctrls,add_intermediates,add_extop)

add_ctrls  = 0
add_extop  = 0
add_intermediates = 0
all        = 0
msgid      = 4
resp_ctrl_classes = None
self       = <ldap.ldapobject.SimpleLDAPObject object at 0x7fae2b201650>
timeout    = -1

/usr/lib64/python3.11/site-packages/ldap/ldapobject.py:553: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <ldap.ldapobject.SimpleLDAPObject object at 0x7fae2b201650>
func = <built-in method result4 of LDAP object at 0x7fae29a2f270>
args = (4, 0, -1, 0, 0, 0), kwargs = {}, diagnostic_message_success = None

    def _ldap_call(self,func,*args,**kwargs):
      """
      Wrapper method mainly for serializing calls into OpenLDAP libs
      and trace logs
      """
      self._ldap_object_lock.acquire()
      if __debug__:
        if self._trace_level>=1:
          self._trace_file.write('*** {} {} - {}\n{}\n'.format(
            repr(self),
            self._uri,
            '.'.join((self.__class__.__name__,func.__name__)),
            pprint.pformat((args,kwargs))
          ))
          if self._trace_level>=9:
            traceback.print_stack(limit=self._trace_stack_limit,file=self._trace_file)
      diagnostic_message_success = None
      try:
        try:
>         result = func(*args,**kwargs)
E         ldap.NO_SUCH_OBJECT: {'msgtype': 101, 'msgid': 4, 'result': 32, 'desc': 'No such object', 'ctrls': [], 'matched': 'cn=users,cn=accounts,dc=ufreeipa,dc=test'}

args       = (4, 0, -1, 0, 0, 0)
diagnostic_message_success = None
func       = <built-in method result4 of LDAP object at 0x7fae29a2f270>
kwargs     = {}
self       = <ldap.ldapobject.SimpleLDAPObject object at 0x7fae2b201650>

/usr/lib64/python3.11/site-packages/ldap/ldapobject.py:128: NO_SUCH_OBJECT

During handling of the above exception, another exception occurred:

self = <ipatests.test_integration.test_simple_replication.TestSimpleReplication object at 0x7fae2b1403d0>

    def test_user_replication_to_master(self):
        """Test user replication replica -> master"""
>       check_replication(self.replicas[0], self.master, 'testuser2')

self       = <ipatests.test_integration.test_simple_replication.TestSimpleReplication object at 0x7fae2b1403d0>

test_integration/test_simple_replication.py:76: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
test_integration/test_simple_replication.py:51: in check_replication
    entry = ldap.get_entry(user_dn)
        basedn     = ipapython.dn.DN('dc=ufreeipa,dc=test')
        dest_host  = <ipatests.pytest_ipa.integration.host.Host master.ufreeipa.test (master)>
        ldap       = <ipatests.pytest_ipa.integration.host.LDAPClientWithoutCertCheck object at 0x7fae2b201890>
        login      = 'testuser2'
        source_host = <ipatests.pytest_ipa.integration.host.Host replica.ufreeipa.test (replica)>
        source_ldap = <ipatests.pytest_ipa.integration.host.LDAPClientWithoutCertCheck object at 0x7fae2b97a3d0>
        user_dn    = ipapython.dn.DN('uid=testuser2,cn=users,cn=accounts,dc=ufreeipa,dc=test')
../ipapython/ipaldap.py:1655: in get_entry
    entries = self.get_entries(
        attrs_list = None
        dn         = ipapython.dn.DN('uid=testuser2,cn=users,cn=accounts,dc=ufreeipa,dc=test')
        get_effective_rights = False
        self       = <ipatests.pytest_ipa.integration.host.LDAPClientWithoutCertCheck object at 0x7fae2b201890>
        size_limit = None
        time_limit = None
../ipapython/ipaldap.py:1466: in get_entries
    entries, truncated = self.find_entries(
        attrs_list = None
        base_dn    = ipapython.dn.DN('uid=testuser2,cn=users,cn=accounts,dc=ufreeipa,dc=test')
        filter     = None
        get_effective_rights = False
        kwargs     = {'size_limit': None, 'time_limit': None}
        scope      = 0
        self       = <ipatests.pytest_ipa.integration.host.LDAPClientWithoutCertCheck object at 0x7fae2b201890>
../ipapython/ipaldap.py:1540: in find_entries
    with self.error_handler():
        attrs_list = None
        base_dn    = ipapython.dn.DN('uid=testuser2,cn=users,cn=accounts,dc=ufreeipa,dc=test')
        base_sctrls = []
        cookie     = ''
        filter     = '(objectClass=*)'
        get_effective_rights = False
        id         = 4
        page_size  = 1999
        paged_search = False
        res        = []
        scope      = 0
        sctrls     = None
        self       = <ipatests.pytest_ipa.integration.host.LDAPClientWithoutCertCheck object at 0x7fae2b201890>
        size_limit = 0
        time_limit = -1.0
        truncated  = False
/usr/lib64/python3.11/contextlib.py:158: in __exit__
    self.gen.throw(typ, value, traceback)
        self       = <contextlib._GeneratorContextManager object at 0x7fae2b202450>
        traceback  = <traceback object at 0x7fae2b201f40>
        typ        = <class 'ldap.NO_SUCH_OBJECT'>
        value      = NO_SUCH_OBJECT({'msgtype': 101, 'msgid': 4, 'result': 32, 'desc': 'No such object', 'ctrls': [], 'matched': 'cn=users,cn=accounts,dc=ufreeipa,dc=test'})
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <ipatests.pytest_ipa.integration.host.LDAPClientWithoutCertCheck object at 0x7fae2b201890>
arg_desc = None

    @contextlib.contextmanager
    def error_handler(self, arg_desc=None):
        """Context manager that handles LDAPErrors
        """
        desc = None
        try:
            try:
                yield
            except ldap.TIMEOUT:
                raise errors.DatabaseTimeout()
            except ldap.LDAPError as e:
                desc = e.args[0]['desc'].strip()
                info = e.args[0].get('info', '').strip()
                if arg_desc is not None:
                    info = "%s arguments: %s" % (info, arg_desc)
                raise
        except ldap.NO_SUCH_OBJECT:
>           raise errors.NotFound(reason=arg_desc or 'no such entry')
E           ipalib.errors.NotFound: no such entry

arg_desc   = None
desc       = 'No such object'
info       = ''
self       = <ipatests.pytest_ipa.integration.host.LDAPClientWithoutCertCheck object at 0x7fae2b201890>

../ipapython/ipaldap.py:1106: NotFound

Logs
Artifacts


From the logs:
- the user gets added to the replica at 12:01:06

[07/Feb/2025:12:01:06.923811459 +0000] conn=22 op=5 ADD dn="uid=testuser2,cn=users,cn=accounts,dc=ufreeipa,dc=test"

After that, the test checks if replication is complete:

dn: cn=meTomaster.ufreeipa.test,cn=replica,cn=dc\=ufreeipa\,dc\=test,cn=mapping tree,cn=config
nsds5replicalastupdatestatus: Error (0) Replica acquired successfully: Incre
 mental update succeeded
nsds5replicaupdateinprogress: FALSE

On the master:
The search for testuser2 happens before the add:

[07/Feb/2025:12:01:08.859879356 +0000] conn=138 op=3 SRCH base="uid=testuser2,cn=users,cn=accounts,dc=ufreeipa,dc=test" scope=0 filter="(objectClass=*)" attrs=ALL
[07/Feb/2025:12:01:08.873188581 +0000] conn=138 op=3 RESULT err=32 tag=101 nentries=0 wtime=0.000090840 optime=0.013308453 etime=0.013394064
[07/Feb/2025:12:01:08.943222515 +0000] conn=131 op=44 RESULT err=0 tag=120 nentries=0 wtime=0.000174547 optime=0.364617358 etime=0.364790252
[07/Feb/2025:12:01:09.234720965 +0000] conn=131 op=45 MOD dn="dnaHostname=replica.ufreeipa.test+dnaPortNum=389,cn=posix-ids,cn=dna,cn=ipa,cn=etc,dc=ufreeipa,dc=test"
[07/Feb/2025:12:01:09.280431903 +0000] conn=131 op=45 RESULT err=0 tag=103 nentries=0 wtime=0.000247915 optime=0.045717941 etime=0.045963602 csn=67a5f603000200030000
[07/Feb/2025:12:01:09.287516236 +0000] conn=131 op=46 ADD dn="uid=testuser2,cn=users,cn=accounts,dc=ufreeipa,dc=test"
[07/Feb/2025:12:01:09.349890177 +0000] conn=131 op=46 RESULT err=0 tag=105 nentries=0 wtime=0.000360786 optime=0.062384942 etime=0.062742101 csn=67a5f603000300030000

so it looks like the replication was marked as complete while it was not.

Log in to comment on this ticket.

Metadata