From 99a40cbbe95b629ccfd49cb3c809889731148779 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Sep 22 2020 13:21:00 +0000 Subject: Simplify LDAPUpdater - drop unused dm_password and ldapi arguments - remove online feature that was never implemented - allow passing of api object that is used to populate substitution dictionary - simplify substitution dictionary updates - remove unused instances vars Signed-off-by: Christian Heimes Reviewed-By: Rob Crittenden --- diff --git a/install/tools/ipa-compat-manage.in b/install/tools/ipa-compat-manage.in index f338a69..2805845 100644 --- a/install/tools/ipa-compat-manage.in +++ b/install/tools/ipa-compat-manage.in @@ -132,7 +132,7 @@ def main(): print("Enabling plugin") if entry is None: - ld = LDAPUpdate(dm_password=dirman_password, sub_dict={}) + ld = LDAPUpdate() if not ld.update(files): print("Updating Directory Server failed.") retval = 1 diff --git a/install/tools/ipa-nis-manage.in b/install/tools/ipa-nis-manage.in index dbac9cb..6b156ce 100644 --- a/install/tools/ipa-nis-manage.in +++ b/install/tools/ipa-nis-manage.in @@ -149,7 +149,7 @@ def main(): # could be turned off, handle both cases. if entry is None: print("Enabling plugin") - ld = LDAPUpdate(dm_password=dirman_password, sub_dict={}, ldapi=True) + ld = LDAPUpdate() if ld.update(files) != True: retval = 1 elif entry.get('nsslapd-pluginenabled', [''])[0].lower() == 'off': diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py index 4527b1d..9f13464 100644 --- a/ipaserver/install/cainstance.py +++ b/ipaserver/install/cainstance.py @@ -673,10 +673,6 @@ class CAInstance(DogtagInstance): self._ldap_update( [paths.CA_TOPOLOGY_ULDIF], basedir=None, - sub_dict={ - 'SUFFIX': api.env.basedn, - 'FQDN': self.fqdn, - } ) def __disable_nonce(self): @@ -1361,13 +1357,7 @@ class CAInstance(DogtagInstance): "Did not find any lightweight CAs; nothing to track") def __dogtag10_migration(self): - self._ldap_update( - ['50-dogtag10-migration.update'], - sub_dict={ - 'SUFFIX': api.env.basedn, - 'FQDN': self.fqdn, - } - ) + self._ldap_update(['50-dogtag10-migration.update']) def is_crlgen_enabled(self): """Check if the local CA instance is generating CRL diff --git a/ipaserver/install/ipa_ldap_updater.py b/ipaserver/install/ipa_ldap_updater.py index 4d90fa8..7a1d2c5 100644 --- a/ipaserver/install/ipa_ldap_updater.py +++ b/ipaserver/install/ipa_ldap_updater.py @@ -142,10 +142,7 @@ class LDAPUpdater_NonUpgrade(LDAPUpdater): options.schema_files, ldapi=True) or modified - ld = LDAPUpdate( - sub_dict={}, - ldapi=True) - + ld = LDAPUpdate() if not self.files: self.files = ld.get_all_files(UPDATES_DIR) diff --git a/ipaserver/install/ldapupdate.py b/ipaserver/install/ldapupdate.py index 9ccd9c7..87c74a0 100644 --- a/ipaserver/install/ldapupdate.py +++ b/ipaserver/install/ldapupdate.py @@ -29,8 +29,8 @@ import sys import uuid import time import os -import pwd import fnmatch +import warnings import six @@ -134,28 +134,33 @@ def safe_output(attr, values): return values +_sentinel = object() + + class LDAPUpdate: - action_keywords = [ + action_keywords = { "default", "add", "remove", "only", "onlyifexist", "deleteentry", "replace", "addifnew", "addifexist" - ] + } index_suffix = DN( ('cn', 'index'), ('cn', 'userRoot'), ('cn', 'ldbm database'), ('cn', 'plugins'), ('cn', 'config') ) - def __init__(self, dm_password=None, sub_dict=None, - online=True, ldapi=False): + def __init__(self, dm_password=_sentinel, sub_dict=None, + online=_sentinel, ldapi=_sentinel, api=api): ''' :parameters: dm_password - Directory Manager password + deprecated and no longer used sub_dict substitution dictionary online - Do an online LDAP update or use an experimental LDIF updater + deprecated and no longer used ldapi - Bind using ldapi. This assumes autobind is enabled. + deprecated and no longer used + api + bootstrapped API object (for configuration) Data Structure Example: ----------------------- @@ -260,82 +265,49 @@ class LDAPUpdate: update format. ''' + if any(arg is not _sentinel for arg in (dm_password, online, ldapi)): + warnings.warn( + "dm_password, online, and ldapi arguments are deprecated", + DeprecationWarning, + stacklevel=2 + ) self.sub_dict = sub_dict if sub_dict is not None else {} - self.dm_password = dm_password self.conn = None self.modified = False - self.online = online - self.ldapi = ldapi - self.pw_name = pwd.getpwuid(os.geteuid()).pw_name - self.realm = None - self.socket_name = ( - paths.SLAPD_INSTANCE_SOCKET_TEMPLATE % - api.env.realm.replace('.', '-') + self.ldapuri = ipaldap.realm_to_ldapi_uri(api.env.realm) + + default_sub = dict( + REALM=api.env.realm, + DOMAIN=api.env.domain, + SUFFIX=api.env.basedn, + ESCAPED_SUFFIX=str(api.env.basedn), + FQDN=api.env.host, + LIBARCH=paths.LIBARCH, + TIME=int(time.time()), + MIN_DOMAIN_LEVEL=str(constants.MIN_DOMAIN_LEVEL), + MAX_DOMAIN_LEVEL=str(constants.MAX_DOMAIN_LEVEL), + STRIP_ATTRS=" ".join(constants.REPL_AGMT_STRIP_ATTRS), + EXCLUDES="(objectclass=*) $ EXCLUDE %s" % ( + " ".join(constants.REPL_AGMT_EXCLUDES) + ), + TOTAL_EXCLUDES="(objectclass=*) $ EXCLUDE %s" % ( + " ".join(constants.REPL_AGMT_TOTAL_EXCLUDES) + ), + SELINUX_USERMAP_DEFAULT=platformconstants.SELINUX_USERMAP_DEFAULT, + SELINUX_USERMAP_ORDER=platformconstants.SELINUX_USERMAP_ORDER, + FIPS="#" if tasks.is_fips_enabled() else "", ) - suffix = None + for k, v in default_sub.items(): + self.sub_dict.setdefault(k, v) - if self.sub_dict.get("REALM"): - self.realm = self.sub_dict["REALM"] - else: - self.realm = api.env.realm - suffix = ipautil.realm_to_suffix(self.realm) if self.realm else None - - self.ldapuri = ipaldap.realm_to_ldapi_uri(self.realm) - if suffix is not None: - assert isinstance(suffix, DN) - - fqdn = installutils.get_fqdn() - if fqdn is None: - raise RuntimeError("Unable to determine hostname") - - if not self.sub_dict.get("REALM") and self.realm is not None: - self.sub_dict["REALM"] = self.realm - if not self.sub_dict.get("FQDN"): - self.sub_dict["FQDN"] = fqdn - if not self.sub_dict.get("DOMAIN"): - self.sub_dict["DOMAIN"] = api.env.domain - if not self.sub_dict.get("SUFFIX") and suffix is not None: - self.sub_dict["SUFFIX"] = suffix - if not self.sub_dict.get("ESCAPED_SUFFIX"): - self.sub_dict["ESCAPED_SUFFIX"] = str(suffix) - if not self.sub_dict.get("LIBARCH"): - self.sub_dict["LIBARCH"] = paths.LIBARCH - if not self.sub_dict.get("TIME"): - self.sub_dict["TIME"] = int(time.time()) - if not self.sub_dict.get("MIN_DOMAIN_LEVEL"): - self.sub_dict["MIN_DOMAIN_LEVEL"] = str(constants.MIN_DOMAIN_LEVEL) - if not self.sub_dict.get("MAX_DOMAIN_LEVEL"): - self.sub_dict["MAX_DOMAIN_LEVEL"] = str(constants.MAX_DOMAIN_LEVEL) - if not self.sub_dict.get("STRIP_ATTRS"): - self.sub_dict["STRIP_ATTRS"] = "%s" % ( - " ".join(constants.REPL_AGMT_STRIP_ATTRS),) - if not self.sub_dict.get("EXCLUDES"): - self.sub_dict["EXCLUDES"] = "(objectclass=*) $ EXCLUDE %s" % ( - " ".join(constants.REPL_AGMT_EXCLUDES),) - if not self.sub_dict.get("TOTAL_EXCLUDES"): - self.sub_dict["TOTAL_EXCLUDES"] = "(objectclass=*) $ EXCLUDE " + \ - " ".join(constants.REPL_AGMT_TOTAL_EXCLUDES) - if not self.sub_dict.get("SELINUX_USERMAP_DEFAULT"): - self.sub_dict["SELINUX_USERMAP_DEFAULT"] = \ - platformconstants.SELINUX_USERMAP_DEFAULT - if not self.sub_dict.get("SELINUX_USERMAP_ORDER"): - self.sub_dict["SELINUX_USERMAP_ORDER"] = \ - platformconstants.SELINUX_USERMAP_ORDER - if "FIPS" not in self.sub_dict: - self.sub_dict["FIPS"] = '#' if tasks.is_fips_enabled() else '' self.api = create_api(mode=None) - self.api.bootstrap(in_server=True, - context='updates', - confdir=paths.ETC_IPA, - ldap_uri=self.ldapuri) + self.api.bootstrap( + in_server=True, + context='updates', + confdir=paths.ETC_IPA, + ldap_uri=self.ldapuri + ) self.api.finalize() - if online: - # Try out the connection/password - # (This will raise if the server is not available) - self.create_connection() - self.close_connection() - else: - raise RuntimeError("Offline updates are not supported.") def _template_str(self, s): try: @@ -913,13 +885,11 @@ class LDAPUpdate: self.create_connection() def create_connection(self): - if self.online: + if self.conn is None: self.api.Backend.ldap2.connect( time_limit=UPDATE_SEARCH_TIME_LIMIT, size_limit=0) self.conn = self.api.Backend.ldap2 - else: - raise RuntimeError("Offline updates are not supported.") def _run_updates(self, all_updates): index_attributes = set() diff --git a/ipaserver/install/plugins/update_ca_topology.py b/ipaserver/install/plugins/update_ca_topology.py index 2183857..38187ef 100644 --- a/ipaserver/install/plugins/update_ca_topology.py +++ b/ipaserver/install/plugins/update_ca_topology.py @@ -32,10 +32,7 @@ class update_ca_topology(Updater): logger.debug("CA is not configured on this host") return False, [] - ld = ldapupdate.LDAPUpdate(ldapi=True, sub_dict={ - 'SUFFIX': self.api.env.basedn, - 'FQDN': self.api.env.host, - }) + ld = ldapupdate.LDAPUpdate(api=self.api) ld.update([paths.CA_TOPOLOGY_ULDIF]) diff --git a/ipaserver/install/plugins/update_nis.py b/ipaserver/install/plugins/update_nis.py index ba5b5cc..c02eb5f 100644 --- a/ipaserver/install/plugins/update_nis.py +++ b/ipaserver/install/plugins/update_nis.py @@ -67,7 +67,7 @@ class update_nis_configuration(Updater): True) # bug is effective run update to recreate missing maps - ld = LDAPUpdate(sub_dict={}, ldapi=True) + ld = LDAPUpdate(api=self.api) ld.update([paths.NIS_ULDIF]) def execute(self, **options): @@ -86,7 +86,7 @@ class update_nis_configuration(Updater): self.__recover_from_missing_maps(ldap) logger.debug("Executing NIS Server update") - ld = LDAPUpdate(sub_dict={}, ldapi=True) + ld = LDAPUpdate(api=self.api) ld.update([paths.NIS_UPDATE_ULDIF]) return False, () diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py index 52811d2..db00a64 100644 --- a/ipaserver/install/service.py +++ b/ipaserver/install/service.py @@ -313,7 +313,6 @@ class Service: self.keytab_user = service_user self.dm_password = None # silence pylint self.promote = False - self.sub_dict = None @property def principal(self): @@ -325,22 +324,20 @@ class Service: kerberos.Principal( (self.service_prefix, self.fqdn), realm=self.realm)) - def _ldap_update( - self, filenames, *, basedir=paths.UPDATES_DIR, sub_dict=None - ): + def _ldap_update(self, filenames, *, basedir=paths.UPDATES_DIR): """Apply update ldif files + Note: Additional substitution must be added to LDAPUpdate() to ensure + that ipa-ldap-updater is able to handle all update files as well. + :param filenames: list of file names :param basedir: base directory for files (default: UPDATES_DIR) - :param sub_dict: substitution dict (defaults to self.sub_dict) :return: modified state """ assert isinstance(filenames, (list, tuple)) - if sub_dict is None: - sub_dict = self.sub_dict if basedir is not None: filenames = [os.path.join(basedir, fname) for fname in filenames] - ld = LDAPUpdate(sub_dict=sub_dict) + ld = LDAPUpdate(api=self.api) # assume that caller supplies files in correct order return ld.update(filenames, ordered=False) diff --git a/ipaserver/install/upgradeinstance.py b/ipaserver/install/upgradeinstance.py index 35041a9..f2455ff 100644 --- a/ipaserver/install/upgradeinstance.py +++ b/ipaserver/install/upgradeinstance.py @@ -269,7 +269,7 @@ class IPAUpgrade(service.Service): def __upgrade(self): try: - ld = ldapupdate.LDAPUpdate(dm_password='', ldapi=True) + ld = ldapupdate.LDAPUpdate(api=self.api) 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_install/test_updates.py b/ipatests/test_install/test_updates.py index 1c9ba90..125be52 100644 --- a/ipatests/test_install/test_updates.py +++ b/ipatests/test_install/test_updates.py @@ -63,7 +63,7 @@ class TestUpdate: self.dm_password = fp.read().rstrip() else: pytest.skip("No directory manager password") - self.updater = LDAPUpdate(dm_password=self.dm_password, sub_dict={}) + self.updater = LDAPUpdate() self.ld = ipaldap.LDAPClient.from_hostname_secure(fqdn) self.ld.simple_bind(bind_dn=ipaldap.DIRMAN_DN, bind_password=self.dm_password)