URL: https://github.com/freeipa/freeipa/pull/2649
Author: tiran
 Title: #2649: Add more LDAP indices
Action: opened

PR body:
"""
## Add more LDAP indices

An index is used to optimize an LDAP operation. Without an index, 389-DS
has to perform a partial or even full table scan. A full database scan can
easily take 10 seconds or more in a large installation.

* automountMapKey: eq, pres (was: eq)
* autoMountMapName: eq
* ipaConfigString: eq
* ipaEnabledFlag: eq
* ipaKrbAuthzData: eq, sub
* ipServicePort: eq
* ipServiceProtocol: eq
* accessRuleType: eq
* hostCategory: eq

automountMapKey and autoMountMapName filters are used for automount.

Installation and service discovery (CA, KRA) use ipaConfigString to find
active services and CA renewal master.

SSSD filters with ipaEnabledFlag, accessRuleType, and hostCategory to
find and cache HBAC rules for each host.

The SSSD plugin for nssswitch service uses ipServicePort and
ipServiceProtocol.

ipaKrbAuthzData is used by ipa host-del. The framework performs a
'*arg*' query, therefore a sub index is required, too.

Fixes: pagure.io/freeipa/issue/7786
Fixes: pagure.io/freeipa/issue/7787
Fixes: pagure.io/freeipa/issue/7790
Fixes: pagure.io/freeipa/issue/7792


## LDAPUpdate: Batch index tasks

The LDAPUpdate framework now keeps record of all changed/added indices
and batches all changed attribute in a single index task. It makes
updates much faster when multiple indices are added or modified.
"""

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/2649/head:pr2649
git checkout pr2649
From 4a6c6c2b8a6fb9b9b141dd437dc10843f68980eb Mon Sep 17 00:00:00 2001
From: Christian Heimes <chei...@redhat.com>
Date: Wed, 5 Dec 2018 12:57:56 +0100
Subject: [PATCH 1/2] LDAPUpdate: Batch index tasks

The LDAPUpdate framework now keeps record of all changed/added indices
and batches all changed attribute in a single index task. It makes
updates much faster when multiple indices are added or modified.

Signed-off-by: Christian Heimes <chei...@redhat.com>
---
 ipaserver/install/ldapupdate.py | 47 ++++++++++++++++++++-------------
 1 file changed, 29 insertions(+), 18 deletions(-)

diff --git a/ipaserver/install/ldapupdate.py b/ipaserver/install/ldapupdate.py
index aff45bbede..0e69908b01 100644
--- a/ipaserver/install/ldapupdate.py
+++ b/ipaserver/install/ldapupdate.py
@@ -134,7 +134,14 @@ def safe_output(attr, values):
 
 
 class LDAPUpdate:
-    action_keywords = ["default", "add", "remove", "only", "onlyifexist", "deleteentry", "replace", "addifnew", "addifexist"]
+    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={},
                  online=True, ldapi=False):
@@ -515,8 +522,8 @@ def emit_plugin_update(update):
 
         return all_updates
 
-    def create_index_task(self, attribute):
-        """Create a task to update an index for an attribute"""
+    def create_index_task(self, *attributes):
+        """Create a task to update an index for attributes"""
 
         # Sleep a bit to ensure previous operations are complete
         time.sleep(5)
@@ -525,7 +532,7 @@ def create_index_task(self, attribute):
         # cn_uuid.time is in nanoseconds, but other users of LDAPUpdate expect
         # seconds in 'TIME' so scale the value down
         self.sub_dict['TIME'] = int(cn_uuid.time/1e9)
-        cn = "indextask_%s_%s_%s" % (attribute, cn_uuid.time, cn_uuid.clock_seq)
+        cn = "indextask_%s_%s" % (cn_uuid.time, cn_uuid.clock_seq)
         dn = DN(('cn', cn), ('cn', 'index'), ('cn', 'tasks'), ('cn', 'config'))
 
         e = self.conn.make_entry(
@@ -533,11 +540,13 @@ def create_index_task(self, attribute):
             objectClass=['top', 'extensibleObject'],
             cn=[cn],
             nsInstance=['userRoot'],
-            nsIndexAttribute=[attribute],
+            nsIndexAttribute=list(attributes),
         )
 
-        logger.debug("Creating task to index attribute: %s", attribute)
-        logger.debug("Task id: %s", dn)
+        logger.info(
+            "Creating task %s to index attributes: %s",
+            dn, ', '.join(attributes)
+        )
 
         self.conn.add_entry(e)
 
@@ -571,8 +580,8 @@ def monitor_index_task(self, dn):
                 time.sleep(1)
                 continue
 
-            if status.lower().find("finished") > -1:
-                logger.debug("Indexing finished")
+            if "finished" in status.lower():
+                logger.info("Indexing finished")
                 break
 
             logger.debug("Indexing in progress")
@@ -792,7 +801,7 @@ def _update_record(self, update):
         entry = self._apply_update_disposition(update.get('updates'), entry)
         if entry is None:
             # It might be None if it is just deleting an entry
-            return
+            return None, False
 
         self.print_entity(entry, "Final value after applying updates")
 
@@ -811,7 +820,7 @@ def _update_record(self, update):
                         # this may not be an error (e.g. entries in NIS container)
                         logger.error("Parent DN of %s may not exist, cannot "
                                      "create the entry", entry.dn)
-                        return
+                        return entry, False
                 added = True
                 self.modified = True
             except Exception as e:
@@ -846,12 +855,7 @@ def _update_record(self, update):
             if updated:
                 self.modified = True
 
-        if entry.dn.endswith(DN(('cn', 'index'), ('cn', 'userRoot'),
-                                ('cn', 'ldbm database'), ('cn', 'plugins'),
-                                ('cn', 'config'))) and (added or updated):
-            taskid = self.create_index_task(entry.single_value['cn'])
-            self.monitor_index_task(taskid)
-        return
+        return entry, added or updated
 
     def _delete_record(self, updates):
         """
@@ -903,13 +907,20 @@ def create_connection(self):
             raise RuntimeError("Offline updates are not supported.")
 
     def _run_updates(self, all_updates):
+        reindex_attributes = set()
         for update in all_updates:
             if 'deleteentry' in update:
                 self._delete_record(update)
             elif 'plugin' in update:
                 self._run_update_plugin(update['plugin'])
             else:
-                self._update_record(update)
+                entry, modified = self._update_record(update)
+                if modified and entry.dn.endswith(self.index_suffix):
+                    reindex_attributes.add(entry.single_value['cn'])
+
+        if reindex_attributes:
+            task_dn = self.create_index_task(*sorted(reindex_attributes))
+            self.monitor_index_task(task_dn)
 
     def update(self, files, ordered=True):
         """Execute the update. files is a list of the update files to use.

From 760db6af9082c8835a527bbde4c6861852c637d6 Mon Sep 17 00:00:00 2001
From: Christian Heimes <chei...@redhat.com>
Date: Wed, 5 Dec 2018 17:55:58 +0100
Subject: [PATCH 2/2] Add more LDAP indices

An index is used to optimize an LDAP operation. Without an index, 389-DS
has to perform a partial or even full table scan. A full database scan can
easily take 10 seconds or more in a large installation.

* automountMapKey: eq, pres (was: eq)
* autoMountMapName: eq
* ipaConfigString: eq
* ipaEnabledFlag: eq
* ipaKrbAuthzData: eq, sub
* ipServicePort: eq
* ipServiceProtocol: eq
* accessRuleType: eq
* hostCategory: eq

automountMapKey and autoMountMapName filters are used for automount.

Installation and service discovery (CA, KRA) use ipaConfigString to find
active services and CA renewal master.

SSSD filters with ipaEnabledFlag, accessRuleType, and hostCategory to
find and cache HBAC rules for each host.

The SSSD plugin for nssswitch service uses ipServicePort and
ipServiceProtocol.

ipaKrbAuthzData is used by ipa host-del. The framework performs a
'*arg*' query, therefore a sub index is required, too.

Fixes: https://pagure.io/freeipa/issue/7786
Fixes: https://pagure.io/freeipa/issue/7787
Fixes: https://pagure.io/freeipa/issue/7790
Fixes: https://pagure.io/freeipa/issue/7792
Signed-off-by: Christian Heimes <chei...@redhat.com>
---
 install/share/indices.ldif        | 66 +++++++++++++++++++++++++++++++
 install/updates/20-indices.update | 58 +++++++++++++++++++++++++++
 2 files changed, 124 insertions(+)

diff --git a/install/share/indices.ldif b/install/share/indices.ldif
index e91ef01ed7..0a1945e680 100644
--- a/install/share/indices.ldif
+++ b/install/share/indices.ldif
@@ -216,6 +216,40 @@ ObjectClass: top
 ObjectClass: nsIndex
 nsSystemIndex: false
 nsIndexType: eq
+nsIndexType: pres
+
+dn: cn=automountMapName,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config
+changetype: add
+cn: automountMapNam
+ObjectClass: top
+ObjectClass: nsIndex
+nsSystemIndex: false
+nsIndexType: eq
+
+dn: cn=ipaConfigString,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config
+changetype: add
+cn: ipaConfigString
+objectClass:top
+objectClass:nsIndex
+nsSystemIndex: false
+nsIndexType: eq
+
+dn: cn=ipaEnabledFlag,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config
+changetype: add
+cn: ipaEnabledFlag
+objectClass:top
+objectClass:nsIndex
+nsSystemIndex: false
+nsIndexType: eq
+
+dn: cn=ipaKrbAuthzData,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config
+changetype: add
+cn: ipaKrbAuthzData
+objectClass: top
+objectClass: nsIndex
+nsSystemIndex: false
+nsIndexType: eq
+nsIndexType: sub
 
 dn: cn=ipakrbprincipalalias,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config
 changetype: add
@@ -271,6 +305,22 @@ nsSystemIndex: false
 nsIndexType: eq
 nsIndexType: pres
 
+dn: cn=ipServicePort,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config
+changetype: add
+cn: ipServicePort
+objectClass:top
+objectClass:nsIndex
+nsSystemIndex: false
+nsIndexType: eq
+
+dn: cn=ipServiceProtocol,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config
+changetype: add
+cn: ipServiceProtocol
+objectClass:top
+objectClass:nsIndex
+nsSystemIndex: false
+nsIndexType: eq
+
 dn: cn=krbCanonicalName,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config
 changetype: add
 cn: krbCanonicalName
@@ -333,3 +383,19 @@ objectClass: nsindex
 nssystemindex: false
 nsindextype: eq
 nsindextype: sub
+
+dn: cn=accessRuleType,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config
+changetype: add
+cn: accessRuleType
+objectClass:top
+objectClass:nsIndex
+nsSystemIndex: false
+nsIndexType: eq
+
+dn: cn=hostCategory,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config
+changetype: add
+cn: hostCategory
+objectClass:top
+objectClass:nsIndex
+nsSystemIndex: false
+nsIndexType: eq
diff --git a/install/updates/20-indices.update b/install/updates/20-indices.update
index d1704adfc2..5cc4b7302a 100644
--- a/install/updates/20-indices.update
+++ b/install/updates/20-indices.update
@@ -151,6 +151,36 @@ default:ObjectClass: top
 default:ObjectClass: nsIndex
 default:nsSystemIndex: false
 default:nsIndexType: eq
+default:nsIndexType: pres
+
+dn: cn=automountMapName,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config
+default:cn: automountMapName
+default:ObjectClass: top
+default:ObjectClass: nsIndex
+default:nsSystemIndex: false
+default:nsIndexType: eq
+
+dn: cn=ipaConfigString,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config
+default: cn: ipaConfigString
+default: objectClass:top
+default: objectClass:nsIndex
+default: nsSystemIndex: false
+default: nsIndexType: eq
+
+dn: cn=ipaEnabledFlag,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config
+default: cn: ipaEnabledFlag
+default: objectClass:top
+default: objectClass:nsIndex
+default: nsSystemIndex: false
+default: nsIndexType: eq
+
+dn: cn=ipaKrbAuthzData,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config
+default: cn: ipaKrbAuthzData
+default: objectClass: top
+default: objectClass: nsIndex
+default: nsSystemIndex: false
+default: nsIndexType: eq
+default: nsIndexType: sub
 
 dn: cn=ipakrbprincipalalias,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config
 default:cn: ipakrbprincipalalias
@@ -243,6 +273,20 @@ default:nsSystemIndex: false
 only:nsIndexType: eq
 only:nsIndexType: pres
 
+dn: cn=ipServicePort,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config
+default: cn: ipServicePort
+default: objectClass:top
+default: objectClass:nsIndex
+default: nsSystemIndex: false
+default: nsIndexType: eq
+
+dn: cn=ipServiceProtocol,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config
+default: cn: ipServiceProtocol
+default: objectClass:top
+default: objectClass:nsIndex
+default: nsSystemIndex: false
+default: nsIndexType: eq
+
 dn: cn=krbPrincipalName,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config
 default:cn: krbPrincipalName
 default:ObjectClass: top
@@ -308,3 +352,17 @@ default: objectclass: nsindex
 default: nssystemindex: false
 default: nsindextype: eq
 default: nsindextype: sub
+
+dn: cn=accessRuleType,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config
+default: cn: accessRuleType
+default: objectClass:top
+default: objectClass:nsIndex
+default: nsSystemIndex: false
+default: nsIndexType: eq
+
+dn: cn=hostCategory,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config
+default: cn: hostCategory
+default: objectClass:top
+default: objectClass:nsIndex
+default: nsSystemIndex: false
+default: nsIndexType: eq
_______________________________________________
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://getfedora.org/code-of-conduct.html
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: 
https://lists.fedorahosted.org/archives/list/freeipa-devel@lists.fedorahosted.org

Reply via email to