From e03fb6f3f32923734836a2d1db963ad2628a473d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Kuzn=C3=ADk?= Date: Thu, 24 Oct 2024 16:04:26 +0100 Subject: [PATCH 1/5] ITS#10278 Port testsuite to python-ldap --- tests/python/backends.py | 13 +++++++------ tests/python/overlays.py | 11 ++++++----- tests/python/slapd.py | 21 +++++++++++---------- tests/python/syncrepl.py | 24 +++++++++++++----------- 4 files changed, 37 insertions(+), 32 deletions(-) diff --git a/tests/python/backends.py b/tests/python/backends.py index e7c2c3deb6..bb1ebf9465 100755 --- a/tests/python/backends.py +++ b/tests/python/backends.py @@ -20,7 +20,7 @@ OpenLDAP fixtures for backends """ -import ldap0 +import ldap import logging import os import pathlib @@ -28,7 +28,7 @@ import pytest import secrets import tempfile -from ldap0.controls.readentry import PostReadControl +from ldap.controls.readentry import PostReadControl from .slapd import server @@ -62,10 +62,11 @@ class Database: # We're just after the generated DN, no other attributes at the moment control = PostReadControl(True, []) - result = conn.add_s( - f"olcDatabase={backend},cn=config", self._entry(), - req_ctrls=[control]) - dn = result.ctrls[0].res.dn_s + _, _, _, ctrls = conn.add_ext_s( + f"olcDatabase={backend},cn=config", + list(self._entry().items()), + serverctrls=[control]) + dn = ctrls[0].dn self.dn = dn server.suffixes[suffix] = self diff --git a/tests/python/overlays.py b/tests/python/overlays.py index 8fbb54de45..6d78d9e202 100755 --- a/tests/python/overlays.py +++ b/tests/python/overlays.py @@ -24,7 +24,7 @@ import logging import os import pathlib -from ldap0.controls.readentry import PostReadControl +from ldap.controls.readentry import PostReadControl SOURCEROOT = pathlib.Path(os.environ.get('TOP_SRCDIR', "..")).absolute() @@ -53,10 +53,11 @@ class Overlay: # We're just after the generated DN, no other attributes at the moment control = PostReadControl(True, []) - result = conn.add_s( - f"olcOverlay={overlay_name},{database.dn}", self._entry(), - req_ctrls=[control]) - self.dn = result.ctrls[0].res.dn_s + _, _, _, ctrls = conn.add_ext_s( + f"olcOverlay={overlay_name},{database.dn}", + list(self._entry().items()), + serverctrls=[control]) + self.dn = ctrls[0].dn if order == -1: database.overlays.append(self) diff --git a/tests/python/slapd.py b/tests/python/slapd.py index 68945b43b4..b138113240 100755 --- a/tests/python/slapd.py +++ b/tests/python/slapd.py @@ -20,7 +20,7 @@ OpenLDAP server fixtures """ -import ldap0 +import ldap import ldapurl import logging import os @@ -34,7 +34,7 @@ import subprocess import tempfile import textwrap -from ldap0.ldapobject import LDAPObject +from ldap.ldapobject import LDAPObject SOURCEROOT = pathlib.Path(os.environ.get('TOP_SRCDIR', "..")).absolute() @@ -208,12 +208,13 @@ class Server: conn.simple_bind_s('cn=config', self.secret) moduleload_object = None - for entry in conn.search_s('cn=config', ldap0.SCOPE_SUBTREE, + for dn, attrs in conn.search_s('cn=config', ldap.SCOPE_SUBTREE, 'objectclass=olcModuleList', ['olcModuleLoad']): if not moduleload_object: - moduleload_object = entry.dn_s - for value in entry.entry_s.get('olcModuleLoad', []): + moduleload_object = dn + for value in attrs.get('olcModuleLoad', []): + value = value.decode() if value[0] == '{': value = value[value.find('}')+1:] if pathlib.Path(value).stem == module_name: @@ -224,11 +225,11 @@ class Server: if moduleload_object: conn.modify_s( moduleload_object, - [(ldap0.MOD_ADD, b'olcModuleLoad', [str(module).encode()])]) + [(ldap.MOD_ADD, 'olcModuleLoad', [str(module).encode()])]) else: - conn.add_s('cn=module,cn=config', - {'objectClass': [b'olcModuleList'], - 'olcModuleLoad': [str(module).encode()]}) + entry = {'objectClass': [b'olcModuleList'], + 'olcModuleLoad': [str(module).encode()]} + conn.add_s('cn=module,cn=config', list(entry.items())) @property def uri(self): @@ -292,4 +293,4 @@ def server(server_factory): def test_rootdse(server): conn = server.connect() - conn.search_s("", scope=ldap0.SCOPE_BASE) + conn.search_s("", scope=ldap.SCOPE_BASE) diff --git a/tests/python/syncrepl.py b/tests/python/syncrepl.py index 32ae9cd1ed..8fa03d4dba 100755 --- a/tests/python/syncrepl.py +++ b/tests/python/syncrepl.py @@ -20,7 +20,7 @@ OpenLDAP fixtures for overlays """ -import ldap0 +import ldap import logging import os import pathlib @@ -86,7 +86,7 @@ def mmr(request, server_factory): conn.simple_bind_s("cn=config", server.secret) conn.modify_s("cn=config", [ - (ldap0.MOD_REPLACE, b"olcServerId", [str(serverid).encode()])]) + (ldap.MOD_REPLACE, "olcServerId", [str(serverid).encode()])]) server.serverid = serverid servers[serverid] = server @@ -110,8 +110,8 @@ def mmr(request, server_factory): f'binddn="{db.suffix}" credentials="{db.secret}"').encode()) connections[serverid].modify_s(db.dn, [ - (ldap0.MOD_REPLACE, b"olcSyncrepl", syncrepl), - (ldap0.MOD_REPLACE, b"olcMultiprovider", [b"TRUE"])]) + (ldap.MOD_REPLACE, "olcSyncrepl", syncrepl), + (ldap.MOD_REPLACE, "olcMultiprovider", [b"TRUE"])]) yield servers @@ -142,27 +142,29 @@ def test_mmr(mmr): conn.simple_bind_s(db.rootdn, db.secret) if not entries_added: - conn.add_s(suffix, { + entry = { "objectClass": [b"organization", b"domainRelatedObject", b"dcobject"], "o": [b"Example, Inc."], - "associatedDomain": [b"example.com"]}) + "associatedDomain": [b"example.com"]} + conn.add_s(suffix, list(entry.items())) entries_added.add(suffix) # Make sure all hosts have the suffix entry wait_for_resync(suffix, mmr.values()) dn = f"cn=entry{serverid},{suffix}" - conn.add_s(dn, {"objectClass": [b"device"], - "description": [(f"Entry created on serverid " - f"{serverid}").encode()]}) + entry = {"objectClass": [b"device"], + "description": [(f"Entry created on serverid " + f"{serverid}").encode()]} + conn.add_s(dn, list(entry.items())) entries_added.add(dn) connections.append(conn) wait_for_resync(suffix, mmr.values()) for conn in connections: - result = conn.search_s(suffix, ldap0.SCOPE_SUBTREE, attrlist=['1.1']) - dns = {entry.dn_s for entry in result} + result = conn.search_s(suffix, ldap.SCOPE_SUBTREE, attrlist=['1.1']) + dns = {dn for dn, entry in result} assert dns == entries_added, \ f"Server {serverid} contents do not match expectations" From 9b2e20e7352800c3982c68a509ae67df791a3bd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Kuzn=C3=ADk?= Date: Thu, 24 Oct 2024 16:05:30 +0100 Subject: [PATCH 2/5] ITS#9596 Do not delete test data unless requested --- tests/python/backends.py | 2 +- tests/python/slapd.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/python/backends.py b/tests/python/backends.py index bb1ebf9465..850ff3b50c 100755 --- a/tests/python/backends.py +++ b/tests/python/backends.py @@ -54,7 +54,7 @@ class Database: raise RuntimeError(f"Suffix {suffix} already configured in server") if self.have_directory: - self.directory = tempfile.TemporaryDirectory(dir=server.home) + self.directory = tempfile.TemporaryDirectory(dir=server.home, delete=False) conn = server.connect() conn.simple_bind_s("cn=config", server.secret) diff --git a/tests/python/slapd.py b/tests/python/slapd.py index b138113240..f6a2839227 100755 --- a/tests/python/slapd.py +++ b/tests/python/slapd.py @@ -252,7 +252,7 @@ class ServerManager: return self.address[1] def new_server(self): - path = tempfile.TemporaryDirectory(dir=self.tmpdir) + path = tempfile.TemporaryDirectory(dir=self.tmpdir, delete=False) return Server(path, self) def wait(self, token): From 0d6e0ead6afe5a1858f655c42d5844dbc27f416a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Kuzn=C3=ADk?= Date: Thu, 24 Oct 2024 16:08:18 +0100 Subject: [PATCH 3/5] ITS#9596 Also load backends that aren't compiled in --- tests/python/backends.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/tests/python/backends.py b/tests/python/backends.py index 850ff3b50c..a4b6ca3aa4 100755 --- a/tests/python/backends.py +++ b/tests/python/backends.py @@ -36,6 +36,7 @@ from .slapd import server SOURCEROOT = pathlib.Path(os.environ.get('TOP_SRCDIR', "..")).absolute() BUILDROOT = pathlib.Path(os.environ.get('TOP_BUILDDIR', SOURCEROOT)).absolute() +NOTSET = object() logger = logging.getLogger(__name__) @@ -43,7 +44,12 @@ logger = logging.getLogger(__name__) class Database: have_directory = True - def __init__(self, server, suffix, backend): + def __init__(self, server, suffix, backend, *, + module=NOTSET): + if module is NOTSET: + module = (BUILDROOT/"servers"/"slapd"/ + f"back-{backend}"/f"back_{backend}") + self.server = server self.suffix = suffix self.rootdn = suffix @@ -56,6 +62,9 @@ class Database: if self.have_directory: self.directory = tempfile.TemporaryDirectory(dir=server.home, delete=False) + if module: + server.load_module(module) + conn = server.connect() conn.simple_bind_s("cn=config", server.secret) @@ -63,8 +72,7 @@ class Database: control = PostReadControl(True, []) _, _, _, ctrls = conn.add_ext_s( - f"olcDatabase={backend},cn=config", - list(self._entry().items()), + f"olcDatabase={backend},cn=config", list(self._entry().items()), serverctrls=[control]) dn = ctrls[0].dn From 33fc2478dde0c3ad56cbf4f3f44d8c95628989e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Kuzn=C3=ADk?= Date: Thu, 24 Oct 2024 16:08:26 +0100 Subject: [PATCH 4/5] ITS#9596 Request only DN for now --- tests/python/backends.py | 2 +- tests/python/overlays.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/python/backends.py b/tests/python/backends.py index a4b6ca3aa4..f812442293 100755 --- a/tests/python/backends.py +++ b/tests/python/backends.py @@ -69,7 +69,7 @@ class Database: conn.simple_bind_s("cn=config", server.secret) # We're just after the generated DN, no other attributes at the moment - control = PostReadControl(True, []) + control = PostReadControl(True, ["1.1"]) _, _, _, ctrls = conn.add_ext_s( f"olcDatabase={backend},cn=config", list(self._entry().items()), diff --git a/tests/python/overlays.py b/tests/python/overlays.py index 6d78d9e202..578529597a 100755 --- a/tests/python/overlays.py +++ b/tests/python/overlays.py @@ -51,7 +51,7 @@ class Overlay: server.load_module(overlay) # We're just after the generated DN, no other attributes at the moment - control = PostReadControl(True, []) + control = PostReadControl(True, ["1.1"]) _, _, _, ctrls = conn.add_ext_s( f"olcOverlay={overlay_name},{database.dn}", From f26d4cd101a40b0afed49d132774ffbff8724b58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Kuzn=C3=ADk?= Date: Mon, 28 Oct 2024 15:52:50 +0000 Subject: [PATCH 5/5] ITS#9596 Allow monitor to be loaded --- tests/python/backends.py | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/tests/python/backends.py b/tests/python/backends.py index f812442293..dffd261b07 100755 --- a/tests/python/backends.py +++ b/tests/python/backends.py @@ -45,14 +45,16 @@ class Database: have_directory = True def __init__(self, server, suffix, backend, *, - module=NOTSET): + rootdn=NOTSET, module=NOTSET): + if rootdn is NOTSET: + rootdn = suffix if module is NOTSET: module = (BUILDROOT/"servers"/"slapd"/ f"back-{backend}"/f"back_{backend}") self.server = server self.suffix = suffix - self.rootdn = suffix + self.rootdn = rootdn self.secret = secrets.token_urlsafe() self.overlays = [] @@ -83,9 +85,11 @@ class Database: entry = { "objectclass": [self.objectclass.encode()], "olcSuffix": [self.suffix.encode()], - "olcRootDN": [self.suffix.encode()], - "olcRootPW": [self.secret.encode()], } + if self.rootdn is not None: + entry["olcRootDN"] = [self.rootdn.encode()] + if self.rootdn.endswith(self.suffix): + entry["olcRootPW"] = [self.secret.encode()] if self.have_directory: entry["olcDbDirectory"] = [self.directory.name.encode()] return entry @@ -101,10 +105,9 @@ class MDB(Database): super().__init__(server, suffix, "mdb") def _entry(self): - entry = { + return super()._entry() | { "olcDbMaxSize": [str(self._size).encode()], } - return {**super()._entry(), **entry} class LDAP(Database): @@ -116,15 +119,24 @@ class LDAP(Database): super().__init__(server, suffix, "ldap") def _entry(self): - entry = { + return super()._entry() | { "olcDbURI": [" ".join(self.uris).encode()], } - return {**super()._entry(), **entry} + + +class Monitor(Database): + have_directory = False + objectclass = "olcMonitorConfig" + + def __init__(self, server): + super().__init__(server, "cn=monitor", "monitor", + rootdn="cn=config", module=None) backend_types = { "mdb": MDB, "ldap": LDAP, + "monitor": Monitor, }