From 4d4931abf0b77c431252389edb6f447b63c91d8c Mon Sep 17 00:00:00 2001 From: Alexander Bokovoy Date: Mon, 31 May 2021 12:53:55 +0300 Subject: [PATCH] ds: Support renaming of a replication plugin in 389-ds IPA topology plugin depends on the replication plugin but 389-ds cannot handle older alias querying in the plugin configuration with 'nsslapd-plugin-depends-on-named: ..' attribute See https://github.com/389ds/389-ds-base/issues/4786 for details Fixes: https://pagure.io/freeipa/issue/8799 Signed-off-by: Alexander Bokovoy --- .../ipa-version/version-conf.ldif | 2 +- .../topology/ipa-topology-conf.ldif | 2 +- install/updates/10-enable-betxn.update | 2 +- .../updates/20-enable_dirsrv_plugins.update | 4 ++-- install/updates/20-replication.update | 2 +- ipaserver/install/dsinstance.py | 8 ++++++- ipaserver/install/replication.py | 24 ++++++++++++++++++- ipaserver/install/upgradeinstance.py | 18 +++++++++++++- .../test_ipaserver/test_topology_plugin.py | 13 +++++++++- 9 files changed, 65 insertions(+), 10 deletions(-) diff --git a/daemons/ipa-slapi-plugins/ipa-version/version-conf.ldif b/daemons/ipa-slapi-plugins/ipa-version/version-conf.ldif index 11558834c..6000868e2 100644 --- a/daemons/ipa-slapi-plugins/ipa-version/version-conf.ldif +++ b/daemons/ipa-slapi-plugins/ipa-version/version-conf.ldif @@ -13,5 +13,5 @@ nsslapd-pluginversion: 1.0 nsslapd-pluginvendor: Red Hat, Inc. nsslapd-plugindescription: IPA Replication version plugin nsslapd-plugin-depends-on-type: database -nsslapd-plugin-depends-on-named: Multimaster Replication Plugin +nsslapd-plugin-depends-on-named: $REPLICATION_PLUGIN diff --git a/daemons/ipa-slapi-plugins/topology/ipa-topology-conf.ldif b/daemons/ipa-slapi-plugins/topology/ipa-topology-conf.ldif index 4b3c4ce99..effa38597 100644 --- a/daemons/ipa-slapi-plugins/topology/ipa-topology-conf.ldif +++ b/daemons/ipa-slapi-plugins/topology/ipa-topology-conf.ldif @@ -15,7 +15,7 @@ nsslapd-topo-plugin-shared-binddngroup: cn=replication managers,cn=sysaccounts,c nsslapd-topo-plugin-startup-delay: 20 nsslapd-pluginId: none nsslapd-plugin-depends-on-named: ldbm database -nsslapd-plugin-depends-on-named: Multimaster Replication Plugin +nsslapd-plugin-depends-on-named: $REPLICATION_PLUGIN nsslapd-pluginVersion: 1.0 nsslapd-pluginVendor: none nsslapd-pluginDescription: none diff --git a/install/updates/10-enable-betxn.update b/install/updates/10-enable-betxn.update index 88f584cb3..1f89341c7 100644 --- a/install/updates/10-enable-betxn.update +++ b/install/updates/10-enable-betxn.update @@ -18,7 +18,7 @@ only: nsslapd-pluginType: betxnpreoperation dn: cn=MemberOf Plugin,cn=plugins,cn=config only: nsslapd-pluginType: betxnpostoperation -dn: cn=Multimaster Replication Plugin,cn=plugins,cn=config +dn: cn=$REPLICATION_PLUGIN,cn=plugins,cn=config only: nsslapd-pluginbetxn: on dn: cn=PAM Pass Through Auth,cn=plugins,cn=config diff --git a/install/updates/20-enable_dirsrv_plugins.update b/install/updates/20-enable_dirsrv_plugins.update index dc046f41b..182a8334d 100644 --- a/install/updates/20-enable_dirsrv_plugins.update +++ b/install/updates/20-enable_dirsrv_plugins.update @@ -50,8 +50,8 @@ replace: nsslapd-pluginEnabled:off::on dn: cn=Managed Entries,cn=plugins,cn=config replace: nsslapd-pluginEnabled:off::on -# Multimaster Replication Plugin, plugins, config -dn: cn=Multimaster Replication Plugin,cn=plugins,cn=config +# Replication Plugin may be Multisupplier or Multimaster +dn: cn=$REPLICATION_PLUGIN,cn=plugins,cn=config replace: nsslapd-pluginEnabled:off::on # Roles Plugin, plugins, config diff --git a/install/updates/20-replication.update b/install/updates/20-replication.update index 34beebc10..287148ec8 100644 --- a/install/updates/20-replication.update +++ b/install/updates/20-replication.update @@ -58,7 +58,7 @@ default: nsslapd-topo-plugin-shared-binddngroup: cn=replication managers,cn=sysa default: nsslapd-topo-plugin-startup-delay: 20 default: nsslapd-pluginId: none default: nsslapd-plugin-depends-on-named: ldbm database -default: nsslapd-plugin-depends-on-named: Multimaster Replication Plugin +default: nsslapd-plugin-depends-on-named: $REPLICATION_PLUGIN default: nsslapd-pluginVersion: 1.0 default: nsslapd-pluginVendor: none default: nsslapd-pluginDescription: none diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py index 622d6a0f5..b0e012ab8 100644 --- a/ipaserver/install/dsinstance.py +++ b/ipaserver/install/dsinstance.py @@ -571,6 +571,12 @@ class DsInstance(service.Service): inst.setup_ldapi() inst.open() + def get_entry(dn, attrs): + return inst.getEntry(dn, attrlist=attrs) + + self.sub_dict['REPLICATION_PLUGIN'] = ( + replication.get_replication_plugin_name(get_entry)) + try: ipadomain = IpaDomain(inst, dn=self.suffix.ldap_text()) ipadomain.create(properties={ @@ -735,7 +741,7 @@ class DsInstance(service.Service): self._ldap_mod("pw-logging-conf.ldif") def __config_version_module(self): - self._ldap_mod("version-conf.ldif") + self._ldap_mod("version-conf.ldif", self.sub_dict) def __config_uuid_module(self): self._ldap_mod("uuid-conf.ldif") diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py index 5a3e5e565..8fb4fd414 100644 --- a/ipaserver/install/replication.py +++ b/ipaserver/install/replication.py @@ -232,6 +232,23 @@ def get_ds_version(conn): return vendor_version +def get_replication_plugin_name(dirsrv_get_entry): + # Support renaming of a replication plugin in 389-ds + # IPA topology plugin depends on the replication plugin but + # 389-ds cannot handle older alias querying in the plugin + # configuration with 'nsslapd-plugin-depends-on-named: ..' attribute + # + # dirsrv_get_entry: function (dn, attrs) -> str + # returns entry dictionary + try: + entry = dirsrv_get_entry( + 'cn=Multisupplier Replication Plugin,cn=plugins,cn=config', + ['cn']) + return str(entry['cn'], encoding='utf-8') + except Exception: + return 'Multimaster Replication Plugin' + + class ReplicationManager: """Manage replication agreements @@ -737,8 +754,13 @@ class ReplicationManager: mtent = self.get_mapping_tree_entry() dn = mtent.dn + def get_entry(dn, attrs): + return self.conn.get_entry(DN(dn), attrs) + + replication_plugin_name = get_replication_plugin_name(get_entry) + plgent = self.conn.get_entry( - DN(('cn', 'Multimaster Replication Plugin'), ('cn', 'plugins'), + DN(('cn', replication_plugin_name), ('cn', 'plugins'), ('cn', 'config')), ['nsslapd-pluginPath']) path = plgent.single_value.get('nsslapd-pluginPath') diff --git a/ipaserver/install/upgradeinstance.py b/ipaserver/install/upgradeinstance.py index a239dd035..581742d6f 100644 --- a/ipaserver/install/upgradeinstance.py +++ b/ipaserver/install/upgradeinstance.py @@ -40,6 +40,7 @@ logger = logging.getLogger(__name__) DSE = 'dse.ldif' COMPAT_DN = "cn=Schema Compatibility,cn=plugins,cn=config" +REPL_PLUGIN_DN_TEMPLATE = "cn=Multi%s Replication Plugin,cn=plugins,cn=config" class GetEntryFromLDIF(ldif.LDIFParser): @@ -97,6 +98,7 @@ class IPAUpgrade(service.Service): self.modified = False self.serverid = serverid self.schema_files = schema_files + self.sub_dict = dict() def __start(self): srv = services.service(self.service_name, api) @@ -170,6 +172,20 @@ class IPAUpgrade(service.Service): else: self.backup_state('nsslapd-global-backend-lock', global_lock) + # update self.sub_dict with the replication plugin name + # It may be different depending on 389-ds version + with open(self.filename, "r") as in_file: + parser = GetEntryFromLDIF(in_file, entries_dn=[]) + parser.parse() + + results = parser.get_results() + + dn = REPL_PLUGIN_DN_TEMPLATE % "supplier" + if dn not in results: + dn = REPL_PLUGIN_DN_TEMPLATE % "master" + + self.sub_dict['REPLICATION_PLUGIN'] = results[dn].get('cn') + with open(self.filename, "r") as in_file: parser = GetEntryFromLDIF(in_file, entries_dn=[COMPAT_DN]) parser.parse() @@ -284,7 +300,7 @@ class IPAUpgrade(service.Service): def __upgrade(self): try: - ld = ldapupdate.LDAPUpdate(api=self.api) + ld = ldapupdate.LDAPUpdate(api=self.api, sub_dict=self.sub_dict) if len(self.files) == 0: self.files = ld.get_all_files(ldapupdate.UPDATES_DIR) self.modified = (ld.update(self.files) or self.modified) diff --git a/ipatests/test_ipaserver/test_topology_plugin.py b/ipatests/test_ipaserver/test_topology_plugin.py index ca68a8905..be24ac5c1 100644 --- a/ipatests/test_ipaserver/test_topology_plugin.py +++ b/ipatests/test_ipaserver/test_topology_plugin.py @@ -10,6 +10,8 @@ from ipapython.dn import DN import pytest +REPL_PLUGIN_NAME_TEMPLATE = 'Multi%s Replication Plugin' + @pytest.mark.tier1 class TestTopologyPlugin: """ @@ -35,12 +37,13 @@ class TestTopologyPlugin: @pytest.mark.skipif(os.path.isfile(pwfile) is False, reason="You did not provide a .dmpw file with the DM password") def test_topologyplugin(self): + supplier = REPL_PLUGIN_NAME_TEMPLATE % 'supplier' pluginattrs = { u'nsslapd-pluginPath': [u'libtopology'], u'nsslapd-pluginVendor': [u'freeipa'], u'cn': [u'IPA Topology Configuration'], u'nsslapd-plugin-depends-on-named': - [u'Multimaster Replication Plugin', u'ldbm database'], + [supplier, u'ldbm database'], u'nsslapd-topo-plugin-shared-replica-root': [u'dc=example,dc=com'], u'nsslapd-pluginVersion': [u'1.0'], u'nsslapd-topo-plugin-shared-config-base': @@ -72,5 +75,13 @@ class TestTopologyPlugin: bind_pw=dm_password) entry = self.conn.get_entry(topoplugindn) assert(set(entry.keys()) == set(pluginattrs.keys())) + + # Handle different names for replication plugin + key = 'nsslapd-plugin-depends-on-named' + plugin_dependencies = entry[key] + if supplier not in plugin_dependencies: + mm = REPL_PLUGIN_NAME_TEMPLATE % 'master' + pluginattrs[key] = [mm, 'ldbm database'] + for i in checkvalues: assert(set(pluginattrs[i]) == set(entry[i])) -- 2.31.1