URL: https://github.com/freeipa/freeipa/pull/5752 Author: tiran Title: #5752: Fix update_dna_shared_config to wait for both entries Action: opened
PR body: """ update_dna_shared_config plugin now waits for presence of both ``dnaHostname=fqdn+dnaPortNum=0`` and ``dnaHostname=fqdn+dnaPortNum=389`` entries before it updates the entries. The commit also refactors the code of update_dna_shared_config for subordinate id support. Fixes: https://pagure.io/freeipa/issue/8831 Signed-off-by: Christian Heimes <chei...@redhat.com> """ To pull the PR as Git branch: git remote add ghfreeipa https://github.com/freeipa/freeipa git fetch ghfreeipa pull/5752/head:pr5752 git checkout pr5752
From 0c31776b1ea4e3725e46bce1e3d9572da02cb766 Mon Sep 17 00:00:00 2001 From: Christian Heimes <chei...@redhat.com> Date: Thu, 6 May 2021 10:08:43 +0200 Subject: [PATCH] Fix update_dna_shared_config to wait for both entries update_dna_shared_config plugin now waits for presence of both ``dnaHostname=fqdn+dnaPortNum=0`` and ``dnaHostname=fqdn+dnaPortNum=389`` entries before it updates the entries. The commit also refactors the code of update_dna_shared_config for subordinate id support. Fixes: https://pagure.io/freeipa/issue/8831 Signed-off-by: Christian Heimes <chei...@redhat.com> --- .../plugins/update_dna_shared_config.py | 146 ++++++++++-------- 1 file changed, 84 insertions(+), 62 deletions(-) diff --git a/ipaserver/install/plugins/update_dna_shared_config.py b/ipaserver/install/plugins/update_dna_shared_config.py index 6cb47def821..70e854303d6 100644 --- a/ipaserver/install/plugins/update_dna_shared_config.py +++ b/ipaserver/install/plugins/update_dna_shared_config.py @@ -15,73 +15,95 @@ register = Registry() - @register() class update_dna_shared_config(Updater): - def execute(self, **options): - method = options.get('method', "SASL/GSSAPI") - protocol = options.get('protocol', "LDAP") + dna_plugin_names = ('posix IDs',) - dna_bind_method = "dnaRemoteBindMethod" - dna_conn_protocol = "dnaRemoteConnProtocol" - dna_plugin = DN(('cn', 'Distributed Numeric Assignment Plugin'), - ('cn', 'plugins'), - ('cn', 'config')) - dna_config_base = DN(('cn', 'posix IDs'), dna_plugin) + dna_plugin_dn = DN( + ('cn', 'Distributed Numeric Assignment Plugin'), + ('cn', 'plugins'), + ('cn', 'config') + ) - conn = self.api.Backend.ldap2 + def is_dna_enabled(self): + """Check the plugin is enabled - # Check the plugin is enabled else it is useless to update - # the shared entry + Else it is useless to update the shared entry + """ try: - entry = conn.get_entry(dna_plugin) - if entry.single_value.get('nsslapd-pluginenabled') == 'off': - return False, () + entry = self.api.Backend.ldap2.get_entry(self.dna_plugin_dn) + enabled = entry.single_value.get('nsslapd-pluginenabled') + if enabled.lower() == 'off': + return False + else: + return True except errors.NotFound: logger.error("Could not find DNA plugin entry: %s", - dna_config_base) - return False, () + self.dna_plugin_dn) + return False + def get_shared_cfg(self, plugin_name): + dna_config_base = DN(('cn', plugin_name), self.dna_plugin_dn) try: - entry = conn.get_entry(dna_config_base) + entry = self.api.Backend.ldap2.get_entry(dna_config_base) except errors.NotFound: logger.error("Could not find DNA config entry: %s", dna_config_base) return False, () + else: + logger.debug('Found DNA config %s', dna_config_base) sharedcfgdn = entry.single_value.get("dnaSharedCfgDN") if sharedcfgdn is not None: sharedcfgdn = DN(sharedcfgdn) + logger.debug("dnaSharedCfgDN: %s", sharedcfgdn) + return sharedcfgdn else: logger.error( "Could not find DNA shared config DN in entry: %s", dna_config_base) - return False, () + return None + + def update_shared_cfg(self, sharedcfgdn, **options): + """Update the shared config entry related to that host + + If the shared config entry already exists (like upgrade) + the update occurs immediately without sleep. + + If the shared config entry does not exist (fresh install) + DS server waits for 30s after its startup to create it. + Startup likely occurred few sec before this function is + called so this loop will wait for 30s max. + + In case the server is not able to create the entry + The loop gives a grace period of 60s before logging + the failure to update the shared config entry and return + """ + + method = options.get('method', "SASL/GSSAPI") + protocol = options.get('protocol', "LDAP") + dna_bind_method = "dnaRemoteBindMethod" + dna_conn_protocol = "dnaRemoteConnProtocol" - # - # Update the shared config entry related to that host - # - # If the shared config entry already exists (like upgrade) - # the update occurs immediately without sleep. - # - # If the shared config entry does not exist (fresh install) - # DS server waits for 30s after its startup to create it. - # Startup likely occurred few sec before this function is - # called so this loop will wait for 30s max. - # - # In case the server is not able to create the entry - # The loop gives a grace period of 60s before logging - # the failure to update the shared config entry and return - # max_wait = 30 + + conn = self.api.Backend.ldap2 fqdn = self.api.env.host + for _i in range(0, max_wait + 1): try: entries = conn.get_entries( sharedcfgdn, scope=ldap.SCOPE_ONELEVEL, filter='dnaHostname=%s' % fqdn ) - break + # There must be two entries: + # - dnaHostname=fqdn+dnaPortNum=0 + # - dnaHostname=fqdn+dnaPortNum=389 + if len(entries) >= 2: + break + + logger.debug("Got only one entry. Retry again in 2 sec.") + time.sleep(2) except errors.NotFound: logger.debug( "Unable to find DNA shared config entry for " @@ -94,35 +116,35 @@ def execute(self, **options): "Could not get dnaHostname entries in %s seconds", max_wait * 2 ) - return False, () - - # If there are several entries, all of them will be updated - # just log a debug msg. This is likely the result of #5510 - if len(entries) != 1: - logger.debug( - "%d entries dnaHostname=%s under %s. One expected", - len(entries), fqdn, sharedcfgdn - ) + return False # time to set the bind method and the protocol in the # shared config entries for entry in entries: - update = False - if entry.single_value.get(dna_bind_method) != method: - entry[dna_bind_method] = method - update = True - - if entry.single_value.get(dna_conn_protocol) != protocol: - entry[dna_conn_protocol] = protocol - update = True - - if update: - try: - conn.update_entry(entry) - except Exception as e: - logger.error( - "Failed to set SASL/GSSAPI bind method/protocol " - "in entry %s: %s", entry, e - ) + entry[dna_bind_method] = method + entry[dna_conn_protocol] = protocol + try: + conn.update_entry(entry) + except errors.EmptyModlist: + logger.debug("Entry %s is already updated", entry.dn) + except Exception as e: + logger.error( + "Failed to set SASL/GSSAPI bind method/protocol " + "in entry %s: %s", entry, e + ) + else: + logger.debug("Updated entry %s", entry.dn) + + return True + + def execute(self, **options): + if not self.is_dna_enabled(): + return False, () + + for plugin_name in self.dna_plugin_names: + sharedcfgdn = self.get_shared_cfg(plugin_name) + if sharedcfgdn is not None: + self.update_shared_cfg(sharedcfgdn, **options) + # no restart, no update return False, ()
_______________________________________________ FreeIPA-devel mailing list -- freeipa-devel@lists.fedorahosted.org To unsubscribe send an email to freeipa-devel-le...@lists.fedorahosted.org Fedora Code of Conduct: https://docs.fedoraproject.org/en-US/project/code-of-conduct/ List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines List Archives: https://lists.fedorahosted.org/archives/list/freeipa-devel@lists.fedorahosted.org Do not reply to spam on the list, report it: https://pagure.io/fedora-infrastructure