URL: https://github.com/freeipa/freeipa/pull/5182
Author: tiran
 Title: #5182: Speed up cainstance.migrate_profiles_to_ldap
Action: opened

PR body:
"""
The ra_certprofile API is slow. It takes ~200ms to migrate and enable a
profile even when the profile already available. The migration step
slows down the installer and upgrader by about 12 to 15 seconds.

Skip all profiles that have been imported by Dogtag already.

Related: https://pagure.io/freeipa/issue/8522
Related: https://pagure.io/freeipa/issue/8521
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/5182/head:pr5182
git checkout pr5182
From bf64e0a7c01dd02ce3096e9dab43a2b80c0cc69d Mon Sep 17 00:00:00 2001
From: Christian Heimes <chei...@redhat.com>
Date: Thu, 8 Oct 2020 14:25:21 +0200
Subject: [PATCH] Speed up cainstance.migrate_profiles_to_ldap

The ra_certprofile API is slow. It takes ~200ms to migrate and enable a
profile even when the profile already available. The migration step
slows down the installer and upgrader by about 12 to 15 seconds.

Skip all profiles that have been imported by Dogtag already.

Related: https://pagure.io/freeipa/issue/8522
Related: https://pagure.io/freeipa/issue/8521
Signed-off-by: Christian Heimes <chei...@redhat.com>
---
 ipaserver/install/cainstance.py | 45 +++++++++++++++++++++++++++++++--
 1 file changed, 43 insertions(+), 2 deletions(-)

diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index 79d2a14769..a8edd14099 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -23,6 +23,7 @@
 
 import base64
 import binascii
+import enum
 import logging
 
 import dbus
@@ -73,6 +74,8 @@
 
 ACME_AGENT_GROUP = 'ACME Agents'
 
+PROFILES_DN = DN(('ou', 'certificateProfiles'), ('ou', 'ca'), ('o', 'ipaca'))
+
 
 def check_ports():
     """Check that dogtag ports (8080, 8443) are available.
@@ -1713,7 +1716,7 @@ def update_ca_renewal_entry(conn, nickname, cert):
 
 def ensure_ldap_profiles_container():
     ensure_entry(
-        DN(('ou', 'certificateProfiles'), ('ou', 'ca'), ('o', 'ipaca')),
+        PROFILES_DN,
         objectclass=['top', 'organizationalUnit'],
         ou=['certificateProfiles'],
     )
@@ -1898,7 +1901,6 @@ def import_included_profiles():
             api.env.container_certprofile, api.env.basedn)
         try:
             conn.get_entry(dn)
-            continue  # the profile is present
         except errors.NotFound:
             # profile not found; add it
             entry = conn.make_entry(
@@ -1914,6 +1916,10 @@ def import_included_profiles():
             profile_data = __get_profile_config(profile_id)
             _create_dogtag_profile(profile_id, profile_data, overwrite=True)
             logger.debug("Imported profile '%s'", profile_id)
+        else:
+            logger.info(
+                "Profile '%s' is already in LDAP; skipping", profile_id
+            )
 
     api.Backend.ra_certprofile.override_port = None
     conn.disconnect()
@@ -1982,6 +1988,16 @@ def migrate_profiles_to_ldap():
     profile_ids = match.group(1).split(',')
 
     for profile_id in profile_ids:
+        state = _check_ldap_profile_state(profile_id)
+        if state in (ProfileState.ENABLED, ProfileState.DISABLED):
+            logger.info(
+                "Profile '%s' is already in LDAP and %s; skipping",
+                profile_id, state.value
+            )
+            continue
+        else:
+            logger.info("Migrating profile '%s'", profile_id)
+
         match = re.search(
             r'^profile\.{}\.config=(\S*)'.format(profile_id),
             cs_cfg, re.MULTILINE
@@ -2016,6 +2032,31 @@ def migrate_profiles_to_ldap():
     api.Backend.ra_certprofile.override_port = None
 
 
+class ProfileState(enum.Enum):
+    MISSING = "missing"
+    ENABLED = "enabled"
+    DISABLED = "disabled"
+
+
+def _check_ldap_profile_state(profile_id):
+    """Check if LDAP profile is loaded and enabled
+
+    The function directly access LDAP for performance reasons. It's much
+    faster than Dogtag's REST API and it's easier to check profiles for all
+    subsystems.
+    """
+    profile_dn = DN(("cn", profile_id), PROFILES_DN)
+    try:
+        entry = api.Backend.ldap2.get_entry(profile_dn)
+    except errors.NotFound:
+        return ProfileState.MISSING
+    cfg = entry.single_value["certProfileConfig"]
+    for line in cfg.split("\n"):
+        if line.lower() == "enable=true":
+            return ProfileState.ENABLED
+    return ProfileState.DISABLED
+
+
 def _create_dogtag_profile(profile_id, profile_data, overwrite):
     with api.Backend.ra_certprofile as profile_api:
         # import the profile
_______________________________________________
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

Reply via email to