[Freeipa-devel] [PATCH] 0020..0022 pki-related upgrade fixes

Fraser Tweedale ftweedal at redhat.com
Mon Jun 29 14:03:13 UTC 2015


On Thu, Jun 25, 2015 at 11:23:01AM +0200, Martin Basti wrote:
> On 19/06/15 09:28, Fraser Tweedale wrote:
> >The attached patches fix upgrade issues when pki is also updated
> >from pre 10.2.4.
> >
> >pki dependency is bumped to 10.2.5 - the official builds should be
> >done Friday (US time) but it is available from my copr[1].  If
> >someone wants to add to official freeipa COPR in meantime the SRPM
> >is here[2].
> >
> >[1] https://copr.fedoraproject.org/coprs/ftweedal/freeipa/
> >[2] https://ftweedal.fedorapeople.org/pki-core-10.2.5-0.2.fc21.src.rpm
> >
> >Thanks,
> >Fraser
> >
> >
> Thank you.
> 
> 1)
> I cannot apply patches.
> 
Rebased patches attached.

> 2)
> IMO patch 0020 was fixed with my patch 266
> 
It seems we are hitting another case of LDAP disconnection during
upgrade; without 0020 the upgrade fails.  There might be a better
way so let me know if you have ideas.

> 3)
> This print should not be there
> +
> +    print cs_cfg
> +    for profile_id in profile_ids:
> 
Thakns; removed.

> 4)
> This is unused variable,  it is defined later
> +   cs_cfg = None
> 
Thanks; removed.

> 5)
> Can you add there log.error or log.debug instead of pass please?
> +        # enable the profile
> +        try:
> +            profile_api.enable_profile(profile_id)
> +        except errors.RemoteRetrieveError:
> +            pass
> 
You've got it.  Also did this a few lines up where the profile is
disabled.

> I will test it later.
> 
> -- 
> Martin Basti
> 
Thank you,
Fraser
-------------- next part --------------
From e2ee2584a683c7a25a90df9bd5d70cabfc448a21 Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftweedal at redhat.com>
Date: Fri, 19 Jun 2015 01:37:26 -0400
Subject: [PATCH 20/22] Upgrade: disconnect ldap2 after adding CA DNS records

Non-disconnection of ldap2 backend in 'add_ca_dns_records' seems to
be causing problems with later uses.  Avoid the problem by
disconnecting it before returning.
---
 ipaserver/install/server/upgrade.py | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
index 784a03b195ab99c865935b6e51cc86a3b81842ee..b9e809f314bfb83eafe26f92f359a0539b98c2f0 100644
--- a/ipaserver/install/server/upgrade.py
+++ b/ipaserver/install/server/upgrade.py
@@ -1038,6 +1038,7 @@ def add_ca_dns_records():
     if not ret['result']:
         root_logger.info('DNS is not configured')
         sysupgrade.set_upgrade_state('dns', 'ipa_ca_records', True)
+        api.Backend.ldap2.disconnect()
         return
 
     bind = bindinstance.BindInstance()
@@ -1050,6 +1051,7 @@ def add_ca_dns_records():
                                 ca_configured=None)
 
     sysupgrade.set_upgrade_state('dns', 'ipa_ca_records', True)
+    api.Backend.ldap2.disconnect()
 
 
 def find_subject_base():
-- 
2.1.0

-------------- next part --------------
From 8ec6bca25e71bd41bd422a9010feddc14d5ea77a Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <frase at frase.id.au>
Date: Tue, 16 Jun 2015 07:40:36 -0400
Subject: [PATCH 21/22] Upgrade CA schema during upgrade

New schema (for LDAP-based profiles) was introduced in Dogtag, but
Dogtag does not yet have a reliable method for upgrading its schema.
Use FreeIPA's schema update machinery to add the new attributeTypes
and objectClasses defined by Dogtag.

Also update the pki dependencies to 10.2.5, which provides the
schema update file.
---
 freeipa.spec.in                     |  6 +++---
 ipaserver/install/server/upgrade.py | 26 ++++++++++++++++++++++++++
 2 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/freeipa.spec.in b/freeipa.spec.in
index 4f08db9f693318c6f4bfaf5e634ccffa78a4a28c..de250d8843506acd6109525c0630132fe60e2268 100644
--- a/freeipa.spec.in
+++ b/freeipa.spec.in
@@ -96,7 +96,7 @@ BuildRequires:  python-backports-ssl_match_hostname
 BuildRequires:  softhsm-devel >= 2.0.0rc1-1
 BuildRequires:  openssl-devel
 BuildRequires:  p11-kit-devel
-BuildRequires:  pki-base >= 10.2.4-1
+BuildRequires:  pki-base >= 10.2.5
 BuildRequires:  python-pytest-multihost >= 0.5
 BuildRequires:  python-pytest-sourceorder
 BuildRequires:  python-kdcproxy >= 0.3
@@ -141,8 +141,8 @@ Requires(post): systemd-units
 Requires: selinux-policy >= %{selinux_policy_version}
 Requires(post): selinux-policy-base
 Requires: slapi-nis >= 0.54.2-1
-Requires: pki-ca >= 10.2.4-1
-Requires: pki-kra >= 10.2.4-1
+Requires: pki-ca >= 10.2.5
+Requires: pki-kra >= 10.2.5
 Requires(preun): python systemd-units
 Requires(postun): python systemd-units
 Requires: python-dns >= 1.11.1
diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
index b9e809f314bfb83eafe26f92f359a0539b98c2f0..0d24e03f96ebc465df90dede1ff44cd609ea7592 100644
--- a/ipaserver/install/server/upgrade.py
+++ b/ipaserver/install/server/upgrade.py
@@ -1256,6 +1256,31 @@ def update_mod_nss_protocol(http):
     sysupgrade.set_upgrade_state('nss.conf', 'protocol_updated_tls12', True)
 
 
+def ca_upgrade_schema(ca):
+    root_logger.info('[Upgrading CA schema]')
+    if not ca.is_configured():
+        root_logger.info('CA is not configured')
+        return False
+
+    realm = krbV.default_context().default_realm
+    upgrade = IPAUpgrade(realm,
+        schema_files=['/usr/share/pki/server/conf/schema-certProfile.ldif'])
+    try:
+        upgrade.create_instance()
+    except BadSyntax:
+        raise RuntimeError(
+            'Bad syntax detected in CA schema file(s).', 1)
+    except RuntimeError:
+        raise RuntimeError('CA schema upgrade failed.', 1)
+    else:
+        if upgrade.modified:
+            root_logger.info('CA schema update complete')
+            return True
+        else:
+            root_logger.info('CA schema update complete (no changes)')
+            return False
+
+
 def add_default_caacl(ca):
     root_logger.info('[Add default CA ACL]')
 
@@ -1448,6 +1473,7 @@ def upgrade_configuration():
 
     ca_restart = any([
         ca_restart,
+        ca_upgrade_schema(ca),
         upgrade_ca_audit_cert_validity(ca),
         certificate_renewal_update(ca),
         ca_enable_pkix(ca),
-- 
2.1.0

-------------- next part --------------
From 2b2f21575986f521db3e4b9b8ad2439ddab6034a Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftweedal at redhat.com>
Date: Tue, 16 Jun 2015 07:38:06 -0400
Subject: [PATCH 22/22] Migrate CA profiles after enabling LDAPProfileSubsystem

After enabling LDAPProfileSubsystem in Dogtag, migrate the
file-based profiles into the LDAP database.
---
 ipaserver/install/cainstance.py     | 136 +++++++++++++++++++++++++++++-------
 ipaserver/install/server/upgrade.py |   7 +-
 2 files changed, 113 insertions(+), 30 deletions(-)

diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index 563a198ab472a58cc6fbeeceb7731486ce7ca6b5..884d27a9115bcac6a50d147bfd1f73a0f1d3b72d 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -1639,6 +1639,29 @@ def update_people_entry(dercert):
 
     return True
 
+def ensure_ldap_profiles_container():
+    server_id = installutils.realm_to_serverid(api.env.realm)
+    dogtag_uri = 'ldapi://%%2fvar%%2frun%%2fslapd-%s.socket' % server_id
+
+    conn = ldap2.ldap2(shared_instance=False, ldap_uri=dogtag_uri)
+    if not conn.isconnected():
+        conn.connect(autobind=True)
+
+    dn = DN(('ou', 'certificateProfiles'), ('ou', 'ca'), ('o', 'ipaca'))
+    try:
+        conn.get_entry(dn)
+    except errors.NotFound:
+        # entry doesn't exist; add it
+        entry = conn.make_entry(
+            dn,
+            objectclass=['top', 'organizationalUnit'],
+            ou=['certificateProfiles'],
+        )
+        conn.add_entry(entry)
+
+    conn.disconnect()
+
+
 def configure_profiles_acl():
     server_id = installutils.realm_to_serverid(api.env.realm)
     dogtag_uri = 'ldapi://%%2fvar%%2frun%%2fslapd-%s.socket' % server_id
@@ -1677,6 +1700,9 @@ def import_included_profiles():
     if not conn.isconnected():
         conn.connect(autobind=True)
 
+    api.Backend.ra_certprofile._read_password()
+    api.Backend.ra_certprofile.override_port = 8443
+
     for (profile_id, desc, store_issued) in dogtag.INCLUDED_PROFILES:
         dn = DN(('cn', profile_id),
             api.env.container_certprofile, api.env.basedn)
@@ -1685,9 +1711,6 @@ def import_included_profiles():
             continue  # the profile is present
         except errors.NotFound:
             # profile not found; add it
-            profile_data = ipautil.template_file(
-                '/usr/share/ipa/profiles/{}.cfg'.format(profile_id), sub_dict)
-
             entry = conn.make_entry(
                 dn,
                 objectclass=['ipacertprofile'],
@@ -1696,34 +1719,93 @@ def import_included_profiles():
                 ipacertprofilestoreissued=['TRUE' if store_issued else 'FALSE'],
             )
             conn.add_entry(entry)
-            api.Backend.ra_certprofile._read_password()
-            api.Backend.ra_certprofile.override_port = 8443
-            with api.Backend.ra_certprofile as profile_api:
-                # import the profile
-                try:
-                    profile_api.create_profile(profile_data)
-                except errors.RemoteRetrieveError:
-                    # conflicting profile; replace it if we are
-                    # installing IPA, but keep it for upgrades
-                    if api.env.context == 'installer':
-                        try:
-                            profile_api.disable_profile(profile_id)
-                        except errors.RemoteRetrieveError:
-                            pass
-                        profile_api.delete_profile(profile_id)
-                        profile_api.create_profile(profile_data)
-
-                # enable the profile
-                try:
-                    profile_api.enable_profile(profile_id)
-                except errors.RemoteRetrieveError:
-                    pass
-
-            api.Backend.ra_certprofile.override_port = None
+            profile_data = ipautil.template_file(
+                '/usr/share/ipa/profiles/{}.cfg'.format(profile_id), sub_dict)
+            _create_dogtag_profile(profile_id, profile_data)
             root_logger.info("Imported profile '%s'", profile_id)
 
+    api.Backend.ra_certprofile.override_port = None
     conn.disconnect()
 
+
+def migrate_profiles_to_ldap():
+    """Migrate profiles from filesystem to LDAP.
+
+    This must be run *after* switching to the LDAPProfileSubsystem
+    and restarting the CA.
+
+    The profile might already exist, e.g. if a replica was already
+    upgraded, so this case is ignored.
+
+    """
+    ensure_ldap_profiles_container()
+
+    api.Backend.ra_certprofile._read_password()
+    api.Backend.ra_certprofile.override_port = 8443
+
+    with open(dogtag.configured_constants().CS_CFG_PATH) as f:
+        cs_cfg = f.read()
+    match = re.search(r'^profile\.list=(\S*)', cs_cfg, re.MULTILINE)
+    profile_ids = match.group(1).split(',')
+
+    for profile_id in profile_ids:
+        match = re.search(
+            r'^profile\.{}\.config=(\S*)'.format(profile_id),
+            cs_cfg, re.MULTILINE
+        )
+        if match is None:
+            root_logger.info("No file for profile '%s'; skipping", profile_id)
+            continue
+        filename = match.group(1)
+
+        match = re.search(
+            r'^profile\.{}\.class_id=(\S*)'.format(profile_id),
+            cs_cfg, re.MULTILINE
+        )
+        if match is None:
+            root_logger.info("No class_id for profile '%s'; skipping", profile_id)
+            continue
+        class_id = match.group(1)
+
+        root_logger.info("Migrating profile '%s' to LDAP", profile_id)
+        with open(filename) as f:
+            profile_data = f.read()
+            if profile_data[-1] != '\n':
+                profile_data += '\n'
+            profile_data += 'profileId={}\n'.format(profile_id)
+            profile_data += 'classId={}\n'.format(class_id)
+            _create_dogtag_profile(profile_id, profile_data)
+
+    api.Backend.ra_certprofile.override_port = None
+
+
+def _create_dogtag_profile(profile_id, profile_data):
+    with api.Backend.ra_certprofile as profile_api:
+        # import the profile
+        try:
+            profile_api.create_profile(profile_data)
+        except errors.RemoteRetrieveError:
+            # conflicting profile; replace it if we are
+            # installing IPA, but keep it for upgrades
+            if api.env.context == 'installer':
+                try:
+                    profile_api.disable_profile(profile_id)
+                except errors.RemoteRetrieveError:
+                    root_logger.debug(
+                        "Failed to disable profile '%s' "
+                        "(it is probably already disabled)")
+                profile_api.delete_profile(profile_id)
+                profile_api.create_profile(profile_data)
+
+        # enable the profile
+        try:
+            profile_api.enable_profile(profile_id)
+        except errors.RemoteRetrieveError:
+            root_logger.debug(
+                "Failed to enable profile '%s' "
+                "(it is probably already enabled)")
+
+
 if __name__ == "__main__":
     standard_logging_setup("install.log")
     ds = dsinstance.DsInstance()
diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
index 0d24e03f96ebc465df90dede1ff44cd609ea7592..248f0a4260ae26908fc36bf552613af979bf47ff 100644
--- a/ipaserver/install/server/upgrade.py
+++ b/ipaserver/install/server/upgrade.py
@@ -332,8 +332,8 @@ def ca_enable_ldap_profile_subsystem(ca):
             quotes=False,
             separator='=')
 
-    # TODO import file-based profiles into Dogtag
-    # More code needed on Dogtag side for this.
+        ca.restart(dogtag.configured_constants().PKI_INSTANCE_NAME)
+        cainstance.migrate_profiles_to_ldap()
 
     return needs_update
 
@@ -1478,7 +1478,6 @@ def upgrade_configuration():
         certificate_renewal_update(ca),
         ca_enable_pkix(ca),
         ca_configure_profiles_acl(ca),
-        ca_enable_ldap_profile_subsystem(ca),
     ])
 
     if ca_restart:
@@ -1488,6 +1487,8 @@ def upgrade_configuration():
         except ipautil.CalledProcessError as e:
             root_logger.error("Failed to restart %s: %s", ca.service_name, e)
 
+    ca_enable_ldap_profile_subsystem(ca)
+
     # This step MUST be done after ca_enable_ldap_profile_subsystem and
     # ca_configure_profiles_acl, and the consequent restart, but does not
     # itself require a restart.
-- 
2.1.0



More information about the Freeipa-devel mailing list