268 lines
11 KiB
Diff
268 lines
11 KiB
Diff
|
From 9b2fc77a36156ea987dcea6e2043f8e4c4a6b259 Mon Sep 17 00:00:00 2001
|
||
|
From: progier389 <progier@redhat.com>
|
||
|
Date: Tue, 18 Jun 2024 14:21:07 +0200
|
||
|
Subject: [PATCH] Issue 6224 - d2entry - Could not open id2entry err 0 - at
|
||
|
startup when having sub-suffixes (#6225)
|
||
|
|
||
|
Problem:: d2entry - Could not open id2entry err 0 is logged at startup when having sub-suffixes
|
||
|
Reason: The slapi_exist_referral internal search access a backend that is not yet started.
|
||
|
Solution: Limit the internal search to a single backend
|
||
|
|
||
|
Issue: #6224
|
||
|
|
||
|
Reviewed by: @droideck Thanks!
|
||
|
|
||
|
(cherry picked from commit 796f703021e961fdd8cbc53b4ad4e20258af0e96)
|
||
|
---
|
||
|
.../tests/suites/ds_logs/ds_logs_test.py | 1 +
|
||
|
.../suites/mapping_tree/regression_test.py | 161 +++++++++++++++++-
|
||
|
ldap/servers/slapd/backend.c | 7 +-
|
||
|
3 files changed, 159 insertions(+), 10 deletions(-)
|
||
|
|
||
|
diff --git a/dirsrvtests/tests/suites/ds_logs/ds_logs_test.py b/dirsrvtests/tests/suites/ds_logs/ds_logs_test.py
|
||
|
index 812936c62..84a9c6ec8 100644
|
||
|
--- a/dirsrvtests/tests/suites/ds_logs/ds_logs_test.py
|
||
|
+++ b/dirsrvtests/tests/suites/ds_logs/ds_logs_test.py
|
||
|
@@ -1222,6 +1222,7 @@ def test_referral_check(topology_st, request):
|
||
|
|
||
|
request.addfinalizer(fin)
|
||
|
|
||
|
+<<<<<<< HEAD
|
||
|
def test_referral_subsuffix(topology_st, request):
|
||
|
"""Test the results of an inverted parent suffix definition in the configuration.
|
||
|
|
||
|
diff --git a/dirsrvtests/tests/suites/mapping_tree/regression_test.py b/dirsrvtests/tests/suites/mapping_tree/regression_test.py
|
||
|
index 99d4a1d5f..689ff9f59 100644
|
||
|
--- a/dirsrvtests/tests/suites/mapping_tree/regression_test.py
|
||
|
+++ b/dirsrvtests/tests/suites/mapping_tree/regression_test.py
|
||
|
@@ -11,10 +11,14 @@ import ldap
|
||
|
import logging
|
||
|
import os
|
||
|
import pytest
|
||
|
+import time
|
||
|
from lib389.backend import Backends, Backend
|
||
|
+from lib389._constants import HOST_STANDALONE, PORT_STANDALONE, DN_DM, PW_DM
|
||
|
from lib389.dbgen import dbgen_users
|
||
|
from lib389.mappingTree import MappingTrees
|
||
|
from lib389.topologies import topology_st
|
||
|
+from lib389.referral import Referrals, Referral
|
||
|
+
|
||
|
|
||
|
try:
|
||
|
from lib389.backend import BackendSuffixView
|
||
|
@@ -31,14 +35,26 @@ else:
|
||
|
logging.getLogger(__name__).setLevel(logging.INFO)
|
||
|
log = logging.getLogger(__name__)
|
||
|
|
||
|
+PARENT_SUFFIX = "dc=parent"
|
||
|
+CHILD1_SUFFIX = f"dc=child1,{PARENT_SUFFIX}"
|
||
|
+CHILD2_SUFFIX = f"dc=child2,{PARENT_SUFFIX}"
|
||
|
+
|
||
|
+PARENT_REFERRAL_DN = f"cn=ref,ou=People,{PARENT_SUFFIX}"
|
||
|
+CHILD1_REFERRAL_DN = f"cn=ref,ou=people,{CHILD1_SUFFIX}"
|
||
|
+CHILD2_REFERRAL_DN = f"cn=ref,ou=people,{CHILD2_SUFFIX}"
|
||
|
+
|
||
|
+REFERRAL_CHECK_PEDIOD = 7
|
||
|
+
|
||
|
+
|
||
|
+
|
||
|
BESTRUCT = [
|
||
|
- { "bename" : "parent", "suffix": "dc=parent" },
|
||
|
- { "bename" : "child1", "suffix": "dc=child1,dc=parent" },
|
||
|
- { "bename" : "child2", "suffix": "dc=child2,dc=parent" },
|
||
|
+ { "bename" : "parent", "suffix": PARENT_SUFFIX },
|
||
|
+ { "bename" : "child1", "suffix": CHILD1_SUFFIX },
|
||
|
+ { "bename" : "child2", "suffix": CHILD2_SUFFIX },
|
||
|
]
|
||
|
|
||
|
|
||
|
-@pytest.fixture(scope="function")
|
||
|
+@pytest.fixture(scope="module")
|
||
|
def topo(topology_st, request):
|
||
|
bes = []
|
||
|
|
||
|
@@ -50,6 +66,9 @@ def topo(topology_st, request):
|
||
|
request.addfinalizer(fin)
|
||
|
|
||
|
inst = topology_st.standalone
|
||
|
+ # Reduce nsslapd-referral-check-period to accelerate test
|
||
|
+ topology_st.standalone.config.set("nsslapd-referral-check-period", str(REFERRAL_CHECK_PEDIOD))
|
||
|
+
|
||
|
ldif_files = {}
|
||
|
for d in BESTRUCT:
|
||
|
bename = d['bename']
|
||
|
@@ -76,14 +95,13 @@ def topo(topology_st, request):
|
||
|
inst.start()
|
||
|
return topology_st
|
||
|
|
||
|
-# Parameters for test_change_repl_passwd
|
||
|
-EXPECTED_ENTRIES = (("dc=parent", 39), ("dc=child1,dc=parent", 13), ("dc=child2,dc=parent", 13))
|
||
|
+# Parameters for test_sub_suffixes
|
||
|
@pytest.mark.parametrize(
|
||
|
"orphan_param",
|
||
|
[
|
||
|
- pytest.param( ( True, { "dc=parent": 2, "dc=child1,dc=parent":1, "dc=child2,dc=parent":1}), id="orphan-is-true" ),
|
||
|
- pytest.param( ( False, { "dc=parent": 3, "dc=child1,dc=parent":1, "dc=child2,dc=parent":1}), id="orphan-is-false" ),
|
||
|
- pytest.param( ( None, { "dc=parent": 3, "dc=child1,dc=parent":1, "dc=child2,dc=parent":1}), id="no-orphan" ),
|
||
|
+ pytest.param( ( True, { PARENT_SUFFIX: 2, CHILD1_SUFFIX:1, CHILD2_SUFFIX:1}), id="orphan-is-true" ),
|
||
|
+ pytest.param( ( False, { PARENT_SUFFIX: 3, CHILD1_SUFFIX:1, CHILD2_SUFFIX:1}), id="orphan-is-false" ),
|
||
|
+ pytest.param( ( None, { PARENT_SUFFIX: 3, CHILD1_SUFFIX:1, CHILD2_SUFFIX:1}), id="no-orphan" ),
|
||
|
],
|
||
|
)
|
||
|
|
||
|
@@ -128,3 +146,128 @@ def test_sub_suffixes(topo, orphan_param):
|
||
|
log.info('Test PASSED')
|
||
|
|
||
|
|
||
|
+def test_one_level_search_on_sub_suffixes(topo):
|
||
|
+ """ Perform one level scoped search accross suffix and sub-suffix
|
||
|
+
|
||
|
+ :id: 92f3139e-280e-11ef-a989-482ae39447e5
|
||
|
+ :feature: mapping-tree
|
||
|
+ :setup: Standalone instance with 3 additional backends:
|
||
|
+ dc=parent, dc=child1,dc=parent, dc=childr21,dc=parent
|
||
|
+ :steps:
|
||
|
+ 1. Perform a ONE LEVEL search on dc=parent
|
||
|
+ 2. Check that all expected entries have been returned
|
||
|
+ 3. Check that only the expected entries have been returned
|
||
|
+ :expectedresults:
|
||
|
+ 1. Success
|
||
|
+ 2. each expected dn should be in the result set
|
||
|
+ 3. Number of returned entries should be the same as the number of expected entries
|
||
|
+ """
|
||
|
+ expected_dns = ( 'dc=child1,dc=parent',
|
||
|
+ 'dc=child2,dc=parent',
|
||
|
+ 'ou=accounting,dc=parent',
|
||
|
+ 'ou=product development,dc=parent',
|
||
|
+ 'ou=product testing,dc=parent',
|
||
|
+ 'ou=human resources,dc=parent',
|
||
|
+ 'ou=payroll,dc=parent',
|
||
|
+ 'ou=people,dc=parent',
|
||
|
+ 'ou=groups,dc=parent', )
|
||
|
+ entries = topo.standalone.search_s("dc=parent", ldap.SCOPE_ONELEVEL, "(objectClass=*)",
|
||
|
+ attrlist=("dc","ou"), escapehatch='i am sure')
|
||
|
+ log.info(f'one level search on dc=parent returned the following entries: {entries}')
|
||
|
+ dns = [ entry.dn for entry in entries ]
|
||
|
+ for dn in expected_dns:
|
||
|
+ assert dn in dns
|
||
|
+ assert len(entries) == len(expected_dns)
|
||
|
+
|
||
|
+
|
||
|
+def test_sub_suffixes_errlog(topo):
|
||
|
+ """ check the entries found on suffix/sub-suffix
|
||
|
+ used int
|
||
|
+
|
||
|
+ :id: 1db9d52e-28de-11ef-b286-482ae39447e5
|
||
|
+ :feature: mapping-tree
|
||
|
+ :setup: Standalone instance with 3 additional backends:
|
||
|
+ dc=parent, dc=child1,dc=parent, dc=childr21,dc=parent
|
||
|
+ :steps:
|
||
|
+ 1. Check that id2entry error message is not in the error log.
|
||
|
+ :expectedresults:
|
||
|
+ 1. Success
|
||
|
+ """
|
||
|
+ inst = topo.standalone
|
||
|
+ assert not inst.searchErrorsLog('id2entry - Could not open id2entry err 0')
|
||
|
+
|
||
|
+
|
||
|
+# Parameters for test_referral_subsuffix:
|
||
|
+# a tuple pair containing:
|
||
|
+# - list of referral dn that must be created
|
||
|
+# - dict of searches basedn: expected_number_of_referrals
|
||
|
+@pytest.mark.parametrize(
|
||
|
+ "parameters",
|
||
|
+ [
|
||
|
+ pytest.param( ((PARENT_REFERRAL_DN, CHILD1_REFERRAL_DN), {PARENT_SUFFIX: 2, CHILD1_SUFFIX:1, CHILD2_SUFFIX:0}), id="Both"),
|
||
|
+ pytest.param( ((PARENT_REFERRAL_DN,), {PARENT_SUFFIX: 1, CHILD1_SUFFIX:0, CHILD2_SUFFIX:0}) , id="Parent"),
|
||
|
+ pytest.param( ((CHILD1_REFERRAL_DN,), {PARENT_SUFFIX: 1, CHILD1_SUFFIX:1, CHILD2_SUFFIX:0}) , id="Child"),
|
||
|
+ pytest.param( ((), {PARENT_SUFFIX: 0, CHILD1_SUFFIX:0, CHILD2_SUFFIX:0}), id="None"),
|
||
|
+ ])
|
||
|
+
|
||
|
+def test_referral_subsuffix(topo, request, parameters):
|
||
|
+ """Test the results of an inverted parent suffix definition in the configuration.
|
||
|
+
|
||
|
+ For more details see:
|
||
|
+ https://www.port389.org/docs/389ds/design/mapping_tree_assembly.html
|
||
|
+
|
||
|
+ :id: 4e111a22-2a5d-11ef-a890-482ae39447e5
|
||
|
+ :feature: referrals
|
||
|
+ :setup: Standalone instance with 3 additional backends:
|
||
|
+ dc=parent, dc=child1,dc=parent, dc=childr21,dc=parent
|
||
|
+
|
||
|
+ :setup: Standalone instance
|
||
|
+ :parametrized: yes
|
||
|
+ :steps:
|
||
|
+ refs,searches = referrals
|
||
|
+
|
||
|
+ 1. Create the referrals according to the current parameter
|
||
|
+ 2. Wait enough time so they get detected
|
||
|
+ 3. For each search base dn, in the current parameter, perform the two following steps
|
||
|
+ 4. In 3. loop: Perform a search with provided base dn
|
||
|
+ 5. In 3. loop: Check that the number of returned referrals is the expected one.
|
||
|
+
|
||
|
+ :expectedresults:
|
||
|
+ all steps succeeds
|
||
|
+ """
|
||
|
+ inst = topo.standalone
|
||
|
+
|
||
|
+ def fin():
|
||
|
+ log.info('Deleting all referrals')
|
||
|
+ for ref in Referrals(inst, PARENT_SUFFIX).list():
|
||
|
+ ref.delete()
|
||
|
+
|
||
|
+ # Set cleanup callback
|
||
|
+ if DEBUGGING:
|
||
|
+ request.addfinalizer(fin)
|
||
|
+
|
||
|
+ # Remove all referrals
|
||
|
+ fin()
|
||
|
+ # Add requested referrals
|
||
|
+ for dn in parameters[0]:
|
||
|
+ refs = Referral(inst, dn=dn)
|
||
|
+ refs.create(basedn=dn, properties={ 'cn': 'ref', 'ref': f'ldap://remote/{dn}'})
|
||
|
+ # Wait that the internal search detects the referrals
|
||
|
+ time.sleep(REFERRAL_CHECK_PEDIOD + 1)
|
||
|
+ # Open a test connection
|
||
|
+ ldc = ldap.initialize(f"ldap://{HOST_STANDALONE}:{PORT_STANDALONE}")
|
||
|
+ ldc.set_option(ldap.OPT_REFERRALS,0)
|
||
|
+ ldc.simple_bind_s(DN_DM,PW_DM)
|
||
|
+
|
||
|
+ # For each search base dn:
|
||
|
+ for basedn,nbref in parameters[1].items():
|
||
|
+ log.info(f"Referrals are: {parameters[0]}")
|
||
|
+ # Perform a search with provided base dn
|
||
|
+ result = ldc.search_s(basedn, ldap.SCOPE_SUBTREE, filterstr="(ou=People)")
|
||
|
+ found_dns = [ dn for dn,entry in result if dn is not None ]
|
||
|
+ found_refs = [ entry for dn,entry in result if dn is None ]
|
||
|
+ log.info(f"Search on {basedn} returned {found_dns} and {found_refs}")
|
||
|
+ # Check that the number of returned referrals is the expected one.
|
||
|
+ log.info(f"Search returned {len(found_refs)} referrals. {nbref} are expected.")
|
||
|
+ assert len(found_refs) == nbref
|
||
|
+ ldc.unbind()
|
||
|
diff --git a/ldap/servers/slapd/backend.c b/ldap/servers/slapd/backend.c
|
||
|
index 498f683b1..f86b0b9b6 100644
|
||
|
--- a/ldap/servers/slapd/backend.c
|
||
|
+++ b/ldap/servers/slapd/backend.c
|
||
|
@@ -230,12 +230,17 @@ slapi_exist_referral(Slapi_Backend *be)
|
||
|
|
||
|
/* search for ("smart") referral entries */
|
||
|
search_pb = slapi_pblock_new();
|
||
|
- server_ctrls = (LDAPControl **) slapi_ch_calloc(2, sizeof (LDAPControl *));
|
||
|
+ server_ctrls = (LDAPControl **) slapi_ch_calloc(3, sizeof (LDAPControl *));
|
||
|
server_ctrls[0] = (LDAPControl *) slapi_ch_malloc(sizeof (LDAPControl));
|
||
|
server_ctrls[0]->ldctl_oid = slapi_ch_strdup(LDAP_CONTROL_MANAGEDSAIT);
|
||
|
server_ctrls[0]->ldctl_value.bv_val = NULL;
|
||
|
server_ctrls[0]->ldctl_value.bv_len = 0;
|
||
|
server_ctrls[0]->ldctl_iscritical = '\0';
|
||
|
+ server_ctrls[1] = (LDAPControl *) slapi_ch_malloc(sizeof (LDAPControl));
|
||
|
+ server_ctrls[1]->ldctl_oid = slapi_ch_strdup(MTN_CONTROL_USE_ONE_BACKEND_EXT_OID);
|
||
|
+ server_ctrls[1]->ldctl_value.bv_val = NULL;
|
||
|
+ server_ctrls[1]->ldctl_value.bv_len = 0;
|
||
|
+ server_ctrls[1]->ldctl_iscritical = '\0';
|
||
|
slapi_search_internal_set_pb(search_pb, suffix, LDAP_SCOPE_SUBTREE,
|
||
|
filter, NULL, 0, server_ctrls, NULL,
|
||
|
(void *) plugin_get_default_component_id(), 0);
|
||
|
--
|
||
|
2.48.0
|
||
|
|